stim 1.20.2 → 1.21.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 +88 -8
- package/dist/acquire-artifact-CD4lbiWE.mjs +153 -0
- package/dist/act-DHAw2A2S.mjs +2667 -0
- package/dist/activity-BzVfHSrY.mjs +1376 -0
- package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-zh1vhbLp.mjs} +21 -65
- package/dist/{android-HqP1_vB_.mjs → android-BEJ8Jpl7.mjs} +2 -2
- package/dist/{android-DCKZrNvV.mjs → android-BLgbNqox.mjs} +128 -78
- package/dist/{android-Dlzxshgp.mjs → android-CV_GCELZ.mjs} +5 -5
- package/dist/{android-Mz_Inn3w.mjs → android-DUYkNF4u.mjs} +184 -102
- package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-Ct5b1xCK.mjs} +7 -6
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/android-project-BCAAmMwz.mjs +12 -0
- package/dist/api.d.mts +740 -8
- package/dist/api.mjs +585 -1
- package/dist/{artifact-HSwkIWEQ.mjs → artifact-B8T3S5gi.mjs} +223 -201
- package/dist/{artifact-D3czlUvT.mjs → artifact-DAuZ-FNU.mjs} +158 -148
- package/dist/{browser-web-CA-F1GQo.mjs → browser-web-QQzVjz3O.mjs} +26 -24
- package/dist/budget-Bs6SxxzO.mjs +9154 -0
- package/dist/{build-DYDbfkk5.mjs → build-CoPzQRNw.mjs} +144 -96
- package/dist/build-cache-DmyR9Zzc.mjs +602 -0
- package/dist/build-plan-CaFskB7_.mjs +188 -0
- package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DkkqguoK.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{ccache-zdKiYQ3E.mjs → ccache-BJRZ9pG3.mjs} +10 -9
- package/dist/{cdp-Dq_ypAlJ.mjs → cdp-CWmIUMbw.mjs} +18 -5
- package/dist/{chrome-BnzZMqsR.mjs → chrome-B6tfCta1.mjs} +7 -4
- package/dist/{cli-CLP3diBm.mjs → cli-0DYf8QhQ.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/client-B7QVOlCr.d.mts +253 -0
- package/dist/client-UXD70ZbM.mjs +1406 -0
- package/dist/collector-run.d.mts +4 -40
- package/dist/collector-run.mjs +9 -8
- package/dist/{command-output-BTy8hZ0F.mjs → command-output-B1UrjZHL.mjs} +1 -1
- package/dist/config-CYcBF478.mjs +949 -0
- package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-CqeBlrEn.mjs} +3 -3
- package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-BbKQW83h.mjs} +20 -5
- package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-DFRyG1_o.mjs} +1 -1
- package/dist/{dev-client-DAWVIGBu.mjs → dev-client-UOeESKm6.mjs} +2 -2
- package/dist/device-DCxH7_By.mjs +1068 -0
- package/dist/{device-BECOiufl.mjs → device-ExJq8Ei7.mjs} +35 -35
- package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-CMlqEcvw.mjs} +43 -13
- package/dist/device-host-worker.mjs +65 -61
- package/dist/{device-ios-COSi6oS1.mjs → device-ios-DRUeKaFV.mjs} +48 -45
- package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-C8raGFoP.mjs} +14 -26
- package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-DMRpVX9a.mjs} +5 -5
- package/dist/doctor-BLHCYxzi.mjs +2 -0
- package/dist/{doctor-kfMBnUw6.mjs → doctor-DTvaDOda.mjs} +281 -317
- package/dist/{doctor-CB8oZKCk.mjs → doctor-Dhqebm0q.mjs} +183 -91
- package/dist/doctor-fingerprint.mjs +19 -0
- package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-Cv1F10Kj.mjs} +40 -21
- package/dist/{eas-build-JyfqyHfC.mjs → eas-build-BomfRnFT.mjs} +53 -20
- package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-DJwZpy0c.mjs} +26 -208
- package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-op6A54yi.mjs} +229 -11
- package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-Bf0rZvG9.mjs} +172 -82
- package/dist/exec-H20xSg2T.d.mts +65 -0
- package/dist/exec-_UbtCQcG.mjs +750 -0
- package/dist/gc-C-WwL0yi.mjs +3 -0
- package/dist/{gc-qWOMdnER.mjs → gc-_-dCXdyL.mjs} +584 -796
- package/dist/git-C3iTsJaZ.mjs +73 -0
- package/dist/{guide-G9cAbVAc.mjs → guide-Yqwt2bd6.mjs} +941 -269
- package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-Bw-honsd.mjs} +8 -6
- package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DB_gBPfY.mjs} +34 -19
- package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CUvOf4Vr.mjs} +1 -1
- package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-DL_P5AdN.mjs} +77 -43
- package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-QI141yKk.mjs} +21 -17
- package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-Ksyjgzq-.mjs} +30 -21
- package/dist/idle-BVeRGroT.d.mts +24 -0
- package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DaKmZi0z.mjs} +11 -10
- package/dist/{ios-BwVCF7oA.mjs → ios-CQ68hG9s.mjs} +8 -8
- package/dist/{ios-RkW4pnQf.mjs → ios-CpByZy12.mjs} +140 -80
- package/dist/{ios-device-B5veSDDQ.mjs → ios-device-CXGP1bsD.mjs} +1 -1
- package/dist/{ios-device-D7pi2Sca.mjs → ios-device-CwFMehUS.mjs} +51 -26
- package/dist/{ios-project-K9hY_Jab.mjs → ios-project-WuwwBdvW.mjs} +13 -13
- package/dist/{ios-nOLJGVdy.mjs → ios-qNJt4dFm.mjs} +1 -1
- package/dist/ios-signing-DTTIChGs.mjs +489 -0
- package/dist/{ios-state-CBLe1xYw.mjs → ios-state-DvFX-K_l.mjs} +1 -1
- package/dist/{ios-Ce7bc7br.mjs → ios-ubFsBzwq.mjs} +129 -86
- package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Cc1dttps.mjs} +53 -26
- package/dist/{launch-F4sOqAhB.mjs → launch-CD1yVc7U.mjs} +91 -90
- package/dist/{launch-C3qJ6Agb.mjs → launch-Zq2mOSDy.mjs} +82 -541
- package/dist/logs-BS00Anxf.mjs +352 -0
- package/dist/logs-CMm05HxN.mjs +255 -0
- package/dist/{macos-D7uDvO-z.mjs → macos-B65--pPd.mjs} +1 -1
- package/dist/{macos-Ch5VJmcS.mjs → macos-C-0qJ6zq.mjs} +225 -212
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +122 -247
- package/dist/{metro-DnCEjCxs.mjs → metro-DEXpIhHC.mjs} +67 -12
- package/dist/{metro-gateway-CX9Xlkq2.mjs → metro-gateway-BMJNlj3E.mjs} +20 -12
- package/dist/{named-ports-4WopRPg-.mjs → named-ports-BWTzt6mu.mjs} +8 -63
- package/dist/native-android-JACyjTZs.mjs +844 -0
- package/dist/{native-gradle-inputs-BsLRrl7u.mjs → native-gradle-inputs-Bep9JcSF.mjs} +128 -140
- package/dist/native-inputs-TRTTTRxt.mjs +91 -0
- package/dist/native-run-DY_RLx3C.mjs +277 -0
- package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-Dg1Q7tfF.mjs} +9 -8
- package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-CB2iQeWq.mjs} +27 -18
- package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-CXX39F7o.mjs} +96 -47
- package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
- package/dist/offload-worker.d.mts +1 -46
- package/dist/offload-worker.mjs +197 -66
- package/dist/{ownership-DCtw_2IA.mjs → ownership-DEmM5vhh.mjs} +3 -3
- package/dist/{page-DRHy329N.mjs → page-CPaHeYqj.mjs} +7 -4
- package/dist/paths-BsJMoPP2.mjs +12 -0
- package/dist/paths-DQtTgsBf.mjs +42 -0
- package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BqGbTa61.mjs} +5 -5
- package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-Bwj-IjY1.mjs} +6 -6
- package/dist/{ports-DdSUicVo.mjs → ports-D-MmCTdv.mjs} +3 -3
- package/dist/prebuild-uD_ipCxF.mjs +449 -0
- package/dist/{project-_phNIJfs.mjs → project-BZNjmW_8.mjs} +65 -37
- package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-Lfetn8Kr.mjs} +2 -2
- package/dist/pull-request-zjCSAryH.d.mts +120 -0
- package/dist/pull-requests.d.mts +1 -119
- package/dist/pull-requests.mjs +1 -1
- package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-DuzH0cn3.mjs} +74 -48
- package/dist/{gradle-DSrXb6lG.mjs → react-native-build-rhk4smwQ.mjs} +292 -15
- package/dist/react-native-doctor-CQpuIMso.mjs +234 -0
- package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-Bhq1rJeV.mjs} +46 -28
- package/dist/{recordings-D0d5aQt0.mjs → recordings-DYteQSu4.mjs} +12 -9
- package/dist/{reload-C8JhxjSh.mjs → reload-CmTRFJaX.mjs} +93 -47
- package/dist/reload-DzjSl5P_.mjs +2 -0
- package/dist/{remote-BiR6aYjy.mjs → remote-ByYkXdGD.mjs} +15 -10
- package/dist/result-DNiS-tTP.mjs +434 -0
- package/dist/{run-BtPgpKks.mjs → run-D23HmJMs.mjs} +4 -5
- package/dist/selection-CSl9i5qU.mjs +619 -0
- package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CxTrvDg8.mjs} +3 -4
- package/dist/{server-command-CTtCkmcQ.mjs → server-command-CtzloH3v.mjs} +14 -7
- package/dist/server-expo-C-90EhcG.mjs +2 -0
- package/dist/{server-expo-DsguMGUF.mjs → server-expo-DT_F_uVI.mjs} +50 -9
- package/dist/{settings-B717odTD.mjs → settings-CsJDEXgK.mjs} +234 -24
- package/dist/{settings-vk3mJGSm.d.mts → settings-DkdmlelE.d.mts} +6 -4
- package/dist/settings-T1gtc3bf.mjs +114 -0
- package/dist/settings-write-HyVZ8eQ8.mjs +359 -0
- package/dist/settings.schema.json +163 -16
- package/dist/{simslim-CCr3rE-A.mjs → simslim-Cgk17SXV.mjs} +14 -12
- package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-DF8VfT64.mjs} +15 -20
- package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
- package/dist/stage-BIS0ydsV.mjs +183 -0
- package/dist/{start-BWqzODpb.mjs → start-7lpH7hmN.mjs} +63 -44
- package/dist/{start-TXeMmmO2.mjs → start-RChynRDp.mjs} +1 -1
- package/dist/{state-D1Icyjlu.mjs → state-C4ZtUisW.mjs} +40 -13
- package/dist/{state-CG_OFoaA.mjs → state-XMziexv2.mjs} +3 -2
- package/dist/{stats-BoY5sEPU.mjs → stats-53T7OTb9.mjs} +7 -13
- package/dist/stats-report-BFfMpWWF.mjs +16 -0
- package/dist/{status-WgFbkRzj.mjs → status-BL7jVyAB.mjs} +535 -447
- package/dist/status-CSi6tlRq.mjs +2 -0
- package/dist/{status-BTA7kKiQ.mjs → status-DqEUSSxs.mjs} +6 -4
- package/dist/{status-watch-C23ILtf9.mjs → status-watch-GDCfqpTE.mjs} +187 -22
- package/dist/status-worker.d.mts +1 -0
- package/dist/status-worker.mjs +19 -0
- package/dist/stim-desktop-C12we7lz.mjs +112 -0
- package/dist/{stop-DR6VoDIk.mjs → stop-Bk_1qiV6.mjs} +2 -2
- package/dist/{stop-BNmBMi1F.mjs → stop-CPzlM1L-.mjs} +138 -98
- package/dist/{stop-DPEhunlw.mjs → stop-D7h6jAXQ.mjs} +11 -10
- package/dist/supervisor-run.d.mts +8 -17
- package/dist/supervisor-run.mjs +63 -27
- package/dist/{support-DMTqj3Hm.mjs → support-67vraa1Q.mjs} +18 -11
- package/dist/{support-CwjbFs9H.mjs → support-Dlu37g6H.mjs} +12 -12
- package/dist/{swiftpm-macos-DRNVJWlb.mjs → swiftpm-macos-p8WZbxKU.mjs} +35 -24
- package/dist/toolchain-DhKwp9iI.mjs +2 -0
- package/dist/toolchain-Hp9sCpK4.mjs +873 -0
- package/dist/{trigger-CigAYjeL.mjs → trigger-BAahxUPq.mjs} +20 -5
- package/dist/trigger-Bf3uDcpv.mjs +2 -0
- package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-BHX5r0Ei.mjs} +250 -156
- package/dist/{web-BDBMxDpx.mjs → web-CJmIj6AI.mjs} +18 -13
- package/dist/web-DknQETPs.mjs +2 -0
- package/dist/web-run.mjs +11 -12
- package/dist/windows-report.d.mts +1 -0
- package/dist/windows-report.mjs +18 -0
- package/dist/windows-report.ps1 +43 -0
- package/dist/workspace-process-lock-1_1OoVW5.mjs +57 -0
- package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-Cjuigeeu.mjs} +62 -58
- package/dist/{workspaces-C36s2jb9.mjs → workspaces-BccMFmGQ.mjs} +1188 -1079
- package/dist/worktree-CK2MpJW5.mjs +2 -0
- package/dist/{worktree-CgvJYJ-Q.mjs → worktree-DQ6Zi2Mv.mjs} +304 -53
- package/dist/xcode-Zlx3qjEs.mjs +896 -0
- package/package.json +7 -5
- package/shim/android-optimizations.gradle +7 -5
- package/dist/activity-BSV745Kz.mjs +0 -629
- package/dist/api-qvOzWyfO.mjs +0 -154
- package/dist/api-run.mjs +0 -294
- package/dist/app-install-BIKtMfPq.mjs +0 -896
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
- package/dist/budget-f7516Zk0.mjs +0 -4106
- package/dist/build-facts-DcLv2HSd.d.mts +0 -111
- package/dist/cancellation-C_22VQTH.mjs +0 -24
- package/dist/client-qQAaXSUs.mjs +0 -1771
- package/dist/config-BYDxlMY3.mjs +0 -562
- package/dist/device-DuiPJQSn.mjs +0 -290
- package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
- package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
- package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
- package/dist/exec-DqKo9GKJ.mjs +0 -268
- package/dist/git-DDfFzkMm.mjs +0 -45
- package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
- package/dist/logs-BGrEUaEs.mjs +0 -383
- package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
- package/dist/native-android-D5qc3-_v.mjs +0 -226
- package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
- package/dist/plan-C4TjdPsR.mjs +0 -260
- package/dist/prebuild-DYbucPXy.mjs +0 -212
- package/dist/preview-78a9kR_-.mjs +0 -1011
- package/dist/react-native-build-CtCccJtb.mjs +0 -239
- package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
- package/dist/remote-cache-OyOyVIS3.mjs +0 -526
- package/dist/result-CaJg5Iat.mjs +0 -186
- package/dist/server-expo-Bigriskl.mjs +0 -2
- package/dist/settings-BORNaaCO.mjs +0 -402
- package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
- package/dist/stage-KNTQopqv.mjs +0 -157
- package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
- package/dist/tailnet-Dh-qiYzG.mjs +0 -265
- package/dist/toolchain-BFkAcstd.mjs +0 -2
- package/dist/toolchain-DxSsNssu.mjs +0 -1657
- package/dist/trigger-9_USgmxz.mjs +0 -2
- package/dist/web-Dq-i3wzJ.mjs +0 -2
- package/dist/worktree-DpLdCHga.mjs +0 -2
- package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
- package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-
|
|
2
|
-
import { t as spawnEntry } from "./spawn-entry-Dcb7sDUz.mjs";
|
|
3
|
-
import { n as windowsLauncherArgs } from "./detached-entry-B9C_zeQC.mjs";
|
|
1
|
+
import { t as getExecutor } from "./exec-_UbtCQcG.mjs";
|
|
4
2
|
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
3
|
+
import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
|
|
4
|
+
import { n as windowsLauncherArgs } from "./detached-entry-DFRyG1_o.mjs";
|
|
5
5
|
import { n as stampAttempt, r as due, t as capChildLog } from "./attempt-DW-mQqM7.mjs";
|
|
6
6
|
import { closeSync, openSync } from "node:fs";
|
|
7
7
|
import { maintenanceChildLogFile, maintenanceRunClaims, readMaintenanceAttempt, readMaintenanceState } from "@stim-cli/core/state";
|
|
8
8
|
import { readClaimSet } from "@stim-cli/core/ownership-claim";
|
|
9
9
|
//#region src/maintenance/trigger.ts
|
|
10
|
-
|
|
10
|
+
const WARNING_FRESH_MS = 6e5;
|
|
11
|
+
function warnCriticalDisk() {
|
|
12
|
+
const state = readMaintenanceState();
|
|
13
|
+
const pressure = state?.pressure;
|
|
14
|
+
const measured = state?.lastAt.pressure;
|
|
15
|
+
if (pressure?.diskLevel !== 3 || measured === void 0 || Date.now() - measured > WARNING_FRESH_MS) return;
|
|
16
|
+
const disk = pressure.disk.map((volume) => `${(volume.freeMb / 1024).toFixed(1)} GB free on ${volume.volume}`);
|
|
17
|
+
const acting = resolveMaintenanceSettings().mode === "on" ? "Automatic maintenance is stopping idle workspaces and deleting regenerable build outputs" : "Automatic maintenance is not in on mode, so it deletes nothing";
|
|
18
|
+
console.error(`Stim: disk pressure level 3 (${disk.join(", ")}). ${acting}; run \`stim status\` to see its plan, and free space outside Stim.`);
|
|
19
|
+
}
|
|
20
|
+
function triggerMaintenance(trigger, { argv = process.argv.slice(2), platform = process.platform, warn = true } = {}) {
|
|
11
21
|
try {
|
|
12
22
|
const env = process.env;
|
|
13
23
|
if ([
|
|
@@ -20,12 +30,17 @@ function triggerMaintenance(trigger, { argv = process.argv.slice(2), platform =
|
|
|
20
30
|
"--version",
|
|
21
31
|
"-V"
|
|
22
32
|
].includes(arg))) return;
|
|
33
|
+
if (warn) warnCriticalDisk();
|
|
34
|
+
if (argv[0] === "gc") return;
|
|
23
35
|
if (env.STIM_MAINTENANCE_CHILD === "1" || (env.STIM_HOME || env.CI) && env.STIM_MAINTENANCE === void 0) return;
|
|
24
36
|
const settings = resolveMaintenanceSettings();
|
|
25
37
|
if (settings.mode === "off" || due(readMaintenanceState(), settings, Date.now(), readMaintenanceAttempt()).length === 0) return;
|
|
26
38
|
const claims = readClaimSet(maintenanceRunClaims());
|
|
27
39
|
if (claims.live.length || claims.unresolved.length) return;
|
|
28
|
-
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
try {
|
|
42
|
+
stampAttempt(now);
|
|
43
|
+
} catch {}
|
|
29
44
|
capChildLog();
|
|
30
45
|
const logFile = maintenanceChildLogFile();
|
|
31
46
|
const fd = openSync(logFile, "a");
|
|
@@ -1,76 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { o as pullRequestLookups } from "./pull-request-
|
|
1
|
+
import { _ as debugLog, f as ownership_claim_exports, n as isTimeoutError, t as getExecutor } from "./exec-_UbtCQcG.mjs";
|
|
2
|
+
import { d as workspaceDir, n as ensureWorkspaceStorage, v as withDirLock } from "./paths-DQtTgsBf.mjs";
|
|
3
|
+
import { f as agentKey, m as discoverAgentSessions, o as updateWorkspaceState, p as attributeAgentSessions } from "./workspace-state-Cjuigeeu.mjs";
|
|
4
|
+
import { Dt as linkedWorktreesOnDisk, bt as gitCommonDirOnDisk } from "./settings-CsJDEXgK.mjs";
|
|
5
|
+
import { i as gitQuietAsync, n as gitAsync, t as git$1 } from "./git-C3iTsJaZ.mjs";
|
|
6
|
+
import { z as ownedAvdDirectory } from "./android-DUYkNF4u.mjs";
|
|
7
|
+
import { o as pullRequestLookups } from "./pull-request-Lfetn8Kr.mjs";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
8
9
|
import { existsSync, mkdirSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
9
11
|
import { basename, dirname, join, sep } from "node:path";
|
|
10
12
|
import { ENDED_AGENT_RETENTION_MS, READY_PHASE_MS, WARM_KEY, agentSessionsCacheFile, diskUsageCacheFile, diskUsageFailureFile, diskUsageWalkClaims, pullRequestCacheFile, readAgentSessionsCache, readDiskUsage, readDiskUsageFailure, readEndedAgentSessions, readPullRequestCache, readWarmRecord, readWorkspaceAgent, readWorkspaceState, workspaceEndedAgentsFile, workspaceEndedAgentsLock } from "@stim-cli/core/state";
|
|
11
|
-
import { clearClaimChild, markClaimChildPending, releaseClaim, setClaimChild, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
12
13
|
import { captureProcessIdentity } from "@stim-cli/core/process-identity";
|
|
13
|
-
import {
|
|
14
|
-
import { homedir } from "node:os";
|
|
14
|
+
import { clearClaimChild, markClaimChildPending, releaseClaim, setClaimChild, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
|
|
15
15
|
//#region src/workspace/merge-state.ts
|
|
16
16
|
const FETCH_TIMEOUT_MS = 3e4;
|
|
17
|
+
/** How old a fetch or a cached lookup can be and still count as fresh. */
|
|
17
18
|
const FETCH_FRESH_MS = 6e5;
|
|
18
19
|
const GIT_TIMEOUT_MS$1 = 6e4;
|
|
19
20
|
const REMOTE_PREFIX = "refs/remotes/origin/";
|
|
20
21
|
const MAX_MERGE_STATE_COMMITS = 2e3;
|
|
21
22
|
function failure(error) {
|
|
22
|
-
const { stderr, message } = error;
|
|
23
|
-
const text = String(stderr ?? "").trim() || String(message ?? error);
|
|
23
|
+
const { code, stderr, message } = error;
|
|
24
|
+
const text = (code === "ENOBUFS" ? "" : String(stderr ?? "").trim()) || String(message ?? error);
|
|
24
25
|
return text.split("\n")[0] ?? text;
|
|
25
26
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
"rev-parse",
|
|
29
|
-
"--path-format=absolute",
|
|
30
|
-
"--git-path",
|
|
31
|
-
"FETCH_HEAD"
|
|
32
|
-
])?.trim();
|
|
27
|
+
function fetchTime(path) {
|
|
28
|
+
path = path?.trim() ?? null;
|
|
33
29
|
try {
|
|
34
|
-
return
|
|
30
|
+
return path ? statSync(path).mtimeMs : null;
|
|
35
31
|
} catch {
|
|
36
|
-
return
|
|
32
|
+
return null;
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* prompting for credentials. It skips the fetch when the checkout fetched anything in the last 10 minutes.
|
|
42
|
-
*/
|
|
43
|
-
function fetchDefaultBranch(repo, now = Date.now()) {
|
|
44
|
-
const ref = gitQuiet(repo, [
|
|
45
|
-
"symbolic-ref",
|
|
46
|
-
"--quiet",
|
|
47
|
-
"refs/remotes/origin/HEAD"
|
|
48
|
-
])?.trim();
|
|
35
|
+
function defaultBranch(repo, ref) {
|
|
36
|
+
ref = ref?.trim() ?? null;
|
|
49
37
|
if (!ref?.startsWith(REMOTE_PREFIX)) return { error: `origin/HEAD is not set; run \`git -C ${repo} remote set-head origin --auto\`` };
|
|
50
|
-
const branch = ref.slice(20);
|
|
51
|
-
if (fetchedRecently(repo, now)) return {
|
|
52
|
-
ref,
|
|
53
|
-
name: `origin/${branch}`
|
|
54
|
-
};
|
|
55
|
-
try {
|
|
56
|
-
git(repo, [
|
|
57
|
-
"fetch",
|
|
58
|
-
"--quiet",
|
|
59
|
-
"--no-tags",
|
|
60
|
-
"--no-recurse-submodules",
|
|
61
|
-
"origin",
|
|
62
|
-
`+refs/heads/${branch}:${ref}`
|
|
63
|
-
], {
|
|
64
|
-
write: true,
|
|
65
|
-
timeoutMs: FETCH_TIMEOUT_MS,
|
|
66
|
-
env: { GIT_TERMINAL_PROMPT: "0" }
|
|
67
|
-
});
|
|
68
|
-
} catch (error) {
|
|
69
|
-
return { error: `git fetch origin ${branch} failed: ${failure(error)}` };
|
|
70
|
-
}
|
|
71
38
|
return {
|
|
72
39
|
ref,
|
|
73
|
-
name: `origin/${
|
|
40
|
+
name: `origin/${ref.slice(20)}`
|
|
74
41
|
};
|
|
75
42
|
}
|
|
76
43
|
function notMerged(detail) {
|
|
@@ -80,129 +47,133 @@ function notMerged(detail) {
|
|
|
80
47
|
detail
|
|
81
48
|
};
|
|
82
49
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
50
|
+
function* git(args, input) {
|
|
51
|
+
return yield {
|
|
52
|
+
args: ["--literal-pathspecs", ...args],
|
|
53
|
+
options: { input }
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function* patch(args, input) {
|
|
57
|
+
return yield {
|
|
58
|
+
args: ["--literal-pathspecs", ...args],
|
|
59
|
+
options: {
|
|
60
|
+
input,
|
|
61
|
+
untrimmed: true
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function* probe(args) {
|
|
66
|
+
try {
|
|
67
|
+
return yield { args };
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (isTimeoutError(error) || typeof error === "object" && error !== null && "code" in error && error.code === "ENOBUFS") throw error;
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function* patchIdCommits(text) {
|
|
74
|
+
const output = text ? yield* git(["patch-id", "--verbatim"], text) : "";
|
|
75
|
+
return new Map(output.split("\n").flatMap((line) => {
|
|
76
|
+
const [id, commit] = line.split(" ");
|
|
77
|
+
return id && commit ? [[id, commit]] : [];
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
function* patchIds(text) {
|
|
81
|
+
return [...(yield* patchIdCommits(text)).keys()];
|
|
82
|
+
}
|
|
83
|
+
function* committedAt(commits) {
|
|
84
|
+
const times = commits.length ? (yield* git([
|
|
85
|
+
"log",
|
|
86
|
+
"--no-walk",
|
|
87
|
+
"--stdin",
|
|
88
|
+
"--format=%ct"
|
|
89
|
+
], commits.join("\n"))).split("\n").map(Number) : [];
|
|
90
|
+
if (!times.length || !times.every(Number.isFinite)) throw new Error(`no committer date for ${commits.join(" ")}`);
|
|
91
|
+
return Math.max(...times) * 1e3;
|
|
92
|
+
}
|
|
93
|
+
function* currentBranch() {
|
|
94
|
+
const ref = (yield* probe([
|
|
85
95
|
"symbolic-ref",
|
|
86
96
|
"--quiet",
|
|
87
97
|
"HEAD"
|
|
88
|
-
])?.trim();
|
|
98
|
+
]))?.trim();
|
|
89
99
|
return ref?.startsWith("refs/heads/") ? ref : null;
|
|
90
100
|
}
|
|
91
|
-
function upstreamGone(
|
|
101
|
+
function* upstreamGone(branch) {
|
|
92
102
|
if (!branch) return false;
|
|
93
|
-
const [upstream, state] = (probe([
|
|
103
|
+
const [upstream, state] = ((yield* probe([
|
|
94
104
|
"for-each-ref",
|
|
95
105
|
"--format=%(upstream)%00%(upstream:track)",
|
|
96
106
|
branch
|
|
97
|
-
]) ?? "").trim().split("\0");
|
|
107
|
+
])) ?? "").trim().split("\0");
|
|
98
108
|
return Boolean(upstream) && state === "[gone]";
|
|
99
109
|
}
|
|
100
|
-
function committedOn(
|
|
110
|
+
function* committedOn(branch, head) {
|
|
101
111
|
if (!branch) return false;
|
|
102
|
-
|
|
112
|
+
const entries = (yield* probe([
|
|
103
113
|
"reflog",
|
|
104
114
|
"show",
|
|
105
115
|
"--format=%H %gs",
|
|
106
116
|
branch
|
|
107
|
-
]) ?? ""
|
|
117
|
+
])) ?? "";
|
|
118
|
+
for (const entry of entries.split("\n")) {
|
|
108
119
|
const [sha = "", ...subject] = entry.split(" ");
|
|
109
|
-
|
|
120
|
+
if (/^(commit|cherry-pick|rebase|revert)\b/.test(subject.join(" ")) && (yield* probe([
|
|
110
121
|
"merge-base",
|
|
111
122
|
"--is-ancestor",
|
|
112
123
|
sha,
|
|
113
124
|
head
|
|
114
|
-
]) !== null;
|
|
115
|
-
}
|
|
125
|
+
])) !== null) return true;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
116
128
|
}
|
|
117
|
-
|
|
118
|
-
* Whether the worktree's HEAD is merged into `target`, and when: `mergedAt` is the committer date, in epoch
|
|
119
|
-
* milliseconds, of the commit on `target` that brought the work in, the latest one for a rebase merge.
|
|
120
|
-
* The signals, all local git:
|
|
121
|
-
* - HEAD is an ancestor of the default branch, off its first-parent line, and the branch's reflog shows a commit made
|
|
122
|
-
* on it that HEAD contains, so a merge commit brought the branch's own work in. A branch with no commit of its own
|
|
123
|
-
* is not merged.
|
|
124
|
-
* - The branch changes the tree, has no merge commits, and every commit since the merge base has the same
|
|
125
|
-
* `git patch-id --verbatim` as a commit on the default branch (a rebase merge).
|
|
126
|
-
* - The branch changes the tree and its whole diff since the merge base has the same verbatim patch id as a commit on
|
|
127
|
-
* the default branch, limited to the files the branch changes (a squash merge).
|
|
128
|
-
* Anything git cannot answer is unknown, never merged. `coversUnpushed` is true for a patch-equivalent HEAD whose
|
|
129
|
-
* upstream branch was deleted: its commits exist only locally, but their change is on the default branch.
|
|
130
|
-
*/
|
|
131
|
-
function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS$1, maxCommits = MAX_MERGE_STATE_COMMITS } = {}) {
|
|
132
|
-
const git$1 = (args, input) => git(path, ["--literal-pathspecs", ...args], {
|
|
133
|
-
timeoutMs,
|
|
134
|
-
input
|
|
135
|
-
});
|
|
136
|
-
const patch = (args, input) => git(path, ["--literal-pathspecs", ...args], {
|
|
137
|
-
timeoutMs,
|
|
138
|
-
input,
|
|
139
|
-
untrimmed: true
|
|
140
|
-
});
|
|
141
|
-
const probe = (args) => {
|
|
142
|
-
try {
|
|
143
|
-
return git(path, args, { timeoutMs });
|
|
144
|
-
} catch (error) {
|
|
145
|
-
if (isTimeoutError(error)) throw error;
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
const patchIdCommits = (text) => new Map(text ? git$1(["patch-id", "--verbatim"], text).split("\n").flatMap((line) => {
|
|
150
|
-
const [id, commit] = line.split(" ");
|
|
151
|
-
return id && commit ? [[id, commit]] : [];
|
|
152
|
-
}) : []);
|
|
153
|
-
const patchIds = (text) => [...patchIdCommits(text).keys()];
|
|
154
|
-
const committedAt = (commits) => {
|
|
155
|
-
const times = commits.length ? git$1([
|
|
156
|
-
"log",
|
|
157
|
-
"--no-walk",
|
|
158
|
-
"--stdin",
|
|
159
|
-
"--format=%ct"
|
|
160
|
-
], commits.join("\n")).split("\n").map(Number) : [];
|
|
161
|
-
if (!times.length || !times.every(Number.isFinite)) throw new Error(`no committer date for ${commits.join(" ")}`);
|
|
162
|
-
return Math.max(...times) * 1e3;
|
|
163
|
-
};
|
|
129
|
+
function* mergeStateReads({ ref, name }, maxCommits) {
|
|
164
130
|
const diffOptions = ["--no-color", "--no-ext-diff"];
|
|
165
|
-
const noOwnCommits =
|
|
131
|
+
const noOwnCommits = {
|
|
132
|
+
merged: false,
|
|
133
|
+
unknown: false,
|
|
134
|
+
detail: `no commits of its own beyond ${name}`,
|
|
135
|
+
noOwnCommits: true
|
|
136
|
+
};
|
|
166
137
|
try {
|
|
167
|
-
const head = git
|
|
138
|
+
const head = yield* git([
|
|
168
139
|
"rev-parse",
|
|
169
140
|
"--verify",
|
|
170
141
|
"HEAD^{commit}"
|
|
171
142
|
]);
|
|
172
|
-
const base = git
|
|
143
|
+
const base = yield* git([
|
|
173
144
|
"merge-base",
|
|
174
145
|
head,
|
|
175
146
|
ref
|
|
176
147
|
]);
|
|
177
|
-
const branch = currentBranch(
|
|
148
|
+
const branch = yield* currentBranch();
|
|
178
149
|
if (base === head) {
|
|
179
|
-
if (git
|
|
150
|
+
if ((yield* git(["rev-parse", ref])) === head || (yield* git([
|
|
180
151
|
"rev-list",
|
|
181
152
|
"--first-parent",
|
|
182
153
|
"--parents",
|
|
183
154
|
`${head}..${ref}`
|
|
184
|
-
]).split("\n").some((line) => line.split(" ")[1] === head) || !committedOn(
|
|
185
|
-
const descendants = new Set(git
|
|
155
|
+
])).split("\n").some((line) => line.split(" ")[1] === head) || !(yield* committedOn(branch, head))) return noOwnCommits;
|
|
156
|
+
const descendants = new Set((yield* git([
|
|
186
157
|
"rev-list",
|
|
187
158
|
"--ancestry-path",
|
|
188
159
|
`${head}..${ref}`
|
|
189
|
-
]).split("\n"));
|
|
190
|
-
const landed = git
|
|
160
|
+
])).split("\n"));
|
|
161
|
+
const landed = (yield* git([
|
|
191
162
|
"rev-list",
|
|
192
163
|
"--first-parent",
|
|
193
164
|
"--reverse",
|
|
194
165
|
`${head}..${ref}`
|
|
195
|
-
]).split("\n").find((commit) => descendants.has(commit));
|
|
166
|
+
])).split("\n").find((commit) => descendants.has(commit));
|
|
196
167
|
if (!landed) throw new Error(`no commit on ${name} merges ${head}`);
|
|
197
168
|
return {
|
|
198
169
|
merged: true,
|
|
199
170
|
into: name,
|
|
200
171
|
head,
|
|
201
172
|
coversUnpushed: false,
|
|
202
|
-
mergedAt: committedAt([landed])
|
|
173
|
+
mergedAt: yield* committedAt([landed])
|
|
203
174
|
};
|
|
204
175
|
}
|
|
205
|
-
const aheadCount = Number(git
|
|
176
|
+
const aheadCount = Number(yield* git([
|
|
206
177
|
"rev-list",
|
|
207
178
|
"--count",
|
|
208
179
|
`${base}..${head}`
|
|
@@ -212,45 +183,49 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS$1, maxComm
|
|
|
212
183
|
unknown: true,
|
|
213
184
|
detail: `merge state unknown: ${aheadCount} commits of its own ahead of the merge base with ${name} exceeds the ${maxCommits}-commit limit`
|
|
214
185
|
};
|
|
215
|
-
const files = git
|
|
186
|
+
const files = (yield* git([
|
|
216
187
|
"diff",
|
|
217
188
|
"--name-only",
|
|
218
189
|
"--no-renames",
|
|
219
190
|
"-z",
|
|
220
191
|
base,
|
|
221
192
|
head
|
|
222
|
-
]).split("\0").filter(Boolean);
|
|
193
|
+
])).split("\0").filter(Boolean);
|
|
223
194
|
if (!files.length) return notMerged(`no net change beyond ${name}`);
|
|
224
|
-
const log = (range, pathspec = [])
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
195
|
+
const log = function* (range, pathspec = []) {
|
|
196
|
+
return yield* patch([
|
|
197
|
+
"log",
|
|
198
|
+
"-p",
|
|
199
|
+
"--no-merges",
|
|
200
|
+
...diffOptions,
|
|
201
|
+
"--format=commit %H",
|
|
202
|
+
"--stdin"
|
|
203
|
+
], pathspec.length ? `${range}\n--\n${pathspec.join("\n")}\n` : `${range}\n`);
|
|
204
|
+
};
|
|
205
|
+
const upstream = yield* patchIdCommits(yield* log(`${base}..${ref}`, files));
|
|
206
|
+
const patchEquivalent = function* (ids) {
|
|
207
|
+
return {
|
|
208
|
+
merged: true,
|
|
209
|
+
into: name,
|
|
210
|
+
head,
|
|
211
|
+
coversUnpushed: yield* upstreamGone(branch),
|
|
212
|
+
mergedAt: yield* committedAt(ids.map((id) => upstream.get(id)))
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
const squash = yield* patchIds(yield* patch([
|
|
241
216
|
"diff",
|
|
242
217
|
...diffOptions,
|
|
243
218
|
base,
|
|
244
219
|
head
|
|
245
220
|
]));
|
|
246
|
-
if (squash.length === 1 && upstream.has(squash[0])) return patchEquivalent(squash);
|
|
247
|
-
if (!git
|
|
221
|
+
if (squash.length === 1 && upstream.has(squash[0])) return yield* patchEquivalent(squash);
|
|
222
|
+
if (!(yield* git([
|
|
248
223
|
"rev-list",
|
|
249
224
|
"--merges",
|
|
250
225
|
`${base}..${head}`
|
|
251
|
-
])) {
|
|
252
|
-
const own = patchIds(log(`${base}..${head}`));
|
|
253
|
-
if (own.length && own.every((id) => upstream.has(id))) return patchEquivalent(own);
|
|
226
|
+
]))) {
|
|
227
|
+
const own = yield* patchIds(yield* log(`${base}..${head}`));
|
|
228
|
+
if (own.length && own.every((id) => upstream.has(id))) return yield* patchEquivalent(own);
|
|
254
229
|
}
|
|
255
230
|
return notMerged(`not merged into ${name}`);
|
|
256
231
|
} catch (error) {
|
|
@@ -263,6 +238,96 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS$1, maxComm
|
|
|
263
238
|
};
|
|
264
239
|
}
|
|
265
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Whether the worktree's HEAD is merged into `target`, and when: `mergedAt` is the committer date, in epoch
|
|
243
|
+
* milliseconds, of the commit on `target` that brought the work in, the latest one for a rebase merge.
|
|
244
|
+
* The signals, all local git:
|
|
245
|
+
* - HEAD is an ancestor of the default branch, off its first-parent line, and the branch's reflog shows a commit made
|
|
246
|
+
* on it that HEAD contains, so a merge commit brought the branch's own work in. A branch with no commit of its own
|
|
247
|
+
* is not merged.
|
|
248
|
+
* - The branch changes the tree, has no merge commits, and every commit since the merge base has the same
|
|
249
|
+
* `git patch-id --verbatim` as a commit on the default branch (a rebase merge).
|
|
250
|
+
* - The branch changes the tree and its whole diff since the merge base has the same verbatim patch id as a commit on
|
|
251
|
+
* the default branch, limited to the files the branch changes (a squash merge).
|
|
252
|
+
* A HEAD the default branch contains with no commit of its own on the branch is not merged and carries
|
|
253
|
+
* `noOwnCommits`. Anything git cannot answer is unknown, never merged. `coversUnpushed` is true for a patch-equivalent HEAD whose
|
|
254
|
+
* upstream branch was deleted: its commits exist only locally, but their change is on the default branch.
|
|
255
|
+
*/
|
|
256
|
+
function mergeState(path, target, { timeoutMs = GIT_TIMEOUT_MS$1, maxCommits = MAX_MERGE_STATE_COMMITS } = {}) {
|
|
257
|
+
const reads = mergeStateReads(target, maxCommits);
|
|
258
|
+
let step = reads.next();
|
|
259
|
+
while (!step.done) {
|
|
260
|
+
const { args, options } = step.value;
|
|
261
|
+
try {
|
|
262
|
+
step = reads.next(git$1(path, args, {
|
|
263
|
+
timeoutMs,
|
|
264
|
+
...options
|
|
265
|
+
}));
|
|
266
|
+
} catch (error) {
|
|
267
|
+
step = reads.throw(error);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return step.value;
|
|
271
|
+
}
|
|
272
|
+
/** `mergeState` without blocking the event loop during Git reads. */
|
|
273
|
+
async function mergeStateAsync(path, target, { timeoutMs = GIT_TIMEOUT_MS$1, maxCommits = MAX_MERGE_STATE_COMMITS } = {}) {
|
|
274
|
+
const reads = mergeStateReads(target, maxCommits);
|
|
275
|
+
let step = reads.next();
|
|
276
|
+
while (!step.done) {
|
|
277
|
+
const { args, options } = step.value;
|
|
278
|
+
try {
|
|
279
|
+
step = reads.next(await gitAsync(path, args, {
|
|
280
|
+
timeoutMs,
|
|
281
|
+
...options
|
|
282
|
+
}));
|
|
283
|
+
} catch (error) {
|
|
284
|
+
step = reads.throw(error);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return step.value;
|
|
288
|
+
}
|
|
289
|
+
/** The last fetch timestamp, or null, read without blocking on Git. */
|
|
290
|
+
async function lastFetchedAtAsync(repo) {
|
|
291
|
+
return fetchTime(await gitQuietAsync(repo, [
|
|
292
|
+
"rev-parse",
|
|
293
|
+
"--path-format=absolute",
|
|
294
|
+
"--git-path",
|
|
295
|
+
"FETCH_HEAD"
|
|
296
|
+
]));
|
|
297
|
+
}
|
|
298
|
+
/** The existing origin/HEAD target, or a refusal, without fetching or blocking on Git. */
|
|
299
|
+
async function localDefaultBranchAsync(repo) {
|
|
300
|
+
return defaultBranch(repo, await gitQuietAsync(repo, [
|
|
301
|
+
"symbolic-ref",
|
|
302
|
+
"--quiet",
|
|
303
|
+
"refs/remotes/origin/HEAD"
|
|
304
|
+
]));
|
|
305
|
+
}
|
|
306
|
+
/** Refreshes origin/HEAD without credential prompts when the last fetch is at least ten minutes old. */
|
|
307
|
+
async function fetchDefaultBranchAsync(repo, now = Date.now()) {
|
|
308
|
+
const target = await localDefaultBranchAsync(repo);
|
|
309
|
+
if ("error" in target) return target;
|
|
310
|
+
const at = await lastFetchedAtAsync(repo);
|
|
311
|
+
if (at !== null && now - at < 6e5) return target;
|
|
312
|
+
const branch = target.ref.slice(20);
|
|
313
|
+
try {
|
|
314
|
+
await gitAsync(repo, [
|
|
315
|
+
"fetch",
|
|
316
|
+
"--quiet",
|
|
317
|
+
"--no-tags",
|
|
318
|
+
"--no-recurse-submodules",
|
|
319
|
+
"origin",
|
|
320
|
+
`+refs/heads/${branch}:${target.ref}`
|
|
321
|
+
], {
|
|
322
|
+
write: true,
|
|
323
|
+
timeoutMs: FETCH_TIMEOUT_MS,
|
|
324
|
+
env: { GIT_TERMINAL_PROMPT: "0" }
|
|
325
|
+
});
|
|
326
|
+
} catch (error) {
|
|
327
|
+
return { error: `git fetch origin ${branch} failed: ${failure(error)}` };
|
|
328
|
+
}
|
|
329
|
+
return target;
|
|
330
|
+
}
|
|
266
331
|
//#endregion
|
|
267
332
|
//#region src/status-measures.ts
|
|
268
333
|
const LIVE_DISK_MAX_AGE_MS = 3e5;
|
|
@@ -361,6 +426,38 @@ function statusPullRequest(fact, checkedAt) {
|
|
|
361
426
|
checkedAt
|
|
362
427
|
};
|
|
363
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* Writes a pull request lookup into the cache `status` and report-only `gc` read. A lookup made without detail is
|
|
431
|
+
* marked `partial`, so `status` asks again for the title, checks and review decision; until then it keeps the title
|
|
432
|
+
* cached for the same pull request, and the checks and review decision cached for the same HEAD.
|
|
433
|
+
*/
|
|
434
|
+
function recordPullRequestLookup({ path, branch, head }, fact, checkedAt) {
|
|
435
|
+
let pullRequest = fact ? statusPullRequest(fact, checkedAt) : null;
|
|
436
|
+
const partial = pullRequest !== null && fact?.title === void 0;
|
|
437
|
+
const previous = partial ? readPullRequestCache(path) : null;
|
|
438
|
+
if (pullRequest && previous?.pullRequest?.number === pullRequest.number) {
|
|
439
|
+
const same = previous.head === head;
|
|
440
|
+
pullRequest = {
|
|
441
|
+
...pullRequest,
|
|
442
|
+
title: previous.pullRequest.title,
|
|
443
|
+
checks: same ? previous.pullRequest.checks : null,
|
|
444
|
+
reviewDecision: same ? previous.pullRequest.reviewDecision : null
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
const entry = {
|
|
448
|
+
path,
|
|
449
|
+
branch,
|
|
450
|
+
head,
|
|
451
|
+
checkedAt,
|
|
452
|
+
pullRequest,
|
|
453
|
+
...fact ? {
|
|
454
|
+
containsHead: fact.containsHead,
|
|
455
|
+
endedAt: fact.endedAt
|
|
456
|
+
} : {},
|
|
457
|
+
...partial ? { partial: true } : {}
|
|
458
|
+
};
|
|
459
|
+
writeCacheFile(pullRequestCacheFile(path), entry);
|
|
460
|
+
}
|
|
364
461
|
function canonicalPath(path) {
|
|
365
462
|
try {
|
|
366
463
|
return realpathSync(path);
|
|
@@ -612,7 +709,7 @@ function createStatusMeasurer({ updated, now = Date.now }) {
|
|
|
612
709
|
const head = await branchHead(repository, branch);
|
|
613
710
|
if (!head) continue;
|
|
614
711
|
const cached = readPullRequestCache(path);
|
|
615
|
-
if (!(cached?.branch === branch && cached.head === head && now() - Date.parse(cached.checkedAt) < PULL_REQUEST_MAX_AGE_MS)) byRepository.set(repository, [...byRepository.get(repository) ?? [], {
|
|
712
|
+
if (!(cached?.branch === branch && cached.head === head && !cached.partial && now() - Date.parse(cached.checkedAt) < PULL_REQUEST_MAX_AGE_MS)) byRepository.set(repository, [...byRepository.get(repository) ?? [], {
|
|
616
713
|
path,
|
|
617
714
|
cwd: repository,
|
|
618
715
|
branch,
|
|
@@ -625,14 +722,11 @@ function createStatusMeasurer({ updated, now = Date.now }) {
|
|
|
625
722
|
results.forEach((result, i) => {
|
|
626
723
|
if (!("pullRequest" in result)) return;
|
|
627
724
|
const { path, branch, head } = queries[i];
|
|
628
|
-
|
|
725
|
+
recordPullRequestLookup({
|
|
629
726
|
path,
|
|
630
727
|
branch,
|
|
631
|
-
head
|
|
632
|
-
|
|
633
|
-
pullRequest: result.pullRequest ? statusPullRequest(result.pullRequest, at) : null
|
|
634
|
-
};
|
|
635
|
-
writeCacheFile(pullRequestCacheFile(path), entry);
|
|
728
|
+
head
|
|
729
|
+
}, result.pullRequest, at);
|
|
636
730
|
});
|
|
637
731
|
if (results.some((result) => "pullRequest" in result)) updated();
|
|
638
732
|
}
|
|
@@ -808,4 +902,4 @@ function workspacePhase(live, state, { now = Date.now(), survey = ownership_clai
|
|
|
808
902
|
};
|
|
809
903
|
}
|
|
810
904
|
//#endregion
|
|
811
|
-
export { forgetStatusMeasures as a, createStatusMeasurer as i, workspacePhase as n,
|
|
905
|
+
export { forgetStatusMeasures as a, FETCH_FRESH_MS as c, localDefaultBranchAsync as d, mergeState as f, createStatusMeasurer as i, fetchDefaultBranchAsync as l, workspacePhase as n, recordPullRequestLookup as o, mergeStateAsync as p, applyStatusMeasures as r, writeCacheFile as s, startWarmProgress as t, lastFetchedAtAsync as u };
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { o as readWebRecord, r as cdpEndpoint } from "./state-
|
|
8
|
-
import {
|
|
9
|
-
import { t as liveWebRecord } from "./page-
|
|
1
|
+
import { m as workspaceLogsDir } from "./paths-DQtTgsBf.mjs";
|
|
2
|
+
import { E as upsertProject, p as getProject } from "./config-CYcBF478.mjs";
|
|
3
|
+
import { f as refuseNoProject, l as phaseLine } from "./command-output-B1UrjZHL.mjs";
|
|
4
|
+
import { i as recordWorkspaceUse } from "./workspace-state-Cjuigeeu.mjs";
|
|
5
|
+
import { J as resolveProjectSettingsAsync, a as SETTING_SHAPE_REMEDY, et as settingShapeErrors } from "./settings-CsJDEXgK.mjs";
|
|
6
|
+
import { f as projectRegistry, n as findCommandWorkspace } from "./project-BZNjmW_8.mjs";
|
|
7
|
+
import { o as readWebRecord, r as cdpEndpoint } from "./state-C4ZtUisW.mjs";
|
|
8
|
+
import { a as workspaceLinkLine, o as workspaceLinks } from "./stim-desktop-C12we7lz.mjs";
|
|
9
|
+
import { t as liveWebRecord } from "./page-CPaHeYqj.mjs";
|
|
10
|
+
import { n as ensureWorkspaceStorageSafely } from "./native-runtime-Dg1Q7tfF.mjs";
|
|
10
11
|
import chalk from "chalk";
|
|
11
12
|
//#region src/commands/web.ts
|
|
12
13
|
const printNote = (line) => console.error(line);
|
|
13
|
-
async function runWeb({ root, headed, note }) {
|
|
14
|
+
async function runWeb({ root, headed, note, context }) {
|
|
14
15
|
const startedAt = Date.now();
|
|
15
16
|
await ensureWorkspaceStorageSafely(root, { note });
|
|
16
17
|
if (!getProject(root)) upsertProject(root, {});
|
|
17
|
-
const { settings } =
|
|
18
|
+
const { settings } = await resolveProjectSettingsAsync(root, context ? {
|
|
19
|
+
env: context.env,
|
|
20
|
+
signal: context.signal
|
|
21
|
+
} : void 0);
|
|
18
22
|
const [shapeError] = settingShapeErrors(settings);
|
|
19
23
|
if (shapeError) return {
|
|
20
24
|
ok: false,
|
|
@@ -39,7 +43,8 @@ async function runWeb({ root, headed, note }) {
|
|
|
39
43
|
const runtime = (await selected.load()).runtime({
|
|
40
44
|
settings,
|
|
41
45
|
headed,
|
|
42
|
-
note
|
|
46
|
+
note,
|
|
47
|
+
context
|
|
43
48
|
});
|
|
44
49
|
const preparation = await runtime.prepare();
|
|
45
50
|
if (!preparation.ok) return {
|
|
@@ -106,7 +111,7 @@ function webCommand(program) {
|
|
|
106
111
|
}
|
|
107
112
|
const { facts, remedy } = result;
|
|
108
113
|
if (remedy) printNote(chalk.yellow(phaseLine("launch", remedy)));
|
|
109
|
-
const links = workspaceLinks(root, { platform: "web" });
|
|
114
|
+
const links = await workspaceLinks(root, { platform: "web" });
|
|
110
115
|
if (json) {
|
|
111
116
|
console.log(JSON.stringify(links ? {
|
|
112
117
|
...facts,
|