stim 1.18.0 → 1.19.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.
Files changed (140) hide show
  1. package/README.md +1 -1
  2. package/dist/{activity-BxnkDZDi.mjs → activity-BSw0x84R.mjs} +3 -3
  3. package/dist/{agent-device-usage-output-CZ66YA4T.mjs → agent-device-usage-output-Bjxu_VmX.mjs} +5 -5
  4. package/dist/{android-BvwuMUJ9.mjs → android-BXc6BmEi.mjs} +507 -347
  5. package/dist/{android-DC3ZLuw0.mjs → android-BdQC6zs1.mjs} +6 -6
  6. package/dist/{android-BKA16DTf.mjs → android-BvV1gGdN.mjs} +3 -3
  7. package/dist/{android-CBwCNicO.mjs → android-DE5g_5gv.mjs} +2 -2
  8. package/dist/{android-cas-BBFyr9CA.mjs → android-cas-C87geAg-.mjs} +3 -3
  9. package/dist/android-cas-compiler.mjs +1 -1
  10. package/dist/{api-D0VtFhqk.mjs → api-DIf_s86s.mjs} +5 -7
  11. package/dist/api-run.mjs +8 -8
  12. package/dist/api.d.mts +8 -2
  13. package/dist/api.mjs +1 -1
  14. package/dist/{app-install-D-PUENug.mjs → app-install-CFI4ptUL.mjs} +33 -13
  15. package/dist/{web-DTU0uiWj.mjs → browser-web-CDhqQxhv.mjs} +134 -172
  16. package/dist/{budget-DIhL2BKx.mjs → budget-Dz-kyXLv.mjs} +15 -202
  17. package/dist/{build-facts-DcLv2HSd.d.mts → build-facts-B87vo-Im.d.mts} +32 -1
  18. package/dist/{cache-manifest-BI7ozfmH.mjs → cache-manifest-DiwKSyv9.mjs} +1 -1
  19. package/dist/cache-manifest.mjs +1 -1
  20. package/dist/{chrome-DJnmnS5q.mjs → chrome-BTUOo8p2.mjs} +1 -1
  21. package/dist/{cli-DNJMwADx.mjs → cli-C9Zvgbdc.mjs} +20 -20
  22. package/dist/cli.mjs +1 -1
  23. package/dist/{client-DzhapoMB.mjs → client-CuUo8Nvg.mjs} +248 -23
  24. package/dist/collector-run.d.mts +6 -0
  25. package/dist/collector-run.mjs +6 -6
  26. package/dist/{command-output-CBtzyIgF.mjs → command-output-Bt8ygHE7.mjs} +1 -1
  27. package/dist/{config-CgYMahz7.mjs → config-DC5jEtd1.mjs} +6 -2
  28. package/dist/{created-devices-DKbeWsiK.mjs → created-devices-D0s26Hx5.mjs} +2 -2
  29. package/dist/{dependency-state-xKoOypBm.mjs → dependency-state-DKaS1OM9.mjs} +2 -2
  30. package/dist/{detached-entry-BLfcgc4O.mjs → detached-entry-pB_IPfV4.mjs} +1 -1
  31. package/dist/{dev-client-CLnIH02x.mjs → dev-client-CDY_zAmD.mjs} +2 -2
  32. package/dist/{device-D7oCHGWi.mjs → device-BHw0WlHl.mjs} +8 -8
  33. package/dist/{device-capacity-EUOOYr8T.mjs → device-capacity-BoN1jQkO.mjs} +23 -12
  34. package/dist/device-host-worker.mjs +14 -14
  35. package/dist/{gradle-C6GKnunQ.mjs → device-ios-B2ruohE-.mjs} +659 -105
  36. package/dist/{device-lease-Co-EwifR.mjs → device-lease-Cu7PtQpZ.mjs} +5 -5
  37. package/dist/{device-lease-run-w1xhCqIW.mjs → device-lease-run-D38SnZtt.mjs} +4 -4
  38. package/dist/{device-pool-F5WvRPtD.mjs → device-pool-CP4rAsHx.mjs} +3 -3
  39. package/dist/{device-remote-tHbd1fKy.mjs → device-remote-B5GiUifk.mjs} +15 -16
  40. package/dist/{doctor-B9ckYUoU.mjs → doctor-PRJH94v6.mjs} +53 -29
  41. package/dist/doctor-watchman-wZhyTdp4.mjs +259 -0
  42. package/dist/{error-diagnostics-BRXOqDzG.mjs → error-diagnostics--v5HGOU0.mjs} +10 -10
  43. package/dist/{exec-DWhCZDGm.mjs → exec-i8GDPwq9.mjs} +32 -8
  44. package/dist/{gc-Dh6mXOKC.mjs → gc-CyHMcKcn.mjs} +19 -19
  45. package/dist/{guide-tm6igAaa.mjs → guide-dRaQJJk9.mjs} +409 -472
  46. package/dist/{hosted-android-Bv285t_t.mjs → hosted-android-Bs7fytj7.mjs} +3 -3
  47. package/dist/{hosted-client-C-rMtppF.mjs → hosted-client-C5G4h_OJ.mjs} +1 -1
  48. package/dist/{hosted-ios-D5mNmtj4.mjs → hosted-ios-Bik035eL.mjs} +1 -1
  49. package/dist/{hosted-logs-DN8Iz4mJ.mjs → hosted-logs-CI9Az9a4.mjs} +7 -7
  50. package/dist/{hosted-macos-B-wEjlwG.mjs → hosted-macos-DABm3ScO.mjs} +4 -4
  51. package/dist/{hosted-native-DeeOG8xZ.mjs → hosted-native-DbV2aUVw.mjs} +12 -8
  52. package/dist/{idle-shutdown-jjtxAn5C.mjs → idle-shutdown-DYiMBn34.mjs} +7 -7
  53. package/dist/{ios-B3SbOWdw.mjs → ios-BWbHFZVz.mjs} +5 -5
  54. package/dist/{ios-Bvbf0SGY.mjs → ios-DCrkgXEM.mjs} +1 -1
  55. package/dist/{ios-DNpdygiv.mjs → ios-DYUr9LGc.mjs} +7 -6
  56. package/dist/ios-ITYno9rO.mjs +2241 -0
  57. package/dist/{ios-device-vOaByMhw.mjs → ios-device-CJ_ZOGky.mjs} +3 -3
  58. package/dist/{ios-device-Bn7jWDB1.mjs → ios-device-CrW8aMb5.mjs} +1 -1
  59. package/dist/{ios-state-B2pES6Vs.mjs → ios-state-By0XuLTQ.mjs} +1 -1
  60. package/dist/{launch-verify-hskNcWkZ.mjs → launch-verify-DCveSE6d.mjs} +4 -4
  61. package/dist/{logs-1Ylc1Ri6.mjs → logs-Bao1HOMy.mjs} +10 -10
  62. package/dist/{macos-DF6C7wUU.mjs → macos-ciyBdTY5.mjs} +108 -130
  63. package/dist/macos-nIOATJmR.mjs +2 -0
  64. package/dist/macos-run.mjs +1 -1
  65. package/dist/maintenance-run.mjs +7 -7
  66. package/dist/manifest-CX0d1IkZ.mjs +148 -0
  67. package/dist/{metro-Dh8T4Ytd.mjs → metro-DI2AjPF_.mjs} +194 -41
  68. package/dist/{metro-gateway-CEUw9RMH.mjs → metro-gateway-BxpJLIwh.mjs} +2 -2
  69. package/dist/{plan-placement-CtxkCO54.mjs → miss-reason-CjQCOKqq.mjs} +180 -296
  70. package/dist/{named-ports-BFIz1Shz.mjs → named-ports-B4iWH4E-.mjs} +12 -5
  71. package/dist/{native-runtime-D_603JiC.mjs → native-runtime-BGxsbfny.mjs} +6 -6
  72. package/dist/offload-worker.d.mts +1 -29
  73. package/dist/offload-worker.mjs +9 -8
  74. package/dist/{ownership-D6Se7gg_.mjs → ownership-EB0ySdGK.mjs} +2 -2
  75. package/dist/{placement-log-BcPhRwR4.mjs → placement-log-Dxe34rJm.mjs} +7 -3
  76. package/dist/plan-placement-BVY59qa8.mjs +290 -0
  77. package/dist/{ports-BLTtfBq-.mjs → ports-ByPc0_97.mjs} +3 -3
  78. package/dist/{prebuild-juCyreaR.mjs → prebuild-BKJ3wJI1.mjs} +4 -4
  79. package/dist/{preview-D5V07Nrl.mjs → preview-BbSottmO.mjs} +16 -17
  80. package/dist/project-B5eQ1USs.mjs +612 -0
  81. package/dist/{pull-request-u4vp7zmK.mjs → pull-request-IHNdMnG8.mjs} +1 -1
  82. package/dist/pull-requests.mjs +1 -1
  83. package/dist/react-native-ios-BMh2i25I.mjs +2 -0
  84. package/dist/react-native-ios-CSpIxexZ.mjs +2083 -0
  85. package/dist/{recordings-BAWltsVt.mjs → recordings-Bv8McZN4.mjs} +1 -1
  86. package/dist/{reload-DvyWzVjJ.mjs → reload-rAPdqeRR.mjs} +13 -14
  87. package/dist/{remote-cache-BGg7aGIZ.mjs → remote-cache-N3hAEaAL.mjs} +4 -4
  88. package/dist/{run-vhtDgpHO.mjs → run-lAkle1-c.mjs} +2 -2
  89. package/dist/{server-bare-B9E7S1aR.mjs → server-bare-CkIjnegq.mjs} +3 -3
  90. package/dist/server-expo-DGsdUGX2.mjs +2 -0
  91. package/dist/{server-expo-DoBHhuzK.mjs → server-expo-n3tUi3Em.mjs} +3 -3
  92. package/dist/{settings-Byp2AQ_E.mjs → settings-2am7TSxp.mjs} +5 -6
  93. package/dist/{settings-CQyMElEP.mjs → settings-CxgngUZk.mjs} +767 -15
  94. package/dist/settings.schema.json +72 -6
  95. package/dist/{simslim-EHBQ2R4G.mjs → simslim-D9LkJxIO.mjs} +5 -5
  96. package/dist/{slot-launch-C1nqh4mu.mjs → slot-launch-HV_KtPIw.mjs} +6 -6
  97. package/dist/{stage-g_WqWeaE.mjs → stage-BgaZJVZY.mjs} +1 -1
  98. package/dist/{start-NTc1Ifqs.mjs → start-D8NbxNBb.mjs} +1 -1
  99. package/dist/{start-D-IeOyoK.mjs → start-DtxthMfI.mjs} +29 -22
  100. package/dist/{state-BG-aAk4k.mjs → state-D2KtnALG.mjs} +2 -2
  101. package/dist/{state-xnqpx3AD.mjs → state-Tp4uImDS.mjs} +4 -2
  102. package/dist/{stats-DY6ekz8F.mjs → stats-8EJ5ivFT.mjs} +6 -6
  103. package/dist/{status-DCjZeE-K.mjs → status-BOyp0CUl.mjs} +25 -27
  104. package/dist/{stim-desktop-Behws_fi.mjs → stim-desktop-C65jk_q2.mjs} +1 -1
  105. package/dist/{stim-installations-aR_WsNOA.mjs → stim-installations-DbmUjsLv.mjs} +1 -1
  106. package/dist/stop-D0UIpZuh.mjs +72 -0
  107. package/dist/{stop-DIJtD2GL.mjs → stop-DRipAg-e.mjs} +2 -2
  108. package/dist/{stop-BTjs3xbc.mjs → stop-zDlknFoz.mjs} +78 -31
  109. package/dist/supervisor-run.mjs +14 -14
  110. package/dist/{support-BaayeYCf.mjs → support-CNqYkV0y.mjs} +7 -7
  111. package/dist/{support-Bwvbrq5-.mjs → support-DsNaFg6D.mjs} +5 -5
  112. package/dist/swiftpm-macos-aJzPAj1t.mjs +119 -0
  113. package/dist/{toolchain-Bnyd_K3A.mjs → toolchain-C3xSoyUl.mjs} +27 -270
  114. package/dist/{trigger-CJMhwXe8.mjs → trigger-CAhmG-4s.mjs} +3 -3
  115. package/dist/trigger-CoalsMTV.mjs +2 -0
  116. package/dist/{warm-progress-CjB-MP6H.mjs → warm-progress-pFLB2e6P.mjs} +133 -36
  117. package/dist/{status-Dcr0Qexd.mjs → watchman-BL1IdOtq.mjs} +75 -7
  118. package/dist/web-DFpFeZu5.mjs +2 -0
  119. package/dist/web-DbbrPUn0.mjs +127 -0
  120. package/dist/web-run.mjs +7 -7
  121. package/dist/{workspace-state-C59dqG-Z.mjs → workspace-state-CR9X86xJ.mjs} +1 -1
  122. package/dist/{workspaces-xXItD8Dj.mjs → workspaces-Djb2gfi9.mjs} +102 -18
  123. package/dist/{worktree-BSYlofkq.mjs → worktree-BL4M1rhB.mjs} +45 -42
  124. package/dist/{worktree-BJfnU6r5.mjs → worktree-DV-A0LNL.mjs} +1 -1
  125. package/package.json +5 -5
  126. package/shim/bundle-response.cjs +2 -1
  127. package/shim/bundle-response.d.cts +1 -1
  128. package/shim/expo-metro-config.cjs +1 -1
  129. package/dist/device-ios-6MewKKnc.mjs +0 -412
  130. package/dist/guide-status-Bhf9SJXc.mjs +0 -125
  131. package/dist/ios-CPdkoKaa.mjs +0 -3953
  132. package/dist/macos-Ck7OBMNY.mjs +0 -2
  133. package/dist/native-run-B06FkmZx.mjs +0 -158
  134. package/dist/project-C3ChRLZy.mjs +0 -212
  135. package/dist/projects-DD7dBTCj.mjs +0 -92
  136. package/dist/server-expo-Db9HBUoa.mjs +0 -2
  137. package/dist/stop-BGhKMOuH.mjs +0 -48
  138. package/dist/trigger-DWAq9hkw.mjs +0 -2
  139. package/dist/web-B6_bFDn7.mjs +0 -2
  140. package/dist/worktree-CsKYexJM.mjs +0 -753
@@ -1,153 +1,18 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
2
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
3
- import { a as formatElapsed, l as phaseLine } from "./command-output-CBtzyIgF.mjs";
4
- import { _ as loadConfig$1 } from "./config-CgYMahz7.mjs";
5
- import { h as resolvePackageJson } from "./project-C3ChRLZy.mjs";
6
- import { _ as workspaceDerivedData, f as sharedCcache$1, p as sharedCompilationCache$1, x as workspaceLogsDir$1 } from "./workspace-state-C59dqG-Z.mjs";
7
- import { r as register } from "./cache-manifest-BI7ozfmH.mjs";
8
- import { o as machineNumber } from "./budget-DIhL2BKx.mjs";
3
+ import { a as formatElapsed, l as phaseLine } from "./command-output-Bt8ygHE7.mjs";
4
+ import { _ as workspaceDerivedData } from "./workspace-state-CR9X86xJ.mjs";
5
+ import { Ot as resolveOptimizations } from "./settings-CxgngUZk.mjs";
9
6
  import { a as spawnDeclared } from "./spawn-claims-Kqiifsk2.mjs";
10
- import { o as androidHome } from "./android-DC3ZLuw0.mjs";
11
- import { Q as resolveOptimizations } from "./settings-CQyMElEP.mjs";
12
- import { t as cleanLine } from "./server-expo-DoBHhuzK.mjs";
7
+ import { o as androidHome } from "./android-BdQC6zs1.mjs";
8
+ import { t as cleanLine } from "./server-expo-n3tUi3Em.mjs";
13
9
  import { createRequire } from "node:module";
14
10
  import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
15
11
  import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
16
12
  import { stimBuildDigest } from "@stim-cli/core/state";
17
13
  import { fileURLToPath } from "node:url";
18
14
  import { homedir } from "node:os";
19
- import chalk from "chalk";
20
15
  import { createHash } from "node:crypto";
21
- const CCACHE_SLOPPINESS = "pch_defines,time_macros";
22
- const STATS_LOG_FILE = "ccache-stats.log";
23
- const CCACHE_UNAVAILABLE = {
24
- status: "unavailable",
25
- hits: null,
26
- misses: null,
27
- hitRatePercent: null
28
- };
29
- const CCACHE_NOT_RUN = {
30
- status: "not-run",
31
- hits: null,
32
- misses: null,
33
- hitRatePercent: null
34
- };
35
- function ccacheStatsLog(root) {
36
- return join(workspaceLogsDir$1(root), STATS_LOG_FILE);
37
- }
38
- function ccacheMaxSize(config = loadConfig$1(), env = process.env) {
39
- const { value, error } = machineNumber("caches.ccacheMaxGb", config, env);
40
- return error || value === void 0 ? "5G" : `${value}G`;
41
- }
42
- function ccacheEnvironment({ binary, dir, workspaceRoot, statsLog, maxSize = "5G" }) {
43
- return {
44
- CMAKE_C_COMPILER_LAUNCHER: binary,
45
- CMAKE_CXX_COMPILER_LAUNCHER: binary,
46
- CCACHE_DIR: dir,
47
- CCACHE_BASEDIR: workspaceRoot,
48
- CCACHE_NOHASHDIR: "true",
49
- CCACHE_SLOPPINESS,
50
- CCACHE_MAXSIZE: maxSize,
51
- CCACHE_STATSLOG: statsLog
52
- };
53
- }
54
- function parseCcacheBinary(output) {
55
- const first = String(output ?? "").split("\n")[0]?.trim();
56
- if (!first || !isAbsolute(first)) return null;
57
- return first;
58
- }
59
- const CMAKE_LAUNCHER = /CMAKE_(C|CXX)_COMPILER_LAUNCHER\b/;
60
- function projectCmakeLauncher(source) {
61
- if (typeof source !== "string") return null;
62
- const match = CMAKE_LAUNCHER.exec(source);
63
- return match ? `CMAKE_${match[1]}_COMPILER_LAUNCHER` : null;
64
- }
65
- const HIT_COUNTERS = /* @__PURE__ */ new Set(["direct_cache_hit", "preprocessed_cache_hit"]);
66
- function parseCcacheStatsLog(text) {
67
- if (typeof text !== "string") return null;
68
- let hits = 0;
69
- let misses = 0;
70
- for (const raw of text.split("\n")) {
71
- const line = raw.trim();
72
- if (HIT_COUNTERS.has(line)) hits += 1;
73
- else if (line === "cache_miss") misses += 1;
74
- }
75
- const total = hits + misses;
76
- if (total === 0) return null;
77
- return {
78
- status: "reported",
79
- hits,
80
- misses,
81
- hitRatePercent: Math.round(hits / total * 1e3) / 10
82
- };
83
- }
84
- function readCcacheActivity(statsLog) {
85
- let text;
86
- try {
87
- text = readFileSync(statsLog, "utf-8");
88
- } catch {
89
- return CCACHE_UNAVAILABLE;
90
- }
91
- return parseCcacheStatsLog(text) ?? CCACHE_UNAVAILABLE;
92
- }
93
- function ccacheActivityLine(activity) {
94
- if (activity.status === "reported") return `${activity.hits} hits / ${activity.misses} misses (${activity.hitRatePercent}%)`;
95
- if (activity.status === "not-run") return "not run; artifact cache supplied the app";
96
- return "unavailable; no C++ compile went through ccache";
97
- }
98
- function lookupCcache() {
99
- try {
100
- return parseCcacheBinary(getExecutor().findExecutable("ccache"));
101
- } catch {
102
- return null;
103
- }
104
- }
105
- function readOrNull$1(file) {
106
- try {
107
- return readFileSync(file, "utf-8");
108
- } catch {
109
- return null;
110
- }
111
- }
112
- function canonical(root) {
113
- try {
114
- return realpathSync(root);
115
- } catch {
116
- return root;
117
- }
118
- }
119
- function resolveCcache({ root, dir = sharedCcache$1(), lookup = lookupCcache, onNote = (line) => console.error(line) }) {
120
- const binary = lookup();
121
- if (!binary) {
122
- onNote(chalk.dim(phaseLine("cache", "ccache off (not installed; brew install ccache)")));
123
- return null;
124
- }
125
- const declared = projectCmakeLauncher(readOrNull$1(join(root, "android", "app", "build.gradle")));
126
- if (declared) {
127
- onNote(chalk.dim(phaseLine("cache", `ccache off (android/app/build.gradle sets ${declared} itself)`)));
128
- return null;
129
- }
130
- const statsLog = ccacheStatsLog(root);
131
- register({
132
- dir,
133
- name: "ccache",
134
- prune: "atomic",
135
- note: "ccache keeps itself under CCACHE_MAXSIZE, so it is emptied whole or not at all"
136
- });
137
- onNote(chalk.dim(phaseLine("cache", `ccache on (${dir})`)));
138
- return {
139
- dir,
140
- statsLog,
141
- env: ccacheEnvironment({
142
- binary,
143
- dir,
144
- workspaceRoot: canonical(root),
145
- statsLog,
146
- maxSize: ccacheMaxSize()
147
- })
148
- };
149
- }
150
- //#endregion
151
16
  //#region src/engine/bundler.ts
152
17
  const COCOAPODS_SPEC = /^ {4}cocoapods \(/m;
153
18
  function bundlerPin(root) {
@@ -308,15 +173,6 @@ function describeDiagnostic(diagnostic) {
308
173
  }
309
174
  //#endregion
310
175
  //#region src/engine/xcode.ts
311
- const IOS_DIR = "ios";
312
- const PREBUILD_REMEDY = "Generate it with `npx expo prebuild -p ios` (stim ios does this automatically for an Expo project with no ios/ directory), or commit the native project.";
313
- function buildFailure(message, remedy) {
314
- return { error: {
315
- code: "STIM_BUILD_FAILED",
316
- message,
317
- remedy
318
- } };
319
- }
320
176
  function pickXcodeProject(entries) {
321
177
  const names = (Array.isArray(entries) ? entries : []).filter((e) => typeof e === "string");
322
178
  const workspaces = names.filter((e) => e.endsWith(".xcworkspace")).toSorted();
@@ -344,22 +200,6 @@ function pickXcodeProject(entries) {
344
200
  }
345
201
  return null;
346
202
  }
347
- function discoverXcodeProject(root) {
348
- const dir = join(root, IOS_DIR);
349
- let entries;
350
- try {
351
- entries = readdirSync(dir);
352
- } catch {
353
- return buildFailure(`No ${IOS_DIR}/ directory in ${root}.`, PREBUILD_REMEDY);
354
- }
355
- const picked = pickXcodeProject(entries);
356
- if (!picked) return buildFailure(`${dir} contains no .xcworkspace and no .xcodeproj.`, PREBUILD_REMEDY);
357
- return {
358
- ...picked,
359
- dir,
360
- path: join(dir, picked.file)
361
- };
362
- }
363
203
  function parseSchemeList(text) {
364
204
  const empty = {
365
205
  name: null,
@@ -462,18 +302,6 @@ function compilationPrefixMappings(workspaceRoot, derivedDataPath) {
462
302
  if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) mappings.push(`${derived}=/^derived-data`);
463
303
  return mappings.map((mapping) => /[\s"\\]/.test(mapping) ? `"${mapping.replace(/["\\]/g, "\\$&")}"` : mapping).join(" ");
464
304
  }
465
- function ccacheEnabled(podfileProperties) {
466
- if (!podfileProperties || typeof podfileProperties !== "object") return false;
467
- return podfileProperties["apple.ccacheEnabled"] === "true";
468
- }
469
- function readPodfileProperties(root) {
470
- try {
471
- const parsed = JSON.parse(readFileSync(join(root, IOS_DIR, "Podfile.properties.json"), "utf-8"));
472
- return parsed && typeof parsed === "object" ? parsed : null;
473
- } catch {
474
- return null;
475
- }
476
- }
477
305
  const SWIFT_PREFIX_MAPPING_MIN_SWIFT = {
478
306
  major: 6,
479
307
  minor: 4
@@ -483,40 +311,12 @@ function swiftPrefixMappingSupported(version) {
483
311
  const min = SWIFT_PREFIX_MAPPING_MIN_SWIFT;
484
312
  return version.major > min.major || version.major === min.major && version.minor >= min.minor;
485
313
  }
486
- const SWIFT_CACHE_MIN_REACT_NATIVE = {
487
- major: 0,
488
- minor: 87
489
- };
490
- function reactNativeSupportsSwiftCache(version) {
491
- if (!version) return false;
492
- const min = SWIFT_CACHE_MIN_REACT_NATIVE;
493
- return version.major > min.major || version.major === min.major && version.minor >= min.minor;
494
- }
495
- function parseReactNativeVersion(packageJson) {
496
- if (!packageJson || typeof packageJson !== "object") return null;
497
- const raw = packageJson.version;
498
- const m = typeof raw === "string" ? /^(\d+)\.(\d+)\./.exec(raw) : null;
499
- if (!m || m[1] === void 0 || m[2] === void 0) return null;
500
- return {
501
- major: parseInt(m[1], 10),
502
- minor: parseInt(m[2], 10)
503
- };
504
- }
505
- function detectReactNativeVersion(root) {
506
- const file = resolvePackageJson(root, "react-native");
507
- if (!file) return null;
508
- try {
509
- return parseReactNativeVersion(JSON.parse(readFileSync(file, "utf-8")));
510
- } catch {
511
- return null;
512
- }
513
- }
514
- function compilationCacheSettings({ workspaceRoot, derivedDataPath, casPath, xcodeMajor, swiftVersion = null, reactNativeVersion = null, ccache = false, optimizations = resolveOptimizations({}, {}).ios }) {
314
+ function compilationCacheSettings({ workspaceRoot, derivedDataPath, casPath, xcodeMajor, swiftVersion = null, swiftCacheCompatible = false, ccache = false, optimizations = resolveOptimizations({}, {}).ios }) {
515
315
  if (xcodeMajor === null || xcodeMajor === void 0) return [];
516
316
  if (xcodeMajor < 26) return [];
517
317
  if (ccache) return [];
518
318
  const swiftMappable = swiftPrefixMappingSupported(swiftVersion);
519
- const auto = swiftMappable && reactNativeSupportsSwiftCache(reactNativeVersion);
319
+ const auto = swiftMappable && swiftCacheCompatible;
520
320
  const swift = optimizations.compilationCache && (optimizations.swiftCompilationCache ?? auto);
521
321
  const mappings = optimizations.prefixMapping ? compilationPrefixMappings(workspaceRoot, derivedDataPath) : "";
522
322
  return [
@@ -552,34 +352,6 @@ function parseXcodeMajor(output) {
552
352
  function detectXcodeMajor(exec = null) {
553
353
  return parseXcodeMajor((exec || getExecutor()).runQuiet("xcodebuild -version", { timeoutMs: 1e4 }));
554
354
  }
555
- function resolveCompilationCacheSettings({ root, derivedDataPath, exec = null, casPath = sharedCompilationCache$1(), optimizations = resolveOptimizations({}, {}).ios, onNote = (line) => console.error(line) }) {
556
- const xcodeMajor = detectXcodeMajor(exec);
557
- const ccache = ccacheEnabled(readPodfileProperties(root));
558
- const probe = xcodeMajor !== null && xcodeMajor >= 26 && !ccache && optimizations.compilationCache && optimizations.swiftCompilationCache !== false;
559
- const swiftVersion = probe ? detectSwiftVersion(exec) : null;
560
- const reactNativeVersion = probe ? detectReactNativeVersion(root) : null;
561
- const settings = compilationCacheSettings({
562
- workspaceRoot: root,
563
- derivedDataPath,
564
- casPath,
565
- xcodeMajor,
566
- swiftVersion,
567
- reactNativeVersion,
568
- ccache,
569
- optimizations
570
- });
571
- if (settings.length > 0 && optimizations.compilationCache) {
572
- register({
573
- dir: casPath,
574
- name: "Xcode compilation cache",
575
- prune: "atomic",
576
- note: "shared Xcode compilation cache"
577
- });
578
- const swift = settings.includes("SWIFT_ENABLE_COMPILE_CACHE=YES") ? settings.includes("SWIFT_ENABLE_PREFIX_MAPPING=YES") ? "Swift on" : "Swift on, unmapped" : swiftVersion && !swiftPrefixMappingSupported(swiftVersion) ? `Swift off, ${swiftVersion.major}.${swiftVersion.minor} < ${SWIFT_PREFIX_MAPPING_MIN_SWIFT.major}.${SWIFT_PREFIX_MAPPING_MIN_SWIFT.minor}` : swiftVersion && reactNativeVersion && !reactNativeSupportsSwiftCache(reactNativeVersion) ? `Swift off, react-native ${reactNativeVersion.major}.${reactNativeVersion.minor} < ${SWIFT_CACHE_MIN_REACT_NATIVE.major}.${SWIFT_CACHE_MIN_REACT_NATIVE.minor}` : "Swift off";
579
- onNote(chalk.dim(phaseLine("cache", `compilation cache on (CAS at ${casPath}, ${swift})`)));
580
- }
581
- return settings;
582
- }
583
355
  function xcodebuildArgs({ project, scheme, udid = null, destination = null, configuration = "Debug", sdk = "iphonesimulator", derivedDataPath, extraArgs = [], buildSettings = [] }) {
584
356
  return [
585
357
  project.flag,
@@ -782,13 +554,13 @@ function compilationCacheActivityLine(activity) {
782
554
  if (activity.status === "not-run") return "not run; artifact cache supplied the app";
783
555
  return "unavailable; Xcode did not report reliable statistics";
784
556
  }
785
- async function buildIos({ root, udid = null, logWriter, project = null, scheme = null, configuration = "Debug", sdk = "iphonesimulator", destination = null, arch = null, derivedDataPath = null, extraArgs = [], compilationCache = void 0, optimizations = resolveOptimizations({}, {}).ios, now = () => Date.now(), exec = null, heartbeatMs = HEARTBEAT_INTERVAL_MS, estimateMs = null, onHeartbeat = (line) => console.error(line), onNote = (line) => console.error(line) }) {
786
- if (!root || typeof root !== "string") throw new TypeError("buildIos requires {root}");
787
- if (!logWriter || typeof logWriter.write !== "function") throw new TypeError("buildIos requires {logWriter} with a write() method");
788
- if (!udid && !destination) throw new TypeError("buildIos requires {udid} (or an explicit {destination})");
557
+ async function buildXcode({ root, udid = null, logWriter, project, scheme = null, configuration = "Debug", sdk = "iphonesimulator", destination = null, arch = null, derivedDataPath = null, extraArgs = [], compilationCache, startedAt: clockStart, now = () => Date.now(), exec = null, heartbeatMs = HEARTBEAT_INTERVAL_MS, estimateMs = null, onHeartbeat = (line) => console.error(line) }) {
558
+ if (!root || typeof root !== "string") throw new TypeError("buildXcode requires {root}");
559
+ if (!logWriter || typeof logWriter.write !== "function") throw new TypeError("buildXcode requires {logWriter} with a write() method");
560
+ if (!udid && !destination) throw new TypeError("buildXcode requires {udid} (or an explicit {destination})");
789
561
  const executor = exec || getExecutor();
790
562
  const dd = derivedDataPath || (scheme ? join(workspaceDerivedData(root), `scheme-${createHash("sha256").update(scheme).digest("hex")}`) : workspaceDerivedData(root));
791
- const startedAt = now();
563
+ const startedAt = clockStart ?? now();
792
564
  const elapsed = () => now() - startedAt;
793
565
  const reportError = (message, remedy) => {
794
566
  logWriter.write({
@@ -799,23 +571,18 @@ async function buildIos({ root, udid = null, logWriter, project = null, scheme =
799
571
  ...remedy ? { remedy } : {}
800
572
  });
801
573
  };
802
- let target = project;
803
- if (!target) {
804
- const discovered = discoverXcodeProject(root);
805
- if (discovered.error) {
806
- reportError(discovered.error.message, discovered.error.remedy);
807
- return failedResult({
808
- code: discovered.error.code,
809
- diagnostics: [{
810
- message: discovered.error.message,
811
- remedy: discovered.error.remedy ?? void 0
812
- }],
813
- durationMs: elapsed()
814
- });
815
- }
816
- target = discovered;
574
+ if (project.error) {
575
+ reportError(project.error.message, project.error.remedy);
576
+ return failedResult({
577
+ code: project.error.code,
578
+ diagnostics: [{
579
+ message: project.error.message,
580
+ remedy: project.error.remedy ?? void 0
581
+ }],
582
+ durationMs: elapsed()
583
+ });
817
584
  }
818
- const resolvedTarget = target;
585
+ const resolvedTarget = project;
819
586
  const selected = resolveScheme(resolvedTarget, {
820
587
  exec: executor,
821
588
  scheme
@@ -832,12 +599,9 @@ async function buildIos({ root, udid = null, logWriter, project = null, scheme =
832
599
  });
833
600
  }
834
601
  const buildScheme = selected.scheme;
835
- const cacheSettings = compilationCache === void 0 ? resolveCompilationCacheSettings({
836
- root,
602
+ const cacheSettings = typeof compilationCache === "function" ? compilationCache({
837
603
  derivedDataPath: dd,
838
- exec: executor,
839
- onNote,
840
- optimizations
604
+ exec: executor
841
605
  }) : compilationCache || [];
842
606
  const buildSettings = arch ? [
843
607
  ...cacheSettings,
@@ -1515,13 +1279,6 @@ function missingPod(err) {
1515
1279
  };
1516
1280
  }
1517
1281
  //#endregion
1518
- //#region src/offload/manifest.ts
1519
- function manifestDigest(entries) {
1520
- const hash = createHash("sha256");
1521
- for (const entry of entries.toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)) hash.update(`${entry.path}\0${entry.kind}\0${entry.sha256}\n`);
1522
- return hash.digest("hex");
1523
- }
1524
- //#endregion
1525
1282
  //#region src/offload/toolchain.ts
1526
1283
  const distDir = dirname(fileURLToPath(import.meta.url));
1527
1284
  function quiet(file, args) {
@@ -1744,4 +1501,4 @@ function toolchainMismatches(target, worker) {
1744
1501
  return out;
1745
1502
  }
1746
1503
  //#endregion
1747
- export { CCACHE_NOT_RUN as A, readBundleId as C, describeDiagnostic as D, tailLines as E, resolveCcache as F, ccacheActivityLine as M, projectCmakeLauncher as N, bundlerPin as O, readCcacheActivity as P, readBundleExecutable as S, startBuildHeartbeat as T, buildIos as _, toolchainMismatches as a, detectXcodeMajor as b, DEPS_ERROR as c, readRubyVersion as d, runCaptured as f, HEARTBEAT_INTERVAL_MS as g, COMPILATION_CACHE_UNAVAILABLE as h, macosToolchain as i, CCACHE_UNAVAILABLE as j, podInstallCommand as k, podsAreStale as l, COMPILATION_CACHE_NOT_RUN as m, androidToolchain as n, workerToolchain as o, runPodInstall as p, iosToolchain as r, manifestDigest as s, androidRequirements as t, readPodState as u, ccacheEnabled as v, resolveScheme as w, discoverXcodeProject as x, compilationCacheActivityLine as y };
1504
+ export { bundlerPin as A, readBundleExecutable as C, swiftPrefixMappingSupported as D, startBuildHeartbeat as E, tailLines as O, pickXcodeProject as S, resolveScheme as T, buildXcode as _, toolchainMismatches as a, detectSwiftVersion as b, podsAreStale as c, runCaptured as d, runPodInstall as f, SWIFT_PREFIX_MAPPING_MIN_SWIFT as g, HEARTBEAT_INTERVAL_MS as h, macosToolchain as i, podInstallCommand as j, describeDiagnostic as k, readPodState as l, COMPILATION_CACHE_UNAVAILABLE as m, androidToolchain as n, workerToolchain as o, COMPILATION_CACHE_NOT_RUN as p, iosToolchain as r, DEPS_ERROR as s, androidRequirements as t, readRubyVersion as u, compilationCacheActivityLine as v, readBundleId as w, detectXcodeMajor as x, compilationCacheSettings as y };
@@ -1,6 +1,6 @@
1
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
2
  import { t as spawnEntry } from "./spawn-entry-Dcb7sDUz.mjs";
3
- import { n as windowsLauncherArgs } from "./detached-entry-BLfcgc4O.mjs";
3
+ import { n as windowsLauncherArgs } from "./detached-entry-pB_IPfV4.mjs";
4
4
  import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.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";
@@ -14,7 +14,7 @@ function triggerMaintenance(trigger, { argv = process.argv.slice(2), platform =
14
14
  "guide",
15
15
  "settings",
16
16
  "help"
17
- ].includes(argv[0] ?? "") || argv[0] === "gc" && argv.includes("--delete") || argv.some((arg) => [
17
+ ].includes(argv[0] ?? "") || argv.includes("--plan") || argv[0] === "gc" && argv.includes("--delete") || argv.some((arg) => [
18
18
  "--help",
19
19
  "-h",
20
20
  "--version",
@@ -0,0 +1,2 @@
1
+ import { t as triggerMaintenance } from "./trigger-CAhmG-4s.mjs";
2
+ export { triggerMaintenance };
@@ -1,13 +1,15 @@
1
1
  import { n as ownership_claim_exports } from "./process-identity-Biv3arCO.mjs";
2
- import { t as getExecutor } from "./exec-DWhCZDGm.mjs";
3
- import { c as gitCommonDirOnDisk } from "./worktree-CsKYexJM.mjs";
4
- import { D as discoverAgentSessions, E as attributeAgentSessions, T as agentKey, a as updateWorkspaceState, u as ensureWorkspaceStorage, v as workspaceDir, w as withDirLock } from "./workspace-state-C59dqG-Z.mjs";
5
- import { I as ownedAvdDirectory } from "./android-DC3ZLuw0.mjs";
6
- import { o as pullRequestLookups } from "./pull-request-u4vp7zmK.mjs";
7
- import { existsSync, mkdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
- import { basename, dirname, join } from "node:path";
9
- import { ENDED_AGENT_RETENTION_MS, READY_PHASE_MS, WARM_KEY, agentSessionsCacheFile, diskUsageCacheFile, pullRequestCacheFile, readAgentSessionsCache, readDiskUsage, readEndedAgentSessions, readPullRequestCache, readWarmRecord, readWorkspaceAgent, readWorkspaceState, workspaceEndedAgentsFile, workspaceEndedAgentsLock } from "@stim-cli/core/state";
2
+ import { n as debugLog, t as getExecutor } from "./exec-i8GDPwq9.mjs";
3
+ import { D as discoverAgentSessions, E as attributeAgentSessions, T as agentKey, a as updateWorkspaceState, u as ensureWorkspaceStorage, v as workspaceDir, w as withDirLock } from "./workspace-state-CR9X86xJ.mjs";
4
+ import { ct as linkedWorktreesOnDisk, rt as gitCommonDirOnDisk } from "./settings-CxgngUZk.mjs";
5
+ import { I as ownedAvdDirectory } from "./android-BdQC6zs1.mjs";
6
+ import { o as pullRequestLookups } from "./pull-request-IHNdMnG8.mjs";
7
+ import { existsSync, mkdirSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
+ import { basename, dirname, join, sep } from "node:path";
9
+ 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";
10
10
  import { homedir } from "node:os";
11
+ import { clearClaimChild, markClaimChildPending, releaseClaim, setClaimChild, tryAcquireClaim } from "@stim-cli/core/ownership-claim";
12
+ import { captureProcessIdentity } from "@stim-cli/core/process-identity";
11
13
  import { randomUUID } from "node:crypto";
12
14
  //#region src/workspace/merge-state.ts
13
15
  const FETCH_TIMEOUT_MS = 3e4;
@@ -282,6 +284,7 @@ function mergeState(path, { ref, name }, { timeoutMs = GIT_TIMEOUT_MS$1, maxComm
282
284
  const LIVE_DISK_MAX_AGE_MS = 3e5;
283
285
  const IDLE_DISK_MAX_AGE_MS = 36e5;
284
286
  const DU_TIMEOUT_MS = 12e4;
287
+ const DU_NICENESS = "19";
285
288
  const PULL_REQUEST_MAX_AGE_MS = 3e5;
286
289
  const PULL_REQUEST_CHECK_MS = 6e4;
287
290
  const GIT_TIMEOUT_MS = 5e3;
@@ -301,8 +304,11 @@ function forgetStatusMeasures(worktree, workspaces) {
301
304
  const roots = [.../* @__PURE__ */ new Set([worktree, ...workspaces])];
302
305
  const files = [pullRequestCacheFile(worktree), ...roots.flatMap((root) => [
303
306
  diskUsageCacheFile(root),
307
+ diskUsageFailureFile(root),
304
308
  diskUsageCacheFile(join(root, "node_modules")),
305
- diskUsageCacheFile(workspaceDir(root))
309
+ diskUsageFailureFile(join(root, "node_modules")),
310
+ diskUsageCacheFile(workspaceDir(root)),
311
+ diskUsageFailureFile(workspaceDir(root))
306
312
  ])];
307
313
  for (const file of files) try {
308
314
  rmSync(file, { force: true });
@@ -459,18 +465,63 @@ function applyStatusMeasures(states, worktrees) {
459
465
  if (cached && cached.branch === worktree.branch) worktree.pullRequest = cached.pullRequest;
460
466
  }
461
467
  }
462
- /** Kilobytes from `du -sk` output, or null when it printed none. */
468
+ /** Kilobytes from `du -sk` output, summed over its lines, or null when it printed none. */
463
469
  function parseDuKilobytes(output) {
464
- const kb = Number(/^(\d+)\s/.exec(output)?.[1]);
465
- return Number.isFinite(kb) ? kb : null;
470
+ const sizes = [...output.matchAll(/^(\d+)\s/gm)].map((match) => Number(match[1]));
471
+ return sizes.length ? sizes.reduce((sum, kb) => sum + kb, 0) : null;
472
+ }
473
+ /** The folders inside a checkout that another measurement owns: its linked worktrees and Stim's workspace folder. */
474
+ function nestedFolders(state) {
475
+ const common = gitCommonDirOnDisk(state.path);
476
+ return [workspaceDir(state.path), ...common ? linkedWorktreesOnDisk(common).map((entry) => entry.path) : []];
477
+ }
478
+ /** The entries to hand to `du` so it sums `root` without descending into `nested`; `[root]` when none is inside it. */
479
+ function walkTargets(root, nested) {
480
+ const top = canonicalPath(root);
481
+ const skip = new Set(nested.map(canonicalPath));
482
+ const inside = [...skip].filter((path) => path.startsWith(top + sep));
483
+ if (!inside.length) return [root];
484
+ const targets = [];
485
+ const visit = (dir) => {
486
+ let names;
487
+ try {
488
+ names = readdirSync(dir);
489
+ } catch {
490
+ targets.push(dir);
491
+ return;
492
+ }
493
+ for (const name of names) {
494
+ const path = join(dir, name);
495
+ if (skip.has(path)) continue;
496
+ if (inside.some((nestedPath) => nestedPath.startsWith(path + sep))) visit(path);
497
+ else targets.push(path);
498
+ }
499
+ };
500
+ visit(top);
501
+ return targets;
466
502
  }
467
503
  function isStale(measure, maxAgeMs, now) {
468
504
  return !measure || now - Date.parse(measure.measuredAt) >= maxAgeMs;
469
505
  }
506
+ function takeWalkClaim() {
507
+ try {
508
+ const attempt = tryAcquireClaim({
509
+ root: diskUsageWalkClaims(),
510
+ mode: "exclusive",
511
+ label: "disk usage walk"
512
+ });
513
+ if (attempt.pending) releaseClaim(attempt.pending);
514
+ return attempt.acquired ?? null;
515
+ } catch (error) {
516
+ debugLog.log("disk-walk-claim", { error: String(error?.message ?? error) });
517
+ return null;
518
+ }
519
+ }
470
520
  /**
471
521
  * Keeps the disk use, pull request and agent session caches fresh for `status --watch`, off its refresh path: one
472
522
  * agent session discovery at most every 15 seconds, which status ignores once it is over 2 minutes old, one `du -sk` at
473
- * a time, live environments first, each folder at most every 5 minutes while its environment is live and every hour otherwise, and one `gh api
523
+ * a time on the whole machine (an ownership claim; a failed walk is recorded so other watchers do not repeat it), at low
524
+ * priority, live environments first, a checkout without the linked worktrees nested in it, each folder at most every 5 minutes while its environment is live and every hour otherwise, and one `gh api
474
525
  * graphql` per repository for worktrees whose lookup is over 5 minutes old or whose branch or HEAD moved. It
475
526
  * runs git only in the repository, never in a worktree, and only for worktrees whose git state status read. It rechecks
476
527
  * a folder's cache right before measuring, so two watchers rarely measure the same folder. A session the previous
@@ -485,35 +536,77 @@ function createStatusMeasurer({ updated, now = Date.now }) {
485
536
  let checkedAt = -Infinity;
486
537
  let discovering = false;
487
538
  let discoveredAt = -Infinity;
488
- const failedAt = /* @__PURE__ */ new Map();
489
- async function du(path) {
539
+ async function du(targets, claim) {
540
+ const hold = (child) => {
541
+ if (child.pid === void 0) return;
542
+ const captured = captureProcessIdentity(child.pid);
543
+ if (!captured.ok) throw new Error(`Cannot record the du process: ${captured.reason}`);
544
+ setClaimChild(claim, {
545
+ pid: child.pid,
546
+ processToken: captured.token
547
+ });
548
+ };
490
549
  try {
491
- return parseDuKilobytes(await exec.runFileAsync("du", ["-sk", path], { timeoutMs: DU_TIMEOUT_MS }));
550
+ markClaimChildPending(claim);
551
+ return parseDuKilobytes(await exec.runFileAsync("nice", [
552
+ "-n",
553
+ DU_NICENESS,
554
+ "du",
555
+ "-sk",
556
+ ...targets
557
+ ], {
558
+ timeoutMs: DU_TIMEOUT_MS,
559
+ onSpawn: hold
560
+ }));
492
561
  } catch (error) {
493
562
  const { code, status, stdout } = error;
494
563
  if (code === "ENOENT") duMissing = true;
495
564
  return status === 1 && typeof stdout === "string" ? parseDuKilobytes(stdout) : null;
565
+ } finally {
566
+ clearClaimChild(claim);
496
567
  }
497
568
  }
569
+ function due(path, maxAgeMs) {
570
+ const failedAt = readDiskUsageFailure(path);
571
+ return isStale(readDiskUsage(path), maxAgeMs, now()) && (!failedAt || now() - Date.parse(failedAt) >= maxAgeMs);
572
+ }
498
573
  async function measure(folders) {
499
- for (const { path, maxAgeMs } of folders) {
500
- if (duMissing || !isStale(readDiskUsage(path), maxAgeMs, now())) continue;
501
- if (now() - (failedAt.get(path) ?? -Infinity) < maxAgeMs) continue;
502
- let bytes = 0;
503
- if (existsSync(path)) {
504
- const kb = await du(path);
505
- if (kb === null) {
506
- failedAt.set(path, now());
507
- continue;
508
- }
509
- bytes = kb * 1024;
510
- } else if (!basename(path).startsWith("node_modules")) continue;
511
- writeCacheFile(diskUsageCacheFile(path), {
574
+ for (const { path, maxAgeMs, nested } of folders) {
575
+ if (duMissing || !due(path, maxAgeMs)) continue;
576
+ const stamp = () => ({
512
577
  path,
513
- bytes,
514
578
  measuredAt: new Date(now()).toISOString()
515
579
  });
516
- updated();
580
+ if (!existsSync(path)) {
581
+ if (!basename(path).startsWith("node_modules")) continue;
582
+ writeCacheFile(diskUsageCacheFile(path), {
583
+ ...stamp(),
584
+ bytes: 0
585
+ });
586
+ updated();
587
+ continue;
588
+ }
589
+ const claim = takeWalkClaim();
590
+ if (!claim) return;
591
+ try {
592
+ if (!due(path, maxAgeMs)) continue;
593
+ const targets = walkTargets(path, nested?.() ?? []);
594
+ const kb = targets.length ? await du(targets, claim) : 0;
595
+ if (kb === null) {
596
+ writeCacheFile(diskUsageFailureFile(path), {
597
+ path,
598
+ failedAt: new Date(now()).toISOString()
599
+ });
600
+ continue;
601
+ }
602
+ writeCacheFile(diskUsageCacheFile(path), {
603
+ ...stamp(),
604
+ bytes: kb * 1024
605
+ });
606
+ updated();
607
+ } finally {
608
+ releaseClaim(claim);
609
+ }
517
610
  }
518
611
  }
519
612
  async function branchHead(repository, branch) {
@@ -600,13 +693,17 @@ function createStatusMeasurer({ updated, now = Date.now }) {
600
693
  ...nodeModules,
601
694
  build,
602
695
  ...deviceFolders(state).map((folder) => folder.path)
603
- ]) folders.set(path, Math.min(folders.get(path) ?? Infinity, maxAgeMs));
696
+ ]) {
697
+ const known = folders.get(path);
698
+ folders.set(path, {
699
+ path,
700
+ maxAgeMs: Math.min(known?.maxAgeMs ?? Infinity, maxAgeMs),
701
+ nested: known?.nested ?? (path === worktree ? () => nestedFolders(state) : void 0)
702
+ });
703
+ }
604
704
  }
605
705
  measuring = true;
606
- measure([...folders].map(([path, maxAgeMs]) => ({
607
- path,
608
- maxAgeMs
609
- }))).catch(() => {}).finally(() => {
706
+ measure([...folders.values()]).catch(() => {}).finally(() => {
610
707
  measuring = false;
611
708
  });
612
709
  }