stim 1.3.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 (34) hide show
  1. package/README.md +4 -3
  2. package/dist/{android-CqcW1hrP.mjs → android-CT-PkXUh.mjs} +22 -19
  3. package/dist/{android-cas-BR5YJBYv.mjs → android-cas-DXorPCi_.mjs} +2 -2
  4. package/dist/{android-BqVIJoG7.mjs → android-hMj83VpN.mjs} +12 -6
  5. package/dist/{build-slots-C3-R4XQr.mjs → build-slots-C4AouyNz.mjs} +1 -1
  6. package/dist/cli.mjs +12 -12
  7. package/dist/{deps-Spz8ozgo.mjs → deps-0Yt0Inly.mjs} +1 -1
  8. package/dist/{dev-client-BjisHDB5.mjs → dev-client-VfSZNLT4.mjs} +4 -4
  9. package/dist/{device-BkiW-gkk.mjs → device-Bbv45Z9Z.mjs} +3 -3
  10. package/dist/{device-lease-BJYybF-2.mjs → device-lease-CJwK7OZr.mjs} +1 -1
  11. package/dist/{device-pool-CPbLGfrB.mjs → device-pool-CcBNTvM7.mjs} +1 -1
  12. package/dist/{device-remote-AkYCKS8U.mjs → device-remote-DAA0Zm6Z.mjs} +1 -1
  13. package/dist/{doctor-Bmv86UUW.mjs → doctor-B4EITgQB.mjs} +5 -5
  14. package/dist/{doctor-fAMXC4vl.mjs → doctor-BueDfLYG.mjs} +2 -2
  15. package/dist/{error-diagnostics-DHC31rXA.mjs → error-diagnostics-DwhNBFDU.mjs} +3 -3
  16. package/dist/{gc-GGu-8ULN.mjs → gc-BRu62v4o.mjs} +7 -7
  17. package/dist/{guide-92CPA21s.mjs → guide-D95E0u3i.mjs} +111 -61
  18. package/dist/{ios-BSXFeO5H.mjs → ios-DAju3TVy.mjs} +12 -12
  19. package/dist/{logs-DPNF4C9s.mjs → logs-CAdwW6c2.mjs} +29 -4
  20. package/dist/{logs-query-R-Cqc6Qv.mjs → logs-query-Cdp5aaCH.mjs} +1 -1
  21. package/dist/{ownership-BpCKiRlQ.mjs → ownership-DXcol4oU.mjs} +1 -1
  22. package/dist/{ownership-claim-Bf2CAfw3.mjs → ownership-claim-BtPtJVmq.mjs} +35 -21
  23. package/dist/{reclaim-iW9Cad7k.mjs → reclaim-CUmwucWG.mjs} +4 -4
  24. package/dist/{reload-DazHDSFA.mjs → reload-CWpXoOgN.mjs} +2 -2
  25. package/dist/{slot-launch-cci0xvmC.mjs → slot-launch-CZklomj6.mjs} +1 -1
  26. package/dist/{start-mObjQH2W.mjs → start-B5G4NjiA.mjs} +3 -3
  27. package/dist/{status-BxQNqu9t.mjs → status-CI9clRSb.mjs} +6 -6
  28. package/dist/{stop-CrHGcjrV.mjs → stop-CQhffpmX.mjs} +2 -2
  29. package/dist/{stop-DimGXEKY.mjs → stop-CjlgDk0a.mjs} +5 -5
  30. package/dist/{teardown-ClFp1Aax.mjs → teardown--gESs9ck.mjs} +103 -4
  31. package/dist/{workspace-process-lock-3NcQnZ0X.mjs → workspace-process-lock-IBj1Towr.mjs} +1 -1
  32. package/dist/{worktree-DxTgN1CJ.mjs → worktree-DtQGO9-s.mjs} +116 -106
  33. package/dist/{xcode-D7sAp-Zy.mjs → xcode-xnxyvJkD.mjs} +81 -44
  34. package/package.json +5 -5
@@ -62,6 +62,8 @@ warm checks for existing entries before copying, not during the copy. Do not
62
62
  edit files, install dependencies, or run another warm in that worktree until
63
63
  it finishes; concurrent files can be overwritten or removed.
64
64
  If warm fails or reports incomplete, resolve the reported failure first.
65
+ A warm that cannot record its ownership claim refuses before copying. Follow
66
+ the printed remedy and keep concurrent runs on the same STIM_HOME.
65
67
 
66
68
  Before native worktree work, run doctor for the platform in scope. It checks
67
69
  the source checkout from a linked worktree. Fix relevant findings and inspect the
@@ -80,6 +82,12 @@ current and highest observed pressure; a timeout does not establish OOM.
80
82
  Avoid repeated reboots under unchanged pressure; do not restart other
81
83
  workspaces' devices or close their apps without asking. That guide covers
82
84
  the recovery steps and profile tradeoffs.
85
+ An Android boot timeout under observed elevated memory pressure gets one
86
+ extra wait while the emulator process this run started is alive. It never
87
+ launches a second emulator. For a timeout, read guide errors STIM_NO_DEVICE
88
+ and free memory by stopping only unneeded devices in workspaces you own;
89
+ ask before closing other apps or devices. Device count alone is not evidence
90
+ of memory pressure.
83
91
  For a linked native library carrying Git metadata, add the printed .git entries to
84
92
  .fingerprintignore only when the native build does not read Git state.
85
93
 
@@ -180,8 +188,9 @@ RULES DURING THE LOOP
180
188
  - A clean logs --errors check requires exit code 0 AND no matching errors in
181
189
  captured logs. Exit code 0 alone means the query succeeded, even when errors
182
190
  were printed. Human output shows "No matching log records" on stderr for
183
- zero matches; JSON mode prints zero bytes. This does not prove launch or log
184
- capture succeeded. Do not read the NDJSON files directly.
191
+ zero matches; JSON mode prints zero bytes. A workspace with no captured
192
+ timeline refuses with STIM_NO_PROJECT and, in a monorepo, names the nearest
193
+ registered descendant app with logs. Do not read the NDJSON files directly.
185
194
  - Use stim status when resuming a workspace or recovering missing device,
186
195
  port, server, or build facts. A normal start and platform run already print
187
196
  them. Use stim doctor when a build is unexpectedly slow or the environment
@@ -196,6 +205,8 @@ the stim-<label> (<model> <runtime>) name. Never point Stim at a user-created
196
205
  emulator or simulator.
197
206
 
198
207
  worktree remove parks the workspace's simulator or emulator for later adoption.
208
+ Before owned-device teardown, Stim best-effort closes local agent-device sessions
209
+ on that exact device; failures warn and teardown continues (guide cleanup).
199
210
  A parked device is Stim-owned: never delete one by hand. gc --delete clears verified
200
211
  entries and keeps failures; see guide lifecycle pool. First launch on a
201
212
  physical iPhone can need the one-time taps named by the remedy.
@@ -898,10 +909,12 @@ discovered, not enumerated.
898
909
 
899
910
  EXIT 0 MEANS THE QUERY SUCCEEDED, whether or not records matched. A clean
900
911
  \`stim logs --errors\` check requires exit code 0 AND no matching errors in
901
- captured logs. An empty result does not prove launch or log capture succeeded;
902
- a workspace with no log directory also returns an empty result.
912
+ captured logs. A workspace that has never produced a timeline refuses with
913
+ STIM_NO_PROJECT instead of passing with an empty result. In a monorepo the
914
+ refusal names the nearest registered descendant app with logs, when there is one.
903
915
 
904
- For zero matches: STDOUT IS EMPTY, exit code 0, and
916
+ Once a timeline file exists, zero matches after filtering means STDOUT IS EMPTY,
917
+ exit code 0, and
905
918
  one dim note on STDERR reading \`No matching log records in <logs dir>\`
906
919
  (human mode only -- \`--json\` prints nothing at all, on either stream).
907
920
  The only exit-1 paths are a malformed query and no project.
@@ -1404,14 +1417,13 @@ code, never on the message.`,
1404
1417
  \`worktree warm\` reports it for the repository-wide warm claim under
1405
1418
  ~/.stim/warm-locks on both paths, including a \`--refresh\` that spawned its
1406
1419
  install and was killed before recording which process: nothing was refreshed
1407
- and nothing was copied. One case is NOT this code for a plain warm: a
1408
- STIM_HOME (or a warm-locks path under it) that is a file rather than a
1409
- directory. No claim can be stored there at all, which is a filesystem state
1410
- that predates claims, so plain \`warm\` degrades to the unsynchronised copy it
1411
- performed before them and \`--refresh\` still refuses.`
1420
+ and nothing was copied. A STIM_HOME or warm-locks ancestor that is a file
1421
+ also refuses. The message names that blocking path and prints a shell-quoted
1422
+ move-aside command. Inspect it first: the file may contain unrelated data.
1423
+ An existing backup prompts before overwriting; preserve both files.`
1412
1424
  },
1413
1425
  STIM_CLAIM_UNAVAILABLE: {
1414
- summary: "this process has no recordable identity, so no build lock or build slot can be taken at all",
1426
+ summary: "a process identity or warm claim store is unavailable, so the protected operation refuses",
1415
1427
  body: () => `STIM_CLAIM_UNAVAILABLE
1416
1428
  Every ownership claim records the holder's process identity, captured through
1417
1429
  the \`unique-pid\` native module. This code is that capture failing: no
@@ -1423,16 +1435,15 @@ code, never on the message.`,
1423
1435
  the same fingerprint while each believed it was alone. Reinstall Stim so the
1424
1436
  module for this platform is present, then run the command again. Nothing was
1425
1437
  built, installed or removed.
1426
- \`worktree warm --refresh\` refuses for the same reason, because it writes to
1427
- the source checkout. Plain \`worktree warm\` does NOT: it prints one dim
1428
- \`lock unavailable (...)\` line and copies unsynchronised. A copy only
1429
- reads, so running it with no claim is what it did before the lock existed,
1430
- while refusing it would break a warm that works today -- an unwritable
1431
- STIM_HOME included.
1432
- It still reads the claim set first, which takes no claim: a live \`--refresh\`
1433
- claim, or a claim it cannot resolve, makes even the unsynchronised copy
1434
- refuse, and the line names what it found. Only a repository nothing is
1435
- warming is copied without a claim.`
1438
+ Both plain \`worktree warm\` and \`worktree warm --refresh\` refuse before
1439
+ copying for the same reason. A copy without a claim would be invisible to a
1440
+ refresh starting after it, allowing the source dependencies to change while
1441
+ they are read.
1442
+ Warm also reports this code for EACCES, EPERM, EROFS and ENOENT while taking a claim.
1443
+ The message names the claim path and original filesystem error. Restore write
1444
+ access to the existing claim store, checking parent permissions, symlink
1445
+ targets, mount access and sandbox rules, then retry. Do not switch STIM_HOME to evade a claim:
1446
+ concurrent runs must coordinate through the same store.`
1436
1447
  },
1437
1448
  STIM_INSTALL_FAILED: {
1438
1449
  summary: "simctl, adb, or devicectl refused the artifact; the one signer-conflict retry",
@@ -1717,6 +1728,20 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
1717
1728
  normally live under ~/.android/avd, and a booted AVD can use several GB. A
1718
1729
  boot whose emulator process exited is also reported at once rather than after
1719
1730
  the full cold-boot timeout.
1731
+ Before a local Android emulator boot, a memory phase line reports observed
1732
+ warning or critical macOS host memory pressure. If the initial boot wait
1733
+ times out under that pressure and the process this run started is still
1734
+ alive, Stim retries the WAIT once for up to 240 seconds more on the same
1735
+ serial; it never starts a second emulator. New-device preparation normally
1736
+ waits 120 seconds first; the later boot check waits 240 seconds. There is
1737
+ no extra wait for normal or unavailable pressure, a process that exited,
1738
+ or a process whose liveness this run cannot check. adb probes are bounded;
1739
+ final diagnostic queries share a separate budget of up to five seconds.
1740
+ A timeout remedy reports observed pressure and the running owned-device
1741
+ count when available. Device count alone does not establish memory pressure
1742
+ or trigger the extra wait. Stop an unneeded device with \`stim stop\` only
1743
+ in a workspace you own, then retry \`stim android\`; ask before closing
1744
+ other apps or devices. Specific emulator log errors retain their remedies.
1720
1745
 
1721
1746
  "this project's sim is X, but --device-type asked for Y"
1722
1747
  The project already owns a simulator of a different model, and Stim will
@@ -1984,7 +2009,9 @@ captured" (in metro.ndjson, bare RN)
1984
2009
  with no package.json above it, or one whose nearest package.json does not
1985
2010
  parse or depends on neither react-native nor expo, so the directory is not
1986
2011
  an app (the refusal names that package.json and says which of the two it
1987
- is; \`doctor\` reports the same directory as a finding), an
2012
+ is; \`doctor\` reports the same directory as a finding), a \`logs\` query in
2013
+ a workspace that has never produced a log timeline (the refusal names the
2014
+ nearest registered descendant app with logs when one exists), an
1988
2015
  android/app/build.gradle that declares product flavors with
1989
2016
  no variant selected (the refusal names the debug variants), or a
1990
2017
  \`--device-type\`, \`--runtime\` or \`--system-image\` name that is BLANK or
@@ -2142,24 +2169,14 @@ not on any remote" (worktree remove)
2142
2169
  which is usually the repository root, so every app of it reads the same one.`
2143
2170
  },
2144
2171
  warm: {
2145
- summary: "two warm refusals whose text is incomplete, known and not fixed",
2146
- body: () => `"Could not warm this worktree: EACCES: permission denied, mkdir
2147
- '<home>/warm-locks/<name>.lock'" (worktree warm --refresh)
2148
- A STIM_HOME that \`--refresh\` cannot write. The refusal itself is right -- it
2149
- writes to the source checkout, so it will not run without a claim -- but it
2150
- carries no \`failed: <CODE>\` line, because EACCES is not a Stim code, and no
2151
- fix line. Make STIM_HOME writable, or set STIM_HOME to somewhere writable,
2152
- then run it again. A plain warm degrades in this state rather than refusing.
2153
-
2154
- "... the claim path is a file, not a claim directory", with a \`rm -rf\` that
2155
- changes nothing (worktree warm --refresh)
2156
- When \`$STIM_HOME/warm-locks\` or STIM_HOME itself is a regular FILE, the
2157
- refusal names \`warm-locks/<name>.lock\` -- a path that cannot exist under a
2158
- file -- so running the printed removal does nothing and the next run refuses
2159
- identically. Remove the file that is in the way and run it again. A plain
2160
- warm copies unsynchronised in this state.
2161
-
2162
- Both are documented rather than fixed: appandflow/stim#696.`
2172
+ summary: "worktree warm claim storage refusals and recovery",
2173
+ body: () => `Both plain warm and --refresh require an ownership claim.
2174
+ Permission-denied or read-only claim storage reports STIM_CLAIM_UNAVAILABLE
2175
+ and names the path. Restore access to the existing claim store and retry.
2176
+ A non-directory claim ancestor reports STIM_CLAIM_REFUSED and names the
2177
+ blocking file. Inspect it and use the printed move-aside command to preserve
2178
+ its contents before retrying. See guide errors STIM_CLAIM_UNAVAILABLE and
2179
+ guide errors STIM_CLAIM_REFUSED for the recovery details.`
2163
2180
  },
2164
2181
  carry: {
2165
2182
  summary: "worktree warm copy results, lockfile mismatches, and remedies",
@@ -2340,6 +2357,7 @@ a seed belongs to this workflow.
2340
2357
  # For a clean check, require exit 0 AND no matching errors.
2341
2358
  # Human mode prints "No matching log records" on stderr for zero matches.
2342
2359
  # Exit 0 alone means the query succeeded, even when it printed errors.
2360
+ # A workspace with no captured timeline refuses with STIM_NO_PROJECT.
2343
2361
  stim logs --errors
2344
2362
 
2345
2363
  # 5. Edit the JS. Fast Refresh applies it; no Stim command is involved.
@@ -2435,6 +2453,12 @@ ANDROID EMULATOR RESTARTS
2435
2453
  Rerun \`stim android\` with the same build options in that workspace to restore Metro
2436
2454
  forwarding, then reopen agent-device on the serial that run reports.
2437
2455
  Other workspaces' simulators and automation sessions remain theirs.
2456
+ A local emulator boot reports observed warning or critical macOS memory
2457
+ pressure before starting. A timeout under elevated pressure gets one
2458
+ additional wait of up to 240 seconds only while the process this run
2459
+ started is alive. Stim keeps waiting on the same emulator; it never
2460
+ launches a duplicate. See \`stim guide errors STIM_NO_DEVICE\` for the
2461
+ wait windows, diagnostics, and recovery steps.
2438
2462
 
2439
2463
  DESTRUCTIVE COMMANDS -- ask the user first
2440
2464
  gc --delete deletes orphaned stim-* devices, tens of GB
@@ -2707,9 +2731,11 @@ result as proof instead of requiring an unrelated screenshot.`
2707
2731
 
2708
2732
  \`--refresh\` always prints a \`lock\` line, then its own facts, one per
2709
2733
  step, before those. A plain warm prints the \`lock\` line only when its copy
2710
- actually waited for another warm:
2734
+ actually waited for another warm. A current refresh reports
2735
+ \`lock acquired shared (seed current)\`; a refresh needing changes
2736
+ reports \`acquired exclusive\` with the reason from its initial check:
2711
2737
 
2712
- lock acquired (waited 12s for stim worktree warm --refresh pid 41233) -- stim guide lifecycle options
2738
+ lock acquired exclusive (fast-forward 2 commits) (waited 12s for stim worktree warm --refresh pid 41233) -- stim guide lifecycle options
2713
2739
  checkout janic/wip 2 commits behind origin/janic/wip -> fast-forwarded to 4b81e0c
2714
2740
  not the default branch (main); worktrees seeded from this copy
2715
2741
  carry janic/wip's dependencies
@@ -3129,6 +3155,20 @@ WHAT MAKES THE CACHE ACTUALLY HIT: .FINGERPRINTIGNORE
3129
3155
  Never ignore a real native input -- a Podfile, a gradle file, the app config
3130
3156
  -- to force a hit: that trades a slow build for a wrong one.
3131
3157
 
3158
+
3159
+ React Native Test App can generate checkout-specific Android output under
3160
+ node_modules/react-native-test-app/android/support/build. If fingerprint
3161
+ differences point only there, add these project-specific entries:
3162
+
3163
+ node_modules/react-native-test-app/android/support/build
3164
+ node_modules/react-native-test-app/android/support/build/**/*
3165
+
3166
+ Put them in the app root's .fingerprintignore and use the path as it appears
3167
+ in the fingerprint sources; a hoisted or linked dependency may differ.
3168
+ Keep android/support/build.gradle and native sources included. Confirm equal
3169
+ fingerprints across built worktrees, and confirm a real native input edit
3170
+ still changes the hash. These exclusions are not Stim defaults.
3171
+
3132
3172
  \`stim doctor\` measures this directly rather than reading the file: it
3133
3173
  fingerprints HEAD in a temporary clean worktree, compares, and reports a
3134
3174
  mismatch naming the differing sources. Untracked, non-gitignored files under
@@ -3274,8 +3314,9 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
3274
3314
  Running it in the source checkout refuses.
3275
3315
 
3276
3316
  \`--refresh\` WRITES TO THE SOURCE CHECKOUT before the copy, which is why it
3277
- is opt-in: it fetches, fast-forwards whatever branch is checked out there to
3278
- its \`@{upstream}\`, and installs what the new commits moved. It refuses a
3317
+ is opt-in: it checks the upstream, fetches changes when needed, and fast-forwards
3318
+ whatever branch is checked out there to its \`@{upstream}\`, and installs
3319
+ what the new commits moved. It refuses a
3279
3320
  source checkout it cannot move -- uncommitted changes to tracked files or a
3280
3321
  rebase or merge in progress (STIM_MAIN_DIRTY), a detached HEAD
3281
3322
  (STIM_MAIN_DETACHED), or a branch that is both ahead and behind
@@ -3309,9 +3350,15 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
3309
3350
  writes no failure anywhere -- is recovered the same way a failed one is.
3310
3351
 
3311
3352
  One lock per repository serialises this, whether or not you pass the flag:
3312
- \`--refresh\` holds it exclusively, and every copy holds it shared, so a copy
3313
- can never read a node_modules a refresh is rewriting. Two plain warms of the
3314
- same repository run together. The lock is keyed on the repository root, so
3353
+ \`--refresh\` first checks under a shared claim. It uses \`git ls-remote\`
3354
+ to compare the upstream's advertised commit with the local tracking ref without
3355
+ updating Git refs or FETCH_HEAD. When the checkout, dependencies and Pods are
3356
+ current, it keeps that shared claim through the copy, overlapping other copies.
3357
+ A changed or unconfirmed upstream, fast-forward, dependency install or Pods
3358
+ install requires an exclusive claim. It releases shared before waiting for
3359
+ exclusive, then checks the checkout again before fetching or writing. Every
3360
+ copy holds shared, so no copy reads a node_modules a refresh is rewriting.
3361
+ The lock is keyed on the repository root, so
3315
3362
  two apps of one monorepo share it. It is the same ownership claim the build
3316
3363
  locks take: the holder's process IDENTITY decides, so a holder that dies frees
3317
3364
  it, a recycled pid cannot keep it, and a refresh whose install runs in a
@@ -3319,20 +3366,13 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
3319
3366
  holder every 30s and gives up with STIM_LOCK_TIMEOUT; a claim Stim cannot
3320
3367
  resolve refuses with STIM_CLAIM_REFUSED and names the removal rather than
3321
3368
  waiting on it or removing it.
3322
- A plain warm that cannot record a claim at all -- an unwritable STIM_HOME, a
3323
- STIM_HOME on a read-only mount or under a dangling symlink, a STIM_HOME that
3324
- is a file, or no \`unique-pid\` build for this platform
3325
- (STIM_CLAIM_UNAVAILABLE) -- says so in one dim line and copies without it,
3326
- exactly as it did before the lock existed, because a copy only reads.
3327
- \`--refresh\` refuses instead, because it writes. Before that unsynchronised
3328
- copy starts, warm still READS the claim set, which needs no claim of its own:
3329
- if a refresh holds this repository, or a claim in it cannot be resolved, the
3330
- copy refuses rather than reading a tree that is being rewritten. That read is
3331
- not a lock, so a refresh that starts after it is not covered; it closes the
3332
- window in which one is already installing. Closing the rest needs a claim,
3333
- which is the one thing that state cannot record, so the residual is
3334
- documented rather than fixed (appandflow/stim#696), as is the
3335
- \`acquired (waited 0s ...)\` a contended-but-fast wait prints.
3369
+ Both plain warm and --refresh refuse before copying when no claim can be
3370
+ recorded. Missing process identity, denied write access and read-only storage
3371
+ report STIM_CLAIM_UNAVAILABLE with recovery instructions. Restore access to the
3372
+ same claim store before retrying; choosing a different STIM_HOME would hide
3373
+ concurrent warm operations. A non-directory claim path reports
3374
+ STIM_CLAIM_REFUSED and names the blocking file with a move-aside command that
3375
+ preserves its contents. Sub-second waits omit the elapsed-time suffix.
3336
3376
 
3337
3377
  Wait for warm to exit successfully (exit code 0) before running start,
3338
3378
  ios, android, or a dependency install in that worktree. If a shell tool
@@ -3814,6 +3854,16 @@ Those are the only two commands that delete. \`stim stop\` shuts a device
3814
3854
  DOWN and leaves it assigned, which is what makes returning to a branch cost a
3815
3855
  boot rather than a create, a provision and a reinstall.
3816
3856
 
3857
+ Before shutting down, parking or deleting an owned device, Stim best-effort
3858
+ closes local agent-device sessions bound to its exact iOS UDID or live Android
3859
+ serial. It rechecks device ownership and uses agent-device's rejecting session
3860
+ target guard; sessions on other devices stay open. Physical devices are outside
3861
+ this cleanup. agent-device is optional: a missing binary skips this step, and a
3862
+ failed or timed-out list/close prints a device line on stderr while teardown
3863
+ continues. Cleanup allows at most 15 seconds of agent-device calls per device.
3864
+ A local daemon that cannot use socket transport or a CLI without the target guard
3865
+ skips cleanup with a warning; no remote daemon is used.
3866
+
3817
3867
  Neither touches $STIM_HOME/stats.json: \`gc\` never reports or trims the run
3818
3868
  counters \`stats\` prints, and there is no reset flag. Delete that one file to
3819
3869
  start the counters over. A file this version cannot read -- unparseable, or
@@ -7,24 +7,24 @@ import { a as findProjectRoot, c as projectShortcut, i as detectIsExpo, r as det
7
7
  import { i as resolveProjectMetro, r as pidExists } from "./metro-CORqXyTL.mjs";
8
8
  import { n as verifyCollectorOwnership } from "./ownership-8O073GIC.mjs";
9
9
  import { _ as launchErrorPreview, c as launchErrorReport, g as stepTimer, h as stepClock, i as formatDuration, l as phaseLine, m as shortUdid, n as appReadinessMessage, p as shortHash } from "./command-output-8wHMEde0.mjs";
10
- import { r as claimFailure } from "./ownership-claim-Bf2CAfw3.mjs";
11
- import { $ as providerDownloadPath, G as buildCacheKey, J as filesystemBuildCapability, K as describeFingerprintMiss, Q as prepareProviderDownloadDir, R as WAIT_CEILING_MS, U as takeoverLine, V as releaseBuildLock, W as waitForBuild, X as fingerprintDiffSuffix, Y as fingerprintDiffRecord, Z as fingerprintProject, at as untrackedMissLine, et as providerUploadOutcome, nt as resolveBuild, ot as untrackedNativeFiles, rt as storeBuild, tt as refingerprintAfterMutation, z as acquireBuildLock } from "./android-BqVIJoG7.mjs";
10
+ import { r as claimFailure } from "./ownership-claim-BtPtJVmq.mjs";
11
+ import { $ as providerDownloadPath, G as buildCacheKey, J as filesystemBuildCapability, K as describeFingerprintMiss, Q as prepareProviderDownloadDir, R as WAIT_CEILING_MS, U as takeoverLine, V as releaseBuildLock, W as waitForBuild, X as fingerprintDiffSuffix, Y as fingerprintDiffRecord, Z as fingerprintProject, at as untrackedMissLine, et as providerUploadOutcome, nt as resolveBuild, ot as untrackedNativeFiles, rt as storeBuild, tt as refingerprintAfterMutation, z as acquireBuildLock } from "./android-hMj83VpN.mjs";
12
12
  import { A as resolveSettings, B as artifactCachePolicy, D as remoteDeviceSettingError, F as tunnelModeSetting, H as optimizationBuildProfile, I as unknownSettingKeys, N as settingShapeErrors, O as remoteIosSetting, R as detectProviders, T as publicUrlSetting, U as resolveOptimizations, _ as iosSigningIdentitySha1SettingError, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, f as iosLanHostSetting, g as iosSigningIdentitySha1Setting, h as iosSigningIdentitySettingError, k as resolveCacheProviderConfig, m as iosSigningIdentitySetting, p as iosLanHostSettingError, r as REMOTE_DEVICE_BACKENDS, x as metroWarmupUrlSetting } from "./settings-DEJf6_kJ.mjs";
13
- import { C as uploadRemote, S as resolveRemote, _ as isEasAuthFailureText, a as POOL_SETTING_REMEDY, c as parkedMaxSetting, d as RESOLVE_TIMEOUT_MS, f as UPLOAD_TIMEOUT_MS, g as exitAfterFlush, h as easAuthNote, m as checkEasAuth, p as cacheLevel, v as loadProjectProvider, x as resolveEasCliBin } from "./teardown-ClFp1Aax.mjs";
14
- import { _ as easDeviceBuildRemedy, a as swapJsBundle, c as ensureWorkspaceStorageSafely, d as launchOutcomeRecord, f as noMetroMessage, g as warmMetro, h as sleep, l as gateShouldRetry, m as resolveMetroWithRetry, n as pickDevClientScheme, o as needsPrebuild, p as noMetroRemedy, r as schemesFromInfoPlist, s as runPrebuild, t as devClientScheme, u as isPhysicalDeviceRequest, v as isEasBuildFailure, y as resolveEasDevelopmentBuild } from "./dev-client-BjisHDB5.mjs";
15
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-3NcQnZ0X.mjs";
13
+ import { C as uploadRemote, S as resolveRemote, _ as isEasAuthFailureText, a as POOL_SETTING_REMEDY, c as parkedMaxSetting, d as RESOLVE_TIMEOUT_MS, f as UPLOAD_TIMEOUT_MS, g as exitAfterFlush, h as easAuthNote, m as checkEasAuth, p as cacheLevel, v as loadProjectProvider, x as resolveEasCliBin } from "./teardown--gESs9ck.mjs";
14
+ import { _ as easDeviceBuildRemedy, a as swapJsBundle, c as ensureWorkspaceStorageSafely, d as launchOutcomeRecord, f as noMetroMessage, g as warmMetro, h as sleep, l as gateShouldRetry, m as resolveMetroWithRetry, n as pickDevClientScheme, o as needsPrebuild, p as noMetroRemedy, r as schemesFromInfoPlist, s as runPrebuild, t as devClientScheme, u as isPhysicalDeviceRequest, v as isEasBuildFailure, y as resolveEasDevelopmentBuild } from "./dev-client-VfSZNLT4.mjs";
15
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-IBj1Towr.mjs";
16
16
  import { C as launchIosApp, E as unverifiedLaunchLines, O as verifyLaunch, T as readMetroRecords, b as isBundleProof, c as RELEASE_VERIFY_WAIT_MS, f as clearOtherUserApps, i as LAUNCH_BUNDLING, k as verifyReleaseLaunch, m as devClientUrl, n as DEFAULT_METRO_PORT, o as LAUNCH_FATAL, s as LAUNCH_UNVERIFIED, v as installIosApp, w as readCollectorRecords, y as iosAppProcess } from "./app-install-DIp9riNx.mjs";
17
17
  import { f as listIosRuntimes } from "./ios-Deh5js5V.mjs";
18
- import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-CPbLGfrB.mjs";
19
- import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-C3-R4XQr.mjs";
18
+ import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-CcBNTvM7.mjs";
19
+ import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-C4AouyNz.mjs";
20
20
  import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-BR-kwj0B.mjs";
21
- import { T as unknownIosRuntimeRefusal, b as ensureBooted, c as discoverXcodeProject, d as resolveScheme, i as buildIos, l as readBundleExecutable, m as describeDiagnostic, n as COMPILATION_CACHE_UNAVAILABLE, o as compilationCacheActivityLine, t as COMPILATION_CACHE_NOT_RUN, u as readBundleId, v as checkDeviceCapacity, w as unknownIosDeviceTypeRefusal, x as ensureOwnedDevice, y as clearIosAdoptionPending } from "./xcode-D7sAp-Zy.mjs";
22
- import { a as ensureMetroReachable, b as ownedSessionName, c as remoteIosDeps, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, w as gateMetroOrigin } from "./device-remote-AkYCKS8U.mjs";
23
- import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-cci0xvmC.mjs";
21
+ import { E as unknownIosRuntimeRefusal, S as ensureOwnedDevice, T as unknownIosDeviceTypeRefusal, b as clearIosAdoptionPending, c as discoverXcodeProject, d as resolveScheme, i as buildIos, l as readBundleExecutable, m as describeDiagnostic, n as COMPILATION_CACHE_UNAVAILABLE, o as compilationCacheActivityLine, t as COMPILATION_CACHE_NOT_RUN, u as readBundleId, x as ensureBooted, y as checkDeviceCapacity } from "./xcode-xnxyvJkD.mjs";
22
+ import { a as ensureMetroReachable, b as ownedSessionName, c as remoteIosDeps, l as resolveRemoteContext, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, w as gateMetroOrigin } from "./device-remote-DAA0Zm6Z.mjs";
23
+ import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-CZklomj6.mjs";
24
24
  import { t as spawnEntry } from "./spawn-entry-nCE6m770.mjs";
25
- import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-DHC31rXA.mjs";
25
+ import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-DwhNBFDU.mjs";
26
26
  import { a as iosDeviceProcess, c as listIosDevices, d as verifyIosDeviceReleaseLaunch, i as installIosDeviceApp, l as localNetworkPending, n as LAUNCH_PROBE_TIMEOUT_MS, o as iosPoolCandidates, r as awaitIosDeviceLaunch, s as iosPoolNoCandidatesRefusal, t as DEVICECTL_INSTALL_TIMEOUT_MS, u as resolveIosPhysicalDevice } from "./ios-device-CWOM_S44.mjs";
27
- import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-Spz8ozgo.mjs";
27
+ import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-0Yt0Inly.mjs";
28
28
  import { existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
29
29
  import { InvalidArgumentError } from "commander";
30
30
  import { X509Certificate } from "node:crypto";
@@ -1,10 +1,12 @@
1
- import { V as validateDeviceSlot } from "./config-CcefMY2Q.mjs";
1
+ import { V as validateDeviceSlot, g as loadConfig, h as isPathPrefix } from "./config-CcefMY2Q.mjs";
2
2
  import { n as SOURCES, t as LEVELS } from "./ndjson-BZwI1NBv.mjs";
3
3
  import { D as workspaceLogsDir, p as readWorkspaceState } from "./state-B3XA2wp2.mjs";
4
4
  import { a as findProjectRoot } from "./project-fKmuIaMI.mjs";
5
5
  import { _ as launchErrorPreview } from "./command-output-8wHMEde0.mjs";
6
- import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-DHC31rXA.mjs";
7
- import { a as followLogs, i as fileSizes, n as buildCriteria, o as parseSince, r as compileGrep, s as queryLogs } from "./logs-query-R-Cqc6Qv.mjs";
6
+ import { i as captureWorkspaceCrashes, t as errorDiagnostics } from "./error-diagnostics-DwhNBFDU.mjs";
7
+ import { a as followLogs, c as queryLogs, i as fileSizes, n as buildCriteria, o as logFiles, r as compileGrep, s as parseSince } from "./logs-query-Cdp5aaCH.mjs";
8
+ import { realpathSync } from "node:fs";
9
+ import { relative, sep } from "node:path";
8
10
  import chalk from "chalk";
9
11
  //#region src/commands/logs.ts
10
12
  const LEVEL_WIDTH = 5;
@@ -61,6 +63,28 @@ function validateLevel(level) {
61
63
  return { error: `Invalid --level value ${JSON.stringify(level)}. Use one of: ${LEVELS.join(", ")}.` };
62
64
  }
63
65
  const ERRORS_PRINT_CAP = 20;
66
+ function nearestRegisteredLogsProject(root, candidates) {
67
+ return candidates.filter((candidate) => candidate !== root && isPathPrefix(root, candidate)).toSorted((a, b) => {
68
+ const depth = (path) => relative(root, path).split(sep).length;
69
+ return depth(a) - depth(b) || a.length - b.length || a.localeCompare(b);
70
+ })[0] ?? null;
71
+ }
72
+ function registeredDescendantWithLogs(root) {
73
+ const candidates = Object.keys(loadConfig()?.projects ?? {}).flatMap((path) => {
74
+ try {
75
+ const canonical = realpathSync(path);
76
+ return logFiles(workspaceLogsDir(canonical)).length > 0 ? [canonical] : [];
77
+ } catch {
78
+ return [];
79
+ }
80
+ });
81
+ return nearestRegisteredLogsProject(root, [...new Set(candidates)]);
82
+ }
83
+ function requireLogsWorkspace(root, dir) {
84
+ if (logFiles(dir).length > 0) return;
85
+ const descendant = registeredDescendantWithLogs(root);
86
+ fail(`STIM_NO_PROJECT: No Stim workspace has run in ${root}.${descendant ? ` The nearest registered app with logs is ${descendant}; run this command from there.` : " Run `stim start`, `stim ios`, or `stim android` in the app first."}`);
87
+ }
64
88
  const LEVEL_COLOURS = {
65
89
  debug: chalk.dim,
66
90
  info: chalk.reset,
@@ -69,7 +93,7 @@ const LEVEL_COLOURS = {
69
93
  fatal: chalk.bgRed
70
94
  };
71
95
  function logsCommand(program) {
72
- program.command("logs").description("Query this workspace's merged NDJSON log timeline (bundler, client, device, build). Prints and exits; nothing matching is a successful, empty result. Use --follow to stream.").option("--slot <name>", "Only records attributed to this device slot", validateDeviceSlot).option("--source <s...>", "Only these sources: metro, client, device, build, or all").option("--level <l>", `Minimum level: ${LEVELS.join(", ")}`).option("--since <d>", "Only records newer than this, e.g. 30s, 5m, 2h").option("--grep <re>", "Only records whose message matches this regular expression").option("--tail <n>", "Only the last n matching records").option("--errors", "Errors and fatals since the last marker, from metro, client and build, plus confirmed native app-crash reports. Add --source device or --source all for general device errors.").option("--follow", "Keep streaming new records until interrupted").option("--json", "Emit the raw records, one per line (valid NDJSON; zero matches is zero bytes, exit 0)").action(async (opts) => {
96
+ program.command("logs").description("Query this workspace's merged NDJSON log timeline (bundler, client, device, build). Prints and exits; an existing timeline with nothing matching is a successful, empty result. Use --follow to stream.").option("--slot <name>", "Only records attributed to this device slot", validateDeviceSlot).option("--source <s...>", "Only these sources: metro, client, device, build, or all").option("--level <l>", `Minimum level: ${LEVELS.join(", ")}`).option("--since <d>", "Only records newer than this, e.g. 30s, 5m, 2h").option("--grep <re>", "Only records whose message matches this regular expression").option("--tail <n>", "Only the last n matching records").option("--errors", "Errors and fatals since the last marker, from metro, client and build, plus confirmed native app-crash reports. Add --source device or --source all for general device errors.").option("--follow", "Keep streaming new records until interrupted").option("--json", "Emit the raw records, one per line (valid NDJSON; zero matches is zero bytes, exit 0)").action(async (opts) => {
73
97
  const root = findProjectRoot(process.cwd());
74
98
  if (!root) {
75
99
  console.error(chalk.red("Not in a React Native project (no package.json found)."));
@@ -102,6 +126,7 @@ function logsCommand(program) {
102
126
  const compiled = compileGrep(opts.grep);
103
127
  if (compiled.error) fail(compiled.error);
104
128
  }
129
+ requireLogsWorkspace(root, dir);
105
130
  const query = {
106
131
  slot: opts.slot,
107
132
  dir,
@@ -287,4 +287,4 @@ function sortByTs(records) {
287
287
  });
288
288
  }
289
289
  //#endregion
290
- export { followLogs as a, readLogRecords as c, fileSizes as i, buildCriteria as n, parseSince as o, compileGrep as r, queryLogs as s, attachExpoErrorContext as t };
290
+ export { followLogs as a, queryLogs as c, fileSizes as i, readLogRecords as l, buildCriteria as n, logFiles as o, compileGrep as r, parseSince as s, attachExpoErrorContext as t };
@@ -2,7 +2,7 @@ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
2
  import { E as inspectProcessIdentity, T as captureProcessToken, u as getConfigDir } from "./config-CcefMY2Q.mjs";
3
3
  import { t as createLineReader } from "./process-output-C7IlIzd7.mjs";
4
4
  import { r as pidExists } from "./metro-CORqXyTL.mjs";
5
- import { t as withWorkspaceProcessLock } from "./workspace-process-lock-3NcQnZ0X.mjs";
5
+ import { t as withWorkspaceProcessLock } from "./workspace-process-lock-IBj1Towr.mjs";
6
6
  import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync } from "node:fs";
7
7
  import { createHash, randomUUID } from "node:crypto";
8
8
  import { basename, join, resolve, sep } from "node:path";
@@ -6,12 +6,6 @@ import { dirname, join } from "node:path";
6
6
  //#region src/ownership-claim.ts
7
7
  const CLAIM_REFUSED = "STIM_CLAIM_REFUSED";
8
8
  const CLAIM_UNAVAILABLE = "STIM_CLAIM_UNAVAILABLE";
9
- /**
10
- * The refusal reason for a claim store whose own path is occupied by a file. It names a filesystem
11
- * state that predates any claim, so a caller that only reads can tell it apart from an unresolvable
12
- * claim record and fall back to what it did before claims existed.
13
- */
14
- const CLAIM_PATH_NOT_A_DIRECTORY = "the claim path is a file, not a claim directory";
15
9
  const EXCLUSIVE_DIR = "exclusive";
16
10
  const SHARED_DIR = "shared";
17
11
  const CLAIM_SUFFIX = ".claim";
@@ -23,9 +17,9 @@ var ClaimRefusedError = class extends Error {
23
17
  claimPath;
24
18
  reason;
25
19
  removeCommand;
26
- constructor({ claimPath, root, reason, label }) {
27
- const removeCommand = claimRemoveCommand(claimPath.startsWith(root) ? claimPath : root);
28
- super(`Stim cannot tell whether the ${label} claim at ${claimPath} is still held: ${reason}. It will not remove a claim it cannot prove is dead, and it will not wait on one either. If nothing is using it, remove the claim and run the command again:\n ${removeCommand}`);
20
+ constructor({ claimPath, root, reason, label, blockingFile = false }) {
21
+ const removeCommand = blockingFile ? `mv -i ${quotedPath(claimPath)} ${quotedPath(`${claimPath}.stim-backup`)}` : claimRemoveCommand(claimPath.startsWith(root) ? claimPath : root);
22
+ super(blockingFile ? `The ${label} claim store is blocked by a non-directory path at ${claimPath}. Inspect it before moving it aside; its contents may be unrelated to Stim. Preserve it with the command below (an existing backup prompts before overwriting), then run the command again:\n ${removeCommand}` : `Stim cannot tell whether the ${label} claim at ${claimPath} is still held: ${reason}. It will not remove a claim it cannot prove is dead, and it will not wait on one either. If nothing is using it, remove the claim and run the command again:\n ${removeCommand}`);
29
23
  this.claimPath = claimPath;
30
24
  this.reason = reason;
31
25
  this.removeCommand = removeCommand;
@@ -34,9 +28,11 @@ var ClaimRefusedError = class extends Error {
34
28
  var ClaimUnavailableError = class extends Error {
35
29
  code = CLAIM_UNAVAILABLE;
36
30
  reason;
37
- constructor(reason) {
38
- super(`Stim could not record a process identity, so it cannot take an ownership claim: ${reason}.`);
31
+ remedy;
32
+ constructor(reason, { claimPath } = {}) {
33
+ super(claimPath ? `Stim could not write the ownership claim at ${claimPath}: ${reason}.` : `Stim could not record a process identity, so it cannot take an ownership claim: ${reason}.`);
39
34
  this.reason = reason;
35
+ this.remedy = claimPath ? `Restore write access to the existing claim store at ${quotedPath(claimPath)} (check parent permissions, symlink targets, mount access and sandbox rules)` : "Reinstall Stim so the unique-pid native module for this platform is present";
40
36
  }
41
37
  };
42
38
  /**
@@ -53,12 +49,7 @@ function isClaimRefusal(err) {
53
49
  function isClaimUnavailable(err) {
54
50
  return err?.code === CLAIM_UNAVAILABLE;
55
51
  }
56
- /**
57
- * The refusal a command reports for either error the claim primitive raises, and null for anything else.
58
- * Both are refusals: a claim Stim cannot resolve and a process identity it cannot record are the two
59
- * states in which it holds no claim, and running the operation a claim serializes without one gives a
60
- * competing run no protection at all.
61
- */
52
+ /** Convert an unresolved claim, unavailable identity or inaccessible warm claim store into command recovery guidance. */
62
53
  function claimFailure(err, retryCommand) {
63
54
  const retry = retryCommand === null ? "retry the same Stim command" : `run \`${retryCommand}\` again`;
64
55
  if (isClaimRefusal(err)) return {
@@ -69,7 +60,7 @@ function claimFailure(err, retryCommand) {
69
60
  if (isClaimUnavailable(err)) return {
70
61
  code: CLAIM_UNAVAILABLE,
71
62
  message: err.message,
72
- remedy: `Reinstall Stim so the unique-pid native module for this platform is present, then ${retry}.`
63
+ remedy: `${err.remedy}, then ${retry}.`
73
64
  };
74
65
  return null;
75
66
  }
@@ -174,6 +165,29 @@ function refuse(root, claimPath, label, reason) {
174
165
  reason
175
166
  });
176
167
  }
168
+ function refuseNonDirectory(root, path, label) {
169
+ let blocking = null;
170
+ for (let level = path;; level = dirname(level)) {
171
+ try {
172
+ if (!statSync(level).isDirectory()) {
173
+ blocking = level;
174
+ break;
175
+ }
176
+ } catch (error) {
177
+ const code = error?.code;
178
+ if (code !== "ENOENT" && code !== "ENOTDIR") break;
179
+ }
180
+ if (dirname(level) === level) break;
181
+ }
182
+ if (blocking === null) throw new ClaimUnavailableError("the non-directory path could not be identified; the claim store may have changed", { claimPath: root });
183
+ throw new ClaimRefusedError({
184
+ root,
185
+ claimPath: blocking,
186
+ label,
187
+ reason: "the claim path is a file, not a claim directory",
188
+ blockingFile: true
189
+ });
190
+ }
177
191
  function names(dir) {
178
192
  try {
179
193
  return readdirSync(dir).toSorted();
@@ -405,7 +419,7 @@ function publishExclusive(root, payload, claimId, label) {
405
419
  });
406
420
  const code = err?.code;
407
421
  if (contended(err)) return null;
408
- if (code === "ENOTDIR") refuse(root, target, label, CLAIM_PATH_NOT_A_DIRECTORY);
422
+ if (code === "ENOTDIR") refuseNonDirectory(root, target, label);
409
423
  throw err;
410
424
  }
411
425
  }
@@ -439,7 +453,7 @@ function tryAcquireClaim({ root, mode, details = {}, label = "ownership" }) {
439
453
  createClaimDir(root);
440
454
  } catch (err) {
441
455
  const code = err?.code;
442
- if (code === "EEXIST" || code === "ENOTDIR") refuse(root, root, label, CLAIM_PATH_NOT_A_DIRECTORY);
456
+ if (code === "EEXIST" || code === "ENOTDIR") refuseNonDirectory(root, root, label);
443
457
  if (contended(err)) continue;
444
458
  throw err;
445
459
  }
@@ -567,4 +581,4 @@ function writeChild(handle, body) {
567
581
  }
568
582
  }
569
583
  //#endregion
570
- export { clearClaimChild as a, isClaimUnavailable as c, readClaimSet as d, releaseClaim as f, tryAcquireClaim as h, claimRemoveCommand as i, markClaimChildPending as l, settleClaim as m, ClaimRefusedError as n, clearFreeClaimSet as o, setClaimChild as p, claimFailure as r, isClaimRefusal as s, CLAIM_PATH_NOT_A_DIRECTORY as t, processGroupAlive as u };
584
+ export { clearClaimChild as a, markClaimChildPending as c, releaseClaim as d, setClaimChild as f, claimRemoveCommand as i, processGroupAlive as l, tryAcquireClaim as m, ClaimUnavailableError as n, clearFreeClaimSet as o, settleClaim as p, claimFailure as r, isClaimRefusal as s, ClaimRefusedError as t, readClaimSet as u };
@@ -2,10 +2,10 @@ import { D as sameProcessRecord, O as waitForProcessExit, f as getProject, v as
2
2
  import { T as workspaceDir, a as clearRemoteSession, c as readMetroTunnel, d as readRemoteSessionId, i as clearManagedMetroTunnel, p as readWorkspaceState } from "./state-B3XA2wp2.mjs";
3
3
  import { i as resolveProjectMetro, n as killMetroTree, r as pidExists } from "./metro-CORqXyTL.mjs";
4
4
  import { n as verifyCollectorOwnership } from "./ownership-8O073GIC.mjs";
5
- import { c as parkedMaxSetting, n as teardownOwnedIosSim, t as teardownOwnedAvd, x as resolveEasCliBin } from "./teardown-ClFp1Aax.mjs";
6
- import { l as releaseWorkspaceLeases } from "./device-lease-BJYybF-2.mjs";
7
- import { i as endRecordedSession } from "./device-remote-AkYCKS8U.mjs";
8
- import { r as stopTunnel, t as resolveSupervisorTarget } from "./ownership-BpCKiRlQ.mjs";
5
+ import { c as parkedMaxSetting, n as teardownOwnedIosSim, t as teardownOwnedAvd, x as resolveEasCliBin } from "./teardown--gESs9ck.mjs";
6
+ import { l as releaseWorkspaceLeases } from "./device-lease-CJwK7OZr.mjs";
7
+ import { i as endRecordedSession } from "./device-remote-DAA0Zm6Z.mjs";
8
+ import { r as stopTunnel, t as resolveSupervisorTarget } from "./ownership-DXcol4oU.mjs";
9
9
  import { existsSync, rmSync } from "node:fs";
10
10
  //#region src/reclaim.ts
11
11
  async function reapCollectors(root, { verify = verifyCollectorOwnership, collectors }) {
@@ -3,10 +3,10 @@ import { f as readWorkspaceLaunches } from "./state-B3XA2wp2.mjs";
3
3
  import { a as findProjectRoot } from "./project-fKmuIaMI.mjs";
4
4
  import { i as resolveProjectMetro } from "./metro-CORqXyTL.mjs";
5
5
  import { l as phaseLine } from "./command-output-8wHMEde0.mjs";
6
- import { N as resolveOwnedAvdSerial } from "./android-BqVIJoG7.mjs";
6
+ import { N as resolveOwnedAvdSerial } from "./android-hMj83VpN.mjs";
7
7
  import { u as androidAppProcess, y as iosAppProcess } from "./app-install-DIp9riNx.mjs";
8
8
  import { x as resolveOwnedIosSim } from "./ios-Deh5js5V.mjs";
9
- import { n as nativeRunCommand } from "./slot-launch-cci0xvmC.mjs";
9
+ import { n as nativeRunCommand } from "./slot-launch-CZklomj6.mjs";
10
10
  import chalk from "chalk";
11
11
  import { WebSocket } from "ws";
12
12
  //#region src/engine/reload.ts
@@ -1,7 +1,7 @@
1
1
  import { f as getProject } from "./config-CcefMY2Q.mjs";
2
2
  import { p as readWorkspaceState } from "./state-B3XA2wp2.mjs";
3
3
  import { h as deviceShellArg } from "./app-install-DIp9riNx.mjs";
4
- import { n as fileLeaseIo } from "./device-lease-BJYybF-2.mjs";
4
+ import { n as fileLeaseIo } from "./device-lease-CJwK7OZr.mjs";
5
5
  //#region src/engine/slot-launch.ts
6
6
  function launchSlotScope(root, slot = "default") {
7
7
  if (slot !== "default") return slot;
@@ -9,10 +9,10 @@ import { g as stepTimer, l as phaseLine } from "./command-output-8wHMEde0.mjs";
9
9
  import { A as resolveSettings, D as remoteDeviceSettingError, E as remoteAndroidSetting, F as tunnelModeSetting, I as unknownSettingKeys, L as PUBLIC_METRO_ENV, N as settingShapeErrors, O as remoteIosSetting, R as detectProviders, S as ngrokUrlSetting, T as publicUrlSetting, a as SETTING_SHAPE_REMEDY, b as metroTunnelSettingError, d as cacheProviderSettingError, k as resolveCacheProviderConfig, z as planMetroReach } from "./settings-DEJf6_kJ.mjs";
10
10
  import { n as expoMetroConfigPath } from "./metro-store-CDDZHtPl.mjs";
11
11
  import { o as expoSdkMajor } from "./server-expo-DizT4OMk.mjs";
12
- import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-3NcQnZ0X.mjs";
12
+ import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-IBj1Towr.mjs";
13
13
  import { t as spawnEntry } from "./spawn-entry-nCE6m770.mjs";
14
- import { s as queryLogs } from "./logs-query-R-Cqc6Qv.mjs";
15
- import { a as withManagedRemoteWorktreeLock, i as terminateChild, n as startTunnelSequence, r as stopTunnel, s as withManagedTunnelLock, t as resolveSupervisorTarget } from "./ownership-BpCKiRlQ.mjs";
14
+ import { c as queryLogs } from "./logs-query-Cdp5aaCH.mjs";
15
+ import { a as withManagedRemoteWorktreeLock, i as terminateChild, n as startTunnelSequence, r as stopTunnel, s as withManagedTunnelLock, t as resolveSupervisorTarget } from "./ownership-DXcol4oU.mjs";
16
16
  import { mkdirSync, openSync, readFileSync } from "node:fs";
17
17
  import { randomUUID } from "node:crypto";
18
18
  import { dirname } from "node:path";