stim 1.2.0 → 1.3.1

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.
Files changed (59) hide show
  1. package/README.md +34 -3
  2. package/dist/{android-Bcmev2s2.mjs → android-CT-PkXUh.mjs} +157 -62
  3. package/dist/{android-cas-D6HPZ6UQ.mjs → android-cas-DXorPCi_.mjs} +5 -5
  4. package/dist/android-hMj83VpN.mjs +1374 -0
  5. package/dist/{app-install-NFxUahnH.mjs → app-install-DIp9riNx.mjs} +6 -6
  6. package/dist/{build-slots-D0b6sJyo.mjs → build-slots-C4AouyNz.mjs} +2 -2
  7. package/dist/{cache-manifest-Cu4_Znw9.mjs → cache-manifest-CXR-Y8pH.mjs} +1 -1
  8. package/dist/cache-manifest.mjs +1 -1
  9. package/dist/cli.mjs +13 -13
  10. package/dist/collector-run.d.mts +3 -1
  11. package/dist/collector-run.mjs +33 -8
  12. package/dist/{config-CMtIaTk9.mjs → config-CcefMY2Q.mjs} +93 -12
  13. package/dist/{deps-BLBsTNDS.mjs → deps-0Yt0Inly.mjs} +1 -1
  14. package/dist/{dev-client-RpvXxCXV.mjs → dev-client-VfSZNLT4.mjs} +186 -9
  15. package/dist/{device-CoCPmazS.mjs → device-Bbv45Z9Z.mjs} +19 -11
  16. package/dist/{device-lease-Dpik41RY.mjs → device-lease-CJwK7OZr.mjs} +107 -83
  17. package/dist/{device-pool-B5pEVa3t.mjs → device-pool-CcBNTvM7.mjs} +18 -12
  18. package/dist/{device-remote-E81KAdXf.mjs → device-remote-DAA0Zm6Z.mjs} +7 -7
  19. package/dist/{doctor-CqPeMsSm.mjs → doctor-B4EITgQB.mjs} +11 -12
  20. package/dist/{doctor-D_CX7ib5.mjs → doctor-BueDfLYG.mjs} +4 -4
  21. package/dist/{error-diagnostics-Dw8Gn3yw.mjs → error-diagnostics-DwhNBFDU.mjs} +62 -52
  22. package/dist/{gc-B7KkDinF.mjs → gc-BRu62v4o.mjs} +66 -57
  23. package/dist/{guide-BS2Xc24o.mjs → guide-D95E0u3i.mjs} +307 -74
  24. package/dist/{ios-B7KLgIp5.mjs → ios-DAju3TVy.mjs} +183 -54
  25. package/dist/{ios-D1h1Di39.mjs → ios-Deh5js5V.mjs} +78 -40
  26. package/dist/{ios-device-xNt0Lg6v.mjs → ios-device-CWOM_S44.mjs} +1 -1
  27. package/dist/{logs-DcX9AvRF.mjs → logs-CAdwW6c2.mjs} +34 -6
  28. package/dist/{logs-query-oqn47Ffx.mjs → logs-query-Cdp5aaCH.mjs} +23 -6
  29. package/dist/{metro-COslRK_F.mjs → metro-CORqXyTL.mjs} +2 -2
  30. package/dist/{ndjson-DcAtEx_K.mjs → ndjson-BZwI1NBv.mjs} +5 -2
  31. package/dist/{ownership-CGPart6T.mjs → ownership-8O073GIC.mjs} +3 -3
  32. package/dist/{ownership-CYOyqxUo.mjs → ownership-DXcol4oU.mjs} +3 -3
  33. package/dist/{ownership-claim-7zRxxTfZ.mjs → ownership-claim-BtPtJVmq.mjs} +38 -23
  34. package/dist/{project-BBTVABUz.mjs → project-fKmuIaMI.mjs} +2 -2
  35. package/dist/{reclaim-C5Jmuahx.mjs → reclaim-CUmwucWG.mjs} +80 -74
  36. package/dist/{reload-Z8nKifAk.mjs → reload-CWpXoOgN.mjs} +32 -24
  37. package/dist/{server-bare-DEk37Mz2.mjs → server-bare-DEzPZLvf.mjs} +2 -2
  38. package/dist/server-expo-44em5Pmg.mjs +2 -0
  39. package/dist/{server-expo-C3ktAwUG.mjs → server-expo-DizT4OMk.mjs} +4 -4
  40. package/dist/{settings-DwU1_U_q.mjs → settings-DEJf6_kJ.mjs} +2 -2
  41. package/dist/slot-launch-CZklomj6.mjs +19 -0
  42. package/dist/{start-BrY4EuIg.mjs → start-B5G4NjiA.mjs} +11 -11
  43. package/dist/{state-CZ-ER-8d.mjs → state-B3XA2wp2.mjs} +9 -9
  44. package/dist/{stats-BCWEVLrM.mjs → stats-BR-kwj0B.mjs} +1 -1
  45. package/dist/{stats-BsF15Bti.mjs → stats-CaaQr4yN.mjs} +3 -3
  46. package/dist/{status-DFI1Hfpg.mjs → status-CI9clRSb.mjs} +55 -24
  47. package/dist/{stop-B7DR4awK.mjs → stop-CQhffpmX.mjs} +2 -2
  48. package/dist/{stop-Btg770vV.mjs → stop-CjlgDk0a.mjs} +93 -42
  49. package/dist/supervisor-run.d.mts +1 -2
  50. package/dist/supervisor-run.mjs +5 -5
  51. package/dist/{remote-cache-DDmJ1Roq.mjs → teardown--gESs9ck.mjs} +985 -887
  52. package/dist/{workspace-process-lock-BKfdys1q.mjs → workspace-process-lock-IBj1Towr.mjs} +1 -1
  53. package/dist/{worktree-BPTbI-LN.mjs → worktree-DtQGO9-s.mjs} +121 -111
  54. package/dist/{worktree-C79xx_kM.mjs → worktree-Eq6TLH8N.mjs} +1 -1
  55. package/dist/{xcode-DeKCribl.mjs → xcode-xnxyvJkD.mjs} +159 -96
  56. package/package.json +5 -5
  57. package/dist/android-K63_0UfF.mjs +0 -727
  58. package/dist/build-lock-BsVoLDaq.mjs +0 -645
  59. package/dist/server-expo-Drd7ksHu.mjs +0 -2
@@ -1,4 +1,4 @@
1
- import { f as releaseClaim, h as tryAcquireClaim } from "./ownership-claim-7zRxxTfZ.mjs";
1
+ import { d as releaseClaim, m as tryAcquireClaim } from "./ownership-claim-BtPtJVmq.mjs";
2
2
  import { join } from "node:path";
3
3
  //#region src/engine/workspace-process-lock.ts
4
4
  const DEFAULT_WAIT_MS = 6e4;
@@ -1,17 +1,17 @@
1
1
  import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { S as upsertProject, f as getProject, g as loadConfig, h as isPathPrefix, u as getConfigDir, v as removeProject, w as captureProcessIdentity } from "./config-CMtIaTk9.mjs";
3
- import { c as readMetroTunnel, u as readRemoteSession } from "./state-CZ-ER-8d.mjs";
4
- import { _ as resolveFullRef, b as warmWorktreePaths, c as hasRemote, d as isPodInstallChurn, f as listWorktrees, h as removeWorktree, i as depsOutOfSync, l as hasUncommittedWork, m as readWorktreeExclude, n as cloneIgnoredEntries, o as dirtyPaths, p as podsOutOfSync, r as deleteBranch, s as gitCommonDir, t as branchExists, u as isMainWorkingTree, v as restoreFile, y as unpushedCommits } from "./worktree-C79xx_kM.mjs";
5
- import { a as findProjectRoot } from "./project-BBTVABUz.mjs";
6
- import { v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
7
- import { A as resolveSettings, I as unknownSettingKeys, N as settingShapeErrors, a as SETTING_SHAPE_REMEDY } from "./settings-DwU1_U_q.mjs";
2
+ import { S as upsertProject, f as getProject, g as loadConfig, h as isPathPrefix, u as getConfigDir, v as removeProject, w as captureProcessIdentity } from "./config-CcefMY2Q.mjs";
3
+ import { c as readMetroTunnel, u as readRemoteSession } from "./state-B3XA2wp2.mjs";
4
+ import { _ as resolveFullRef, b as warmWorktreePaths, c as hasRemote, d as isPodInstallChurn, f as listWorktrees, h as removeWorktree, i as depsOutOfSync, l as hasUncommittedWork, m as readWorktreeExclude, n as cloneIgnoredEntries, o as dirtyPaths, p as podsOutOfSync, r as deleteBranch, s as gitCommonDir, t as branchExists, u as isMainWorkingTree, v as restoreFile, y as unpushedCommits } from "./worktree-Eq6TLH8N.mjs";
5
+ import { a as findProjectRoot } from "./project-fKmuIaMI.mjs";
8
6
  import { a as formatElapsed, f as releasedLeaseFact, i as formatDuration, l as phaseLine, m as shortUdid, u as plural } from "./command-output-8wHMEde0.mjs";
9
- import { a as clearClaimChild, c as isClaimUnavailable, d as readClaimSet, f as releaseClaim, h as tryAcquireClaim, i as claimRemoveCommand, l as markClaimChildPending, m as settleClaim, p as setClaimChild, r as claimFailure, s as isClaimRefusal, u as processGroupAlive } from "./ownership-claim-7zRxxTfZ.mjs";
10
- import { g as podInstallCommand, r as HEARTBEAT_INTERVAL_MS } from "./xcode-DeKCribl.mjs";
11
- import { a as installedNpmTreeIsValid, i as hasInstalledDependencies, o as locallyKnownUpstream, t as dependencyState } from "./doctor-CqPeMsSm.mjs";
12
- import { c as withManagedTunnelRemovalLock, o as withManagedRemoteWorktreeRemovalLock } from "./ownership-CYOyqxUo.mjs";
13
- import { n as reclaimProject } from "./reclaim-C5Jmuahx.mjs";
14
- import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-BLBsTNDS.mjs";
7
+ import { a as clearClaimChild, c as markClaimChildPending, d as releaseClaim, f as setClaimChild, i as claimRemoveCommand, l as processGroupAlive, m as tryAcquireClaim, n as ClaimUnavailableError, p as settleClaim, r as claimFailure } from "./ownership-claim-BtPtJVmq.mjs";
8
+ import { A as resolveSettings, I as unknownSettingKeys, N as settingShapeErrors, a as SETTING_SHAPE_REMEDY } from "./settings-DEJf6_kJ.mjs";
9
+ import { a as POOL_SETTING_REMEDY, c as parkedMaxSetting } from "./teardown--gESs9ck.mjs";
10
+ import { g as podInstallCommand, r as HEARTBEAT_INTERVAL_MS } from "./xcode-xnxyvJkD.mjs";
11
+ import { a as installedNpmTreeIsValid, i as hasInstalledDependencies, o as locallyKnownUpstream, t as dependencyState } from "./doctor-B4EITgQB.mjs";
12
+ import { c as withManagedTunnelRemovalLock, o as withManagedRemoteWorktreeRemovalLock } from "./ownership-DXcol4oU.mjs";
13
+ import { n as reclaimProject } from "./reclaim-CUmwucWG.mjs";
14
+ import { a as runPodInstall, i as runCaptured, n as podsAreStale, r as readPodState, t as DEPS_ERROR } from "./deps-0Yt0Inly.mjs";
15
15
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
16
16
  import { createHash, randomUUID } from "node:crypto";
17
17
  import { join, relative } from "node:path";
@@ -56,57 +56,10 @@ function asHolder(holder) {
56
56
  function waitingLine(holder, elapsedMs) {
57
57
  return phaseLine("lock", `waiting ${formatElapsed(elapsedMs)} for ${warmCommand(holder.phase)} (pid ${holder.pid}) -- stim guide lifecycle options`);
58
58
  }
59
- function warmClaimAcquiredLine(wait) {
60
- if (!wait.holder || wait.waitedMs <= 0) return phaseLine("lock", "acquired");
61
- return phaseLine("lock", `acquired (waited ${formatElapsed(wait.waitedMs)} for ${warmCommand(wait.holder.phase)} pid ${wait.holder.pid}) -- stim guide lifecycle options`);
62
- }
63
- function warmClaimUnavailableLine(reason) {
64
- return phaseLine("lock", `unavailable (${reason}); copying without it`);
65
- }
66
- /**
67
- * The reason a copy may proceed without the claim, or null when it must refuse. Plain `warm` worked on an
68
- * unwritable STIM_HOME before any claim existed and only reads, so the states in which no claim can be
69
- * recorded at all degrade to an unsynchronised copy: no process identity, a claim store the filesystem
70
- * rejects, and a claim store whose own path holds a file. A claim record Stim cannot resolve and a wait
71
- * that ran out are refusals: neither state can exist unless the claim does, so refusing them takes
72
- * nothing away.
73
- */
74
- function warmClaimDegradation(error) {
75
- if (isClaimUnavailable(error)) return error.message;
76
- if (isClaimRefusal(error)) return error.reason === "the claim path is a file, not a claim directory" ? `${error.claimPath}: ${error.reason}` : null;
77
- const code = error?.code;
78
- if (typeof code === "string" && code.startsWith("STIM_")) return null;
79
- return error?.message ?? String(error);
80
- }
81
- /**
82
- * What a copy that could not record a claim of its own would overlap if it went ahead anyway. Reading the
83
- * claim set classifies without writing anything and without refusing, so it works in exactly the states
84
- * that made the claim unrecordable -- a read-only STIM_HOME included. It is a read before a copy rather
85
- * than a held claim, so a refresh that starts after it is not covered; it closes the window in which one
86
- * is already installing, which is the window a refresh actually occupies.
87
- */
88
- function warmClaimBlocker(repositoryRoot) {
89
- const survey = readClaimSet(warmClaimPath(repositoryRoot));
90
- const refresh = survey.live.find((holder) => holder.mode === "exclusive");
91
- if (refresh) return {
92
- kind: "refresh",
93
- holder: asHolder(refresh)
94
- };
95
- const unresolved = survey.unresolved.find((problem) => problem.path.endsWith(".claim"));
96
- if (unresolved) return {
97
- kind: "unresolved",
98
- path: unresolved.path,
99
- reason: unresolved.reason
100
- };
101
- return null;
102
- }
103
- function warmClaimBlockedLine(reason, blocker) {
104
- const what = blocker.kind === "refresh" ? `${warmCommand(blocker.holder.phase)} (pid ${blocker.holder.pid}) holds this repository` : `a claim at ${blocker.path} cannot be resolved: ${blocker.reason}`;
105
- return phaseLine("lock", `unavailable (${reason}); ${what}`);
106
- }
107
- function warmClaimBlockedRefusal(blocker) {
108
- if (blocker.kind === "refresh") return "Refusing to copy from a source checkout a refresh is rewriting, even without a claim of its own. Wait for that refresh to finish, then run warm again.";
109
- return `Refusing to copy past a claim Stim cannot resolve. If nothing is warming, remove it and run warm again:\n ${claimRemoveCommand(blocker.path)}`;
59
+ function warmClaimAcquiredLine(wait, detail = "") {
60
+ const acquired = `acquired${detail ? ` ${detail}` : ""}`;
61
+ if (!wait.holder || wait.waitedMs < 1e3) return phaseLine("lock", acquired);
62
+ return phaseLine("lock", `${acquired} (waited ${formatElapsed(wait.waitedMs)} for ${warmCommand(wait.holder.phase)} pid ${wait.holder.pid}) -- stim guide lifecycle options`);
110
63
  }
111
64
  function installerWaitingLine(pid, elapsedMs) {
112
65
  return phaseLine("lock", `waiting on the install this refresh spawned (pid ${pid}, ${formatElapsed(elapsedMs)} elapsed) -- stim guide lifecycle options`);
@@ -183,7 +136,7 @@ function timeoutError(holder, elapsedMs, root) {
183
136
  error.code = "STIM_LOCK_TIMEOUT";
184
137
  return error;
185
138
  }
186
- async function acquireWarmClaim({ repositoryRoot, phase, now = Date.now, sleep = defaultSleep, pollMs = WARM_CLAIM_POLL_MS, progressMs = WARM_CLAIM_PROGRESS_MS, ceilingMs = WARM_CLAIM_CEILING_MS, out = () => {} }) {
139
+ async function acquireWarmClaim({ repositoryRoot, phase, mode = phase === "refresh" ? "exclusive" : "shared", now = Date.now, sleep = defaultSleep, pollMs = WARM_CLAIM_POLL_MS, progressMs = WARM_CLAIM_PROGRESS_MS, ceilingMs = WARM_CLAIM_CEILING_MS, out = () => {} }) {
187
140
  const root = warmClaimPath(repositoryRoot);
188
141
  const started = now();
189
142
  let lastProgress = started;
@@ -193,7 +146,7 @@ async function acquireWarmClaim({ repositoryRoot, phase, now = Date.now, sleep =
193
146
  for (;;) {
194
147
  const attempt = pending ? settleClaim(pending) : tryAcquireClaim({
195
148
  root,
196
- mode: phase === "refresh" ? "exclusive" : "shared",
149
+ mode,
197
150
  label: WARM_CLAIM_LABEL
198
151
  });
199
152
  const acquired = attempt.acquired;
@@ -228,6 +181,12 @@ async function acquireWarmClaim({ repositoryRoot, phase, now = Date.now, sleep =
228
181
  }
229
182
  } catch (error) {
230
183
  releaseClaim(pending);
184
+ if ([
185
+ "EACCES",
186
+ "EPERM",
187
+ "EROFS",
188
+ "ENOENT"
189
+ ].includes(error?.code ?? "")) throw new ClaimUnavailableError(error.message, { claimPath: root });
231
190
  throw error;
232
191
  }
233
192
  }
@@ -521,6 +480,38 @@ function branchRemote(root, branch) {
521
480
  `branch.${branch}.remote`
522
481
  ])?.trim() || "origin";
523
482
  }
483
+ function remoteUpstreamIsCurrent(root, branch) {
484
+ const exec = getExecutor();
485
+ const merge = exec.runFileQuiet("git", [
486
+ "-C",
487
+ root,
488
+ "config",
489
+ "--get-all",
490
+ `branch.${branch}.merge`
491
+ ])?.trim();
492
+ if (!merge) return true;
493
+ if (!merge.startsWith("refs/") || merge.includes("\n")) return false;
494
+ const remote = branchRemote(root, branch);
495
+ if (remote === ".") return true;
496
+ const local = resolveFullRef(root, "@{upstream}");
497
+ if (!local) return false;
498
+ const advertised = exec.runFileQuiet("git", [
499
+ "-C",
500
+ root,
501
+ "ls-remote",
502
+ "--exit-code",
503
+ "--refs",
504
+ "--",
505
+ remote,
506
+ merge
507
+ ], {
508
+ timeoutMs: FETCH_TIMEOUT_MS,
509
+ env: { GIT_TERMINAL_PROMPT: "0" }
510
+ });
511
+ if (advertised === null) return false;
512
+ const refs = advertised.trim().split("\n").map((line) => line.split(/\s+/));
513
+ return refs.length === 1 && refs[0]?.[0] === local && refs[0]?.[1] === merge;
514
+ }
524
515
  function gitPath(...parts) {
525
516
  return parts.filter((part) => part && part !== ".").join("/");
526
517
  }
@@ -603,7 +594,7 @@ function fastForward(root, upstream) {
603
594
  };
604
595
  }
605
596
  }
606
- async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = null, now = Date.now, heartbeatMs = HEARTBEAT_INTERVAL_MS, installer = NO_INSTALLER_CLAIM }) {
597
+ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = null, now = Date.now, heartbeatMs = HEARTBEAT_INTERVAL_MS, installer = NO_INSTALLER_CLAIM, inspectOnly = false }) {
607
598
  const state = readMainCheckoutState(root);
608
599
  const refusal = mainCheckoutRefusal(root, state);
609
600
  if (refusal) return refusal;
@@ -640,7 +631,9 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
640
631
  };
641
632
  };
642
633
  const before = resolveFullRef(root, "HEAD") ?? "";
643
- if (getExecutor().runFileQuiet("git", [
634
+ if (inspectOnly) {
635
+ if (!remoteUpstreamIsCurrent(root, branch)) return { mutation: "fetch upstream" };
636
+ } else if (getExecutor().runFileQuiet("git", [
644
637
  "-C",
645
638
  root,
646
639
  "fetch",
@@ -652,6 +645,7 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
652
645
  }) === null) emit(phaseLine("checkout", "could not fetch; continuing with the local state"));
653
646
  const plan = checkoutPlan(locallyKnownUpstream(root));
654
647
  if (plan.kind === "diverged") return divergedRefusal(root, branch, plan);
648
+ if (inspectOnly && plan.kind === "fast-forward") return { mutation: `fast-forward ${plan.behind} commit${plan.behind === 1 ? "" : "s"}` };
655
649
  const depsBefore = dependencyState(existsSync(appDir) ? appDir : root);
656
650
  const priorInstall = depsBefore ? readInstallEvidence(depsBefore.root) : null;
657
651
  const marked = plan.kind === "fast-forward" ? depsBefore : null;
@@ -683,6 +677,7 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
683
677
  });
684
678
  const depsSubject = `source ${dependencies?.root ?? root}: ${deps.reason}`;
685
679
  if (deps.run && dependencies) {
680
+ if (inspectOnly) return { mutation: deps.reason };
686
681
  writeInstallEvidence(dependencies.root, dependencies.lock, consumed, false);
687
682
  const install = await runInstallCommand({
688
683
  command: dependencies.command,
@@ -719,6 +714,7 @@ async function refreshMainCheckout({ root, appDir, settings, emit, spawnFn = nul
719
714
  emit(stepLine("pods", `${where}${pods.reason}`, "skipped"));
720
715
  return null;
721
716
  }
717
+ if (inspectOnly) return { mutation: pods.reason };
722
718
  const result = await runPodInstall(appDir, null, {
723
719
  spawnFn: spawn,
724
720
  now,
@@ -793,31 +789,6 @@ function registerWarm(worktree) {
793
789
  for (const key of unknownSettingKeys(settings)) console.error(chalk.yellow(`Warning: setting "${key}" is not read by Stim and will be ignored.`));
794
790
  return settings;
795
791
  };
796
- if (opts.refresh) {
797
- const settings = readSettings();
798
- if (!settings) {
799
- process.exitCode = 1;
800
- return;
801
- }
802
- const failure = await withWarmClaim({
803
- repositoryRoot: root,
804
- phase: "refresh",
805
- out: console.error
806
- }, (hold) => {
807
- console.error(warmClaimAcquiredLine(hold.wait));
808
- return refreshMainCheckout({
809
- root,
810
- appDir: mainCheckoutAppDir(root, target),
811
- settings,
812
- emit: (line) => console.error(line),
813
- installer: hold.installer
814
- });
815
- });
816
- if (failure) {
817
- reportRefreshFailure(failure);
818
- return;
819
- }
820
- }
821
792
  const copy = (wait) => {
822
793
  if (wait?.holder) console.error(warmClaimAcquiredLine(wait));
823
794
  const incomplete = incompleteInstallRefusal(root, mainCheckoutAppDir(root, target));
@@ -846,30 +817,69 @@ function registerWarm(worktree) {
846
817
  console.error(phaseLine("carry", `${result.failed.length ? "incomplete" : "complete"}: ${result.copied.length} ignored entries copied, ${result.skipped.length} kept, ${result.failed.length} failed`));
847
818
  if (result.failed.length) process.exitCode = 1;
848
819
  };
849
- let hold = null;
850
- try {
851
- hold = await acquireWarmClaim({
820
+ if (opts.refresh) {
821
+ const inspect = await acquireWarmClaim({
852
822
  repositoryRoot: root,
853
- phase: "copy",
823
+ phase: "refresh",
824
+ mode: "shared",
854
825
  out: console.error
855
826
  });
856
- } catch (error) {
857
- const degraded = opts.refresh ? null : warmClaimDegradation(error);
858
- if (degraded === null) throw error;
859
- const blocker = warmClaimBlocker(root);
860
- if (blocker) {
861
- console.error(chalk.dim(warmClaimBlockedLine(degraded, blocker)));
862
- console.error(chalk.red(warmClaimBlockedRefusal(blocker)));
863
- throw error;
827
+ let mutation;
828
+ try {
829
+ const settings = readSettings();
830
+ if (!settings) {
831
+ process.exitCode = 1;
832
+ return;
833
+ }
834
+ const lines = [];
835
+ const result = await refreshMainCheckout({
836
+ root,
837
+ appDir: mainCheckoutAppDir(root, target),
838
+ settings,
839
+ emit: (line) => lines.push(line),
840
+ inspectOnly: true
841
+ });
842
+ if (!result || !("mutation" in result)) {
843
+ console.error(warmClaimAcquiredLine(inspect.wait, result ? "shared" : "shared (seed current)"));
844
+ for (const line of lines) console.error(line);
845
+ if (result) reportRefreshFailure(result);
846
+ else copy(null);
847
+ return;
848
+ }
849
+ mutation = result.mutation;
850
+ } finally {
851
+ inspect.release();
864
852
  }
865
- console.error(chalk.dim(warmClaimUnavailableLine(degraded)));
866
- }
867
- if (!hold) copy(null);
868
- else try {
869
- copy(hold.wait);
870
- } finally {
871
- hold.release();
853
+ const failure = await withWarmClaim({
854
+ repositoryRoot: root,
855
+ phase: "refresh",
856
+ out: console.error
857
+ }, async (hold) => {
858
+ console.error(warmClaimAcquiredLine(hold.wait, `exclusive (${mutation})`));
859
+ const settings = readSettings();
860
+ if (!settings) {
861
+ process.exitCode = 1;
862
+ return null;
863
+ }
864
+ return refreshMainCheckout({
865
+ root,
866
+ appDir: mainCheckoutAppDir(root, target),
867
+ settings,
868
+ emit: (line) => console.error(line),
869
+ installer: hold.installer
870
+ });
871
+ });
872
+ if (failure) {
873
+ reportRefreshFailure(failure);
874
+ return;
875
+ }
876
+ if (process.exitCode) return;
872
877
  }
878
+ await withWarmClaim({
879
+ repositoryRoot: root,
880
+ phase: "copy",
881
+ out: console.error
882
+ }, (hold) => copy(hold.wait));
873
883
  } catch (error) {
874
884
  const code = error?.code;
875
885
  console.error(chalk.red(`Could not warm this worktree: ${error.message}`));
@@ -1,5 +1,5 @@
1
1
  import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
- import { g as loadConfig, u as getConfigDir } from "./config-CMtIaTk9.mjs";
2
+ import { g as loadConfig, u as getConfigDir } from "./config-CcefMY2Q.mjs";
3
3
  import { accessSync, chmodSync, constants, lstatSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
4
4
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import { chmodSync as chmodSync$1, existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, utimesSync } from "fs";