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,9 +1,12 @@
1
- import { _ as loadConfig$1, f as getConfigPath$1, h as getRepoSettings, m as getProjectSettings } from "./config-CgYMahz7.mjs";
2
- import { s as gitCommonDir, y as repoRoot } from "./worktree-CsKYexJM.mjs";
3
- import { isAbsolute } from "node:path";
4
- import { isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
1
+ import { t as getExecutor } from "./exec-i8GDPwq9.mjs";
2
+ import { _ as loadConfig$1, d as getConfigDir, f as getConfigPath$1, h as getRepoSettings, m as getProjectSettings } from "./config-DC5jEtd1.mjs";
3
+ import { accessSync, chmodSync, constants, lstatSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
4
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
+ import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
5
6
  import { ANDROID_COMPILER_CACHE_CHOICES, ANDROID_PCH_CHOICES, REMOTE_DEVICE_BACKENDS, SETTINGS, SETTING_GROUPS, TUNNEL_MODES, WEB_VIEWPORTS, acceptsShape, coerceSettingText, expectedShape, isLayeredSetting, settingDefinition, settingValueError } from "@stim-cli/core/state";
6
- import { existsSync, readFileSync, realpathSync, statSync } from "fs";
7
+ import { tmpdir } from "node:os";
8
+ import { chmodSync as chmodSync$1, existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, statSync as statSync$1, utimesSync as utimesSync$1 } from "fs";
9
+ import { buildCacheRoot } from "@stim-cli/core";
7
10
  import { createHash } from "node:crypto";
8
11
  //#region src/optimizations.ts
9
12
  function compilerCacheFallbackMessage({ fallback, compilerCache, file = null }) {
@@ -102,6 +105,750 @@ function resolveMetroSharedCache(settings) {
102
105
  return optimizationBoolean(settings, "metroSharedCache");
103
106
  }
104
107
  //#endregion
108
+ //#region src/temporary.ts
109
+ function existingPath(path) {
110
+ const missing = [];
111
+ let current = resolve(path);
112
+ while (!lstatSync(current, { throwIfNoEntry: false })) {
113
+ missing.unshift(basename(current));
114
+ current = dirname(current);
115
+ }
116
+ const existing = realpathSync(current);
117
+ return {
118
+ existing,
119
+ resolved: join(existing, ...missing)
120
+ };
121
+ }
122
+ function filesystemDevice(path) {
123
+ return statSync(existingPath(path).existing).dev;
124
+ }
125
+ function outsideWorkingTree(path) {
126
+ let current = path;
127
+ while (true) {
128
+ if (lstatSync(join(current, ".git"), { throwIfNoEntry: false })) return false;
129
+ const parent = dirname(current);
130
+ if (parent === current) return true;
131
+ current = parent;
132
+ }
133
+ }
134
+ function inside(parent, path) {
135
+ const rel = relative(parent, path);
136
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
137
+ }
138
+ function temporaryRoot(near) {
139
+ const reference = existingPath(near);
140
+ const insideReference = (path) => inside(reference.resolved, path);
141
+ const override = process.env.STIM_TMPDIR ?? loadConfig$1()?.tempDir;
142
+ if (override !== void 0) {
143
+ if (typeof override !== "string" || !isAbsolute(override)) throw new Error("STIM_TMPDIR / tempDir must be an absolute directory path.");
144
+ const { existing, resolved } = existingPath(override);
145
+ if (!statSync(existing).isDirectory() || !outsideWorkingTree(existing)) throw new Error(`Temporary directory ${override} must be outside Git working trees.`);
146
+ if (insideReference(resolved)) throw new Error(`Temporary directory ${override} must not be inside ${near}.`);
147
+ accessSync(existing, constants.W_OK);
148
+ return resolved;
149
+ }
150
+ const { existing } = reference;
151
+ const cache = existingPath(buildCacheRoot()).resolved;
152
+ const device = statSync(existing).dev;
153
+ const candidates = [tmpdir()];
154
+ let current = existing === reference.resolved || !statSync(existing).isDirectory() ? dirname(existing) : existing;
155
+ while (statSync(current).dev === device) {
156
+ candidates.push(current);
157
+ const parent = dirname(current);
158
+ if (parent === current) break;
159
+ current = parent;
160
+ }
161
+ for (const candidate of candidates) try {
162
+ const path = realpathSync(candidate);
163
+ if (statSync(path).dev !== device || insideReference(path) || inside(cache, path) || !outsideWorkingTree(path)) continue;
164
+ accessSync(path, constants.W_OK);
165
+ return path;
166
+ } catch {}
167
+ throw new Error(`No writable temporary directory on the filesystem containing ${near}. Set STIM_TMPDIR or tempDir in ${join(getConfigDir(), "config.json")} to a directory outside Git working trees.`);
168
+ }
169
+ function makeTemporaryDirectory(near, prefix) {
170
+ const root = temporaryRoot(near);
171
+ mkdirSync(root, {
172
+ recursive: true,
173
+ mode: 448
174
+ });
175
+ return mkdtempSync(join(root, prefix));
176
+ }
177
+ function removeTemporaryEntry(path) {
178
+ const stat = lstatSync(path, { throwIfNoEntry: false });
179
+ if (stat?.isDirectory()) {
180
+ chmodSync(path, stat.mode | 448);
181
+ for (const entry of readdirSync(path, { withFileTypes: true })) if (entry.isDirectory()) removeTemporaryEntry(join(path, entry.name));
182
+ }
183
+ rmSync(path, {
184
+ recursive: true,
185
+ force: true
186
+ });
187
+ }
188
+ //#endregion
189
+ //#region src/workspace/worktree.ts
190
+ const CARRY_SKIP_BASENAMES = /* @__PURE__ */ new Set([
191
+ ".DerivedData",
192
+ ".DS_Store",
193
+ ".idea",
194
+ ".jj"
195
+ ]);
196
+ function isCarrySkipped(rel) {
197
+ return /(^|\/)android\/build\/generated\/autolinking(\/|$)/.test(rel) || String(rel).split("/").some((seg) => CARRY_SKIP_BASENAMES.has(seg));
198
+ }
199
+ function nativePath(path) {
200
+ return sep$1 === "/" ? path : path.replaceAll("/", sep$1);
201
+ }
202
+ function gitCommonDir(cwd) {
203
+ const out = getExecutor().runFileQuiet("git", [
204
+ "-C",
205
+ cwd,
206
+ "rev-parse",
207
+ "--path-format=absolute",
208
+ "--git-common-dir"
209
+ ]);
210
+ return out ? nativePath(out.trim()) : null;
211
+ }
212
+ function repoRoot(cwd) {
213
+ const out = getExecutor().runFileQuiet("git", [
214
+ "-C",
215
+ cwd,
216
+ "rev-parse",
217
+ "--show-toplevel"
218
+ ]);
219
+ return out ? nativePath(out.trim()) : null;
220
+ }
221
+ function locallyKnownUpstream(projectRoot) {
222
+ try {
223
+ const name = getExecutor().runFile("git", [
224
+ "-C",
225
+ projectRoot,
226
+ "rev-parse",
227
+ "--abbrev-ref",
228
+ "--symbolic-full-name",
229
+ "@{upstream}"
230
+ ], { timeoutMs: 5e3 });
231
+ const counts = getExecutor().runFile("git", [
232
+ "-C",
233
+ projectRoot,
234
+ "rev-list",
235
+ "--left-right",
236
+ "--count",
237
+ "HEAD...@{upstream}"
238
+ ], { timeoutMs: 5e3 }).trim().split(/\s+/).map(Number);
239
+ const ahead = counts[0] ?? NaN;
240
+ const behind = counts[1] ?? NaN;
241
+ if (!name || !Number.isInteger(ahead) || !Number.isInteger(behind)) return null;
242
+ return {
243
+ name,
244
+ ahead,
245
+ behind
246
+ };
247
+ } catch {
248
+ return null;
249
+ }
250
+ }
251
+ function warmWorktreePaths(cwd) {
252
+ const currentRoot = repoRoot(cwd);
253
+ if (!currentRoot) throw new Error("Not a git repository.");
254
+ const target = realpathSync$1(currentRoot);
255
+ const source = resolveSourceCheckout(target);
256
+ if ("refusal" in source) throw new Error(source.refusal);
257
+ if (!source.entries.find((entry) => canonicalPath(entry.path) === target)) throw new Error("Could not identify the linked worktree and its source checkout.");
258
+ const root = realpathSync$1(source.path);
259
+ if (root === target) throw new Error("Run stim worktree warm from a linked worktree, not the source checkout.");
260
+ const sourceRoot = repoRoot(root);
261
+ const sourceCommon = gitCommonDir(root);
262
+ const targetCommon = gitCommonDir(target);
263
+ if (!sourceRoot || realpathSync$1(sourceRoot) !== root || !sourceCommon || !targetCommon || realpathSync$1(sourceCommon) !== realpathSync$1(targetCommon)) throw new Error("Could not verify that the source checkout belongs to this linked worktree.");
264
+ return {
265
+ root,
266
+ target,
267
+ common: realpathSync$1(targetCommon)
268
+ };
269
+ }
270
+ function matchesInclude(path, patterns) {
271
+ for (const pattern of patterns || []) {
272
+ const rooted = pattern.startsWith("/");
273
+ const escaped = (rooted ? pattern.slice(1) : pattern).replace(/[.+^${}()|[\]\\?]/g, "\\$&").replace(/\*\*\//g, "::GLOBSTAR::").replace(/\*/g, "[^/]+").replace(/::GLOBSTAR::/g, "(?:.*/)?").replace(/\\\?/g, "[^/]");
274
+ if (new RegExp(`${rooted ? "^" : "(^|/)"}${escaped}$`).test(path)) return true;
275
+ }
276
+ return false;
277
+ }
278
+ function readWorktreeExclude(root) {
279
+ return readPatternFile(join$1(root, ".worktreeexclude"));
280
+ }
281
+ function readPatternFile(p) {
282
+ if (!existsSync$1(p)) return null;
283
+ return readFileSync$1(p, "utf-8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
284
+ }
285
+ function canonicalPath(path) {
286
+ try {
287
+ return realpathSync$1(path);
288
+ } catch {
289
+ return resolve$1(path);
290
+ }
291
+ }
292
+ function nestedWorktreePaths(root) {
293
+ const source = canonicalPath(root);
294
+ const paths = /* @__PURE__ */ new Set();
295
+ const out = getExecutor().runFileQuiet("git", [
296
+ "-C",
297
+ root,
298
+ "worktree",
299
+ "list",
300
+ "--porcelain"
301
+ ]);
302
+ if (out === null) throw new Error("Could not list Git worktrees. Refusing to carry ignored files.");
303
+ for (const entry of parseWorktrees(out)) {
304
+ const rel = relative$1(source, canonicalPath(entry.path));
305
+ if (!rel || rel === ".." || rel.startsWith(`..${sep$1}`) || isAbsolute$1(rel)) continue;
306
+ paths.add(rel.split(sep$1).join("/"));
307
+ }
308
+ return [...paths];
309
+ }
310
+ function overlapsNestedWorktree(rel, nestedPaths) {
311
+ const path = String(rel).replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/$/, "");
312
+ return nestedPaths.some((nested) => path === nested || path.startsWith(`${nested}/`) || nested.startsWith(`${path}/`));
313
+ }
314
+ function listTrackedPaths(dir) {
315
+ const out = getExecutor().runFileQuiet("git", [
316
+ "-C",
317
+ dir,
318
+ "ls-files",
319
+ "-z"
320
+ ]);
321
+ if (out === null) return null;
322
+ return out.split("\0").filter(Boolean);
323
+ }
324
+ function trackedGuard(dir) {
325
+ const paths = listTrackedPaths(dir);
326
+ if (paths === null) return {
327
+ known: false,
328
+ covers: () => false
329
+ };
330
+ const entries = new Set(paths);
331
+ const covered = new Set(paths);
332
+ for (const p of paths) for (let i = p.indexOf("/"); i !== -1; i = p.indexOf("/", i + 1)) covered.add(p.slice(0, i));
333
+ return {
334
+ known: true,
335
+ covers: (rel) => {
336
+ if (covered.has(rel)) return true;
337
+ for (let i = rel.indexOf("/"); i !== -1; i = rel.indexOf("/", i + 1)) if (entries.has(rel.slice(0, i))) return true;
338
+ return false;
339
+ }
340
+ };
341
+ }
342
+ function listGitignoredEntries(root) {
343
+ const args = [
344
+ "-C",
345
+ root,
346
+ "ls-files",
347
+ "--others",
348
+ "--ignored",
349
+ "--exclude-standard",
350
+ "--directory",
351
+ "--no-empty-directory",
352
+ "-z"
353
+ ];
354
+ const out = getExecutor().runFile("git", args);
355
+ if (!out) return [];
356
+ return out.split("\0").filter(Boolean).map((e) => e.endsWith("/") ? e.slice(0, -1) : e);
357
+ }
358
+ function listCarryableIgnoredEntries(root, patterns) {
359
+ const nested = nestedWorktreePaths(root);
360
+ return listGitignoredEntries(root).filter((rel) => !isCarrySkipped(rel) && !overlapsNestedWorktree(rel, nested) && !matchesInclude(rel, patterns));
361
+ }
362
+ function missingDestinationReason(target, rel) {
363
+ const parts = rel.split("/");
364
+ for (let i = 1; i < parts.length; i++) {
365
+ const parent = parts.slice(0, i).join("/");
366
+ const stat = lstatSync$1(join$1(target, parent), { throwIfNoEntry: false });
367
+ if (stat?.isSymbolicLink()) return `symlink ancestor: ${parent}`;
368
+ if (stat && !stat.isDirectory()) return `non-directory ancestor: ${parent}`;
369
+ }
370
+ return lstatSync$1(join$1(target, rel), { throwIfNoEntry: false }) ? "exists" : null;
371
+ }
372
+ function removeCopiedExclusions(path, rel) {
373
+ const entries = readdirSync$1(path, { withFileTypes: true });
374
+ const excluded = entries.filter((entry) => isCarrySkipped(`${rel}/${entry.name}`));
375
+ if (excluded.length > 0) {
376
+ const stat = lstatSync$1(path);
377
+ chmodSync$1(path, stat.mode | 448);
378
+ try {
379
+ for (const entry of excluded) removeTemporaryEntry(join$1(path, entry.name));
380
+ } finally {
381
+ utimesSync$1(path, stat.atime, stat.mtime);
382
+ chmodSync$1(path, stat.mode);
383
+ }
384
+ }
385
+ for (const entry of entries) {
386
+ const child = `${rel}/${entry.name}`;
387
+ if (entry.isDirectory() && !isCarrySkipped(child)) removeCopiedExclusions(join$1(path, entry.name), child);
388
+ }
389
+ }
390
+ function cloneIgnoredEntries({ root, target, patterns }) {
391
+ const copied = [];
392
+ const skipped = [];
393
+ const failed = [];
394
+ let cloned = true;
395
+ const guard = trackedGuard(target);
396
+ if (!guard.known) throw new Error("Could not list the destination's tracked files.");
397
+ const nested = nestedWorktreePaths(target);
398
+ for (const rel of listCarryableIgnoredEntries(root, patterns)) {
399
+ const from = join$1(root, rel);
400
+ const to = join$1(target, rel);
401
+ try {
402
+ const reason = guard.covers(rel) ? "tracked" : overlapsNestedWorktree(rel, nested) ? "nested worktree" : missingDestinationReason(target, rel);
403
+ if (reason) {
404
+ skipped.push({
405
+ file: rel,
406
+ reason
407
+ });
408
+ continue;
409
+ }
410
+ mkdirSync$1(dirname$1(to), { recursive: true });
411
+ try {
412
+ getExecutor().runFile("cp", [
413
+ "-Rc",
414
+ from,
415
+ to
416
+ ]);
417
+ } catch {
418
+ removeTemporaryEntry(to);
419
+ getExecutor().runFile("cp", [
420
+ "-R",
421
+ from,
422
+ to
423
+ ]);
424
+ cloned = false;
425
+ }
426
+ if (lstatSync$1(to).isDirectory()) removeCopiedExclusions(to, rel);
427
+ copied.push(rel);
428
+ } catch (e) {
429
+ failed.push({
430
+ file: rel,
431
+ error: String(e?.message || e)
432
+ });
433
+ }
434
+ }
435
+ return {
436
+ copied,
437
+ skipped,
438
+ failed,
439
+ cloned
440
+ };
441
+ }
442
+ function podsOutOfSync(target, copiedEntries, { read = readFileSync$1 } = {}) {
443
+ const problems = [];
444
+ for (const rel of copiedEntries || []) {
445
+ if (rel !== "Pods" && !rel.endsWith("/Pods")) continue;
446
+ const iosDir = rel === "Pods" ? "" : rel.slice(0, -5);
447
+ const manifest = join$1(target, rel, "Manifest.lock");
448
+ const podfileLock = join$1(target, iosDir, "Podfile.lock");
449
+ if (!existsSync$1(manifest)) continue;
450
+ if (!existsSync$1(podfileLock)) {
451
+ problems.push({
452
+ dir: iosDir || ".",
453
+ reason: "missing"
454
+ });
455
+ continue;
456
+ }
457
+ try {
458
+ if (read(manifest, "utf-8") !== read(podfileLock, "utf-8")) problems.push({
459
+ dir: iosDir || ".",
460
+ reason: "mismatch"
461
+ });
462
+ } catch {}
463
+ }
464
+ return problems;
465
+ }
466
+ const LOCKFILE_NAMES = [
467
+ "pnpm-lock.yaml",
468
+ "yarn.lock",
469
+ "bun.lock",
470
+ "bun.lockb",
471
+ "package-lock.json"
472
+ ];
473
+ function npmInstallMatches(wanted, installed) {
474
+ if (!wanted.packages || !installed.packages) return null;
475
+ for (const [key, entry] of Object.entries(wanted.packages)) {
476
+ if (!key.includes("node_modules/") || entry.link) continue;
477
+ const present = installed.packages[key];
478
+ if (!present && (entry.optional || entry.devOptional)) continue;
479
+ if (present?.version !== entry.version) return false;
480
+ }
481
+ return true;
482
+ }
483
+ function lastYamlDocument(text) {
484
+ return (text.split(/^---$/m).at(-1) ?? "").trim();
485
+ }
486
+ function yarnClassicInstallMatches(lockfile, integrity) {
487
+ if (!integrity.lockfileEntries) return null;
488
+ const wanted = [...lockfile.matchAll(/^ {2}resolved "([^"]+)"$/gm)].flatMap((m) => m[1] ?? []);
489
+ if (wanted.length === 0) return null;
490
+ const installed = new Set(Object.values(integrity.lockfileEntries));
491
+ return wanted.every((url) => installed.has(url));
492
+ }
493
+ function yarnBerryInstallMatches(lockfile, state) {
494
+ const installed = new Set([...state.matchAll(/^"?([^\s"#][^"]*?)"?:$/gm)].flatMap((m) => m[1]?.replace(/@virtual:[^#]+#/, "@") ?? []));
495
+ let entries = 0;
496
+ for (const entry of lockfile.split(/\n(?=\S)/)) {
497
+ const resolution = /^ {2}resolution: "([^"]+)"$/m.exec(entry)?.[1];
498
+ if (!resolution) continue;
499
+ entries += 1;
500
+ if (installed.has(resolution) || /^ {2}conditions: /m.test(entry)) continue;
501
+ return false;
502
+ }
503
+ return entries === 0 ? null : true;
504
+ }
505
+ function installedMatchesLockfile(dir, lockfile, { read = readFileSync$1 } = {}) {
506
+ const text = (rel) => {
507
+ try {
508
+ return read(join$1(dir, rel), "utf-8").replaceAll("\r\n", "\n");
509
+ } catch {
510
+ return null;
511
+ }
512
+ };
513
+ const wanted = text(lockfile);
514
+ if (wanted === null) return null;
515
+ try {
516
+ if (lockfile === "package-lock.json") {
517
+ const installed = text("node_modules/.package-lock.json");
518
+ return installed === null ? null : npmInstallMatches(JSON.parse(wanted), JSON.parse(installed));
519
+ }
520
+ if (lockfile === "pnpm-lock.yaml") {
521
+ const installed = text("node_modules/.pnpm/lock.yaml");
522
+ return installed === null ? null : lastYamlDocument(wanted) === lastYamlDocument(installed);
523
+ }
524
+ if (lockfile === "yarn.lock") {
525
+ if (/^__metadata:$/m.test(wanted)) {
526
+ const berry = text("node_modules/.yarn-state.yml");
527
+ return berry === null ? null : yarnBerryInstallMatches(wanted, berry);
528
+ }
529
+ const classic = text("node_modules/.yarn-integrity");
530
+ return classic === null ? null : yarnClassicInstallMatches(wanted, JSON.parse(classic));
531
+ }
532
+ } catch {}
533
+ return null;
534
+ }
535
+ function depsOutOfSync(root, target, copiedEntries, { read = readFileSync$1 } = {}) {
536
+ const problems = [];
537
+ for (const rel of copiedEntries || []) {
538
+ if (rel !== "node_modules" && !rel.endsWith("/node_modules")) continue;
539
+ const dir = rel === "node_modules" ? "" : rel.slice(0, -13);
540
+ const name = LOCKFILE_NAMES.find((candidate) => existsSync$1(join$1(target, dir, candidate)));
541
+ if (!name) continue;
542
+ const installed = installedMatchesLockfile(join$1(target, dir), name, { read });
543
+ if (installed === false) {
544
+ problems.push({
545
+ dir: dir || ".",
546
+ lockfile: name,
547
+ reason: "installed"
548
+ });
549
+ continue;
550
+ }
551
+ const source = join$1(root, dir, name);
552
+ if (installed === true || !existsSync$1(source)) continue;
553
+ try {
554
+ if (read(source, "utf-8") !== read(join$1(target, dir, name), "utf-8")) problems.push({
555
+ dir: dir || ".",
556
+ lockfile: name,
557
+ reason: "lockfile"
558
+ });
559
+ } catch {}
560
+ }
561
+ return problems;
562
+ }
563
+ const FINGERPRINT_INPUT_FILES = [
564
+ "app.json",
565
+ "app.config.ts",
566
+ "app.config.js",
567
+ "app.config.mjs",
568
+ "package.json"
569
+ ];
570
+ function dirtyFingerprintFiles(root) {
571
+ const out = getExecutor().runFileQuiet("git", [
572
+ "-C",
573
+ root,
574
+ "status",
575
+ "--porcelain",
576
+ "--",
577
+ ...FINGERPRINT_INPUT_FILES
578
+ ]);
579
+ if (out === null || out.trim() === "") return [];
580
+ return out.split("\n").map((line) => normalizePorcelainLine(line.trimEnd())).filter((line) => line !== "").map((line) => line.slice(3).trim()).filter((path) => path !== "");
581
+ }
582
+ function hasUncommittedWork(dir) {
583
+ const out = getExecutor().runFileQuiet("git", [
584
+ "--no-optional-locks",
585
+ "-C",
586
+ dir,
587
+ "status",
588
+ "--porcelain"
589
+ ]);
590
+ if (out === null) return null;
591
+ return out.trim().length > 0;
592
+ }
593
+ function dirtyPaths(dir, { limit = 10 } = {}) {
594
+ const out = getExecutor().runFileQuiet("git", [
595
+ "--no-optional-locks",
596
+ "-C",
597
+ dir,
598
+ "status",
599
+ "--porcelain"
600
+ ]);
601
+ if (out === null) return [];
602
+ return out.split("\n").map((l) => normalizePorcelainLine(l.trimEnd())).filter(Boolean).slice(0, limit);
603
+ }
604
+ function normalizePorcelainLine(line) {
605
+ if (line === "" || line[2] === " ") return line;
606
+ return ` ${line}`;
607
+ }
608
+ function restoreFile(dir, file) {
609
+ return getExecutor().runFileQuiet("git", [
610
+ "-C",
611
+ dir,
612
+ "checkout",
613
+ "--",
614
+ file
615
+ ]) !== null;
616
+ }
617
+ function isPodInstallChurn(paths) {
618
+ if (!paths || paths.length === 0) return false;
619
+ return paths.every((line) => /(?:^|\/)(?:Podfile\.lock|project\.pbxproj)$/.test(line.slice(3).trim()));
620
+ }
621
+ const SAFE_BRANCH_NAME = /^[A-Za-z0-9@._/-]+$/;
622
+ function unpushedCommits(dir) {
623
+ const exec = getExecutor();
624
+ const branch = exec.runFileQuiet("git", [
625
+ "-C",
626
+ dir,
627
+ "symbolic-ref",
628
+ "--quiet",
629
+ "--short",
630
+ "HEAD"
631
+ ]);
632
+ const own = branch === null ? "" : branch.trim();
633
+ const protection = own && SAFE_BRANCH_NAME.test(own) ? [
634
+ "--remotes",
635
+ `--exclude=${own}`,
636
+ "--branches"
637
+ ] : ["--remotes"];
638
+ if (!own && exec.runFileQuiet("git", [
639
+ "-C",
640
+ dir,
641
+ "rev-parse",
642
+ "--abbrev-ref",
643
+ "HEAD"
644
+ ]) === "HEAD") protection.push("--branches");
645
+ const out = exec.runFileQuiet("git", [
646
+ "-C",
647
+ dir,
648
+ "log",
649
+ "--oneline",
650
+ "HEAD",
651
+ "--not",
652
+ ...protection
653
+ ]);
654
+ if (out === null) return null;
655
+ return out.split("\n").map((l) => l.trim()).filter(Boolean);
656
+ }
657
+ function hasRemote(dir) {
658
+ const out = getExecutor().runFileQuiet("git", [
659
+ "-C",
660
+ dir,
661
+ "remote"
662
+ ]);
663
+ return Boolean(out && out.trim().length > 0);
664
+ }
665
+ function branchExists(cwd, branch) {
666
+ const out = getExecutor().runFileQuiet("git", [
667
+ "-C",
668
+ cwd,
669
+ "rev-parse",
670
+ "--verify",
671
+ "--quiet",
672
+ `refs/heads/${branch}`
673
+ ]);
674
+ return Boolean(out);
675
+ }
676
+ function resolveFullRef(cwd, ref) {
677
+ try {
678
+ const out = getExecutor().runFile("git", [
679
+ "-C",
680
+ cwd,
681
+ "rev-parse",
682
+ "--verify",
683
+ "--quiet",
684
+ "--end-of-options",
685
+ `${ref}^{commit}`
686
+ ]);
687
+ return out && out.trim() ? out.trim() : null;
688
+ } catch {
689
+ return null;
690
+ }
691
+ }
692
+ function removeWorktree(path, { from, force = false, platform = process.platform }) {
693
+ const args = [
694
+ ...platform === "win32" ? ["-c", "core.longpaths=true"] : [],
695
+ "-C",
696
+ from,
697
+ "worktree",
698
+ "remove",
699
+ ...force ? ["--force"] : [],
700
+ "--",
701
+ path
702
+ ];
703
+ getExecutor().runFile("git", args);
704
+ }
705
+ function deleteBranch(cwd, branch, expectedSha) {
706
+ if (!SAFE_BRANCH_NAME.test(branch) || branch.startsWith("-")) throw new Error(`Refusing branch ${JSON.stringify(branch)}: it is not a safe local branch name.`);
707
+ getExecutor().runFile("git", [
708
+ "-C",
709
+ cwd,
710
+ "update-ref",
711
+ "-d",
712
+ `refs/heads/${branch}`,
713
+ expectedSha
714
+ ]);
715
+ }
716
+ function parseWorktrees(out) {
717
+ const entries = [];
718
+ let current = {};
719
+ for (const line of out.split("\n")) if (line.startsWith("worktree ")) {
720
+ if (current.path) entries.push(current);
721
+ current = { path: nativePath(line.slice(9)) };
722
+ } else if (line.startsWith("branch ")) current.branch = line.slice(7).replace("refs/heads/", "");
723
+ else if (line === "prunable" || line.startsWith("prunable ")) current.prunable = true;
724
+ else if (line === "locked" || line.startsWith("locked ")) current.locked = true;
725
+ else if (line === "bare") current.bare = true;
726
+ if (current.path) entries.push(current);
727
+ return entries;
728
+ }
729
+ function hasPopulatedSubmodules(worktree) {
730
+ const modules = getExecutor().runFileQuiet("git", [
731
+ "-C",
732
+ worktree,
733
+ "rev-parse",
734
+ "--git-path",
735
+ "modules"
736
+ ]);
737
+ if (modules && existsSync$1(resolve$1(worktree, nativePath(modules)))) return true;
738
+ return (getExecutor().runFileQuiet("git", [
739
+ "-C",
740
+ worktree,
741
+ "ls-files",
742
+ "--stage",
743
+ "-z"
744
+ ]) ?? "").split("\0").some((line) => line.startsWith("160000 ") && existsSync$1(join$1(worktree, line.slice(line.indexOf(" ") + 1), ".git")));
745
+ }
746
+ function listWorktrees(cwd) {
747
+ const out = getExecutor().runFileQuiet("git", [
748
+ "-C",
749
+ cwd,
750
+ "worktree",
751
+ "list",
752
+ "--porcelain"
753
+ ]);
754
+ return out ? parseWorktrees(out) : [];
755
+ }
756
+ function branchOf(head) {
757
+ return head.startsWith("ref: refs/heads/") ? head.slice(16) : void 0;
758
+ }
759
+ /**
760
+ * The linked worktrees recorded under a git common dir, read from `worktrees/<id>/gitdir` and `HEAD` without running
761
+ * git or touching the worktree directories, sorted by path. The worktree with the branch the common dir's own `HEAD`
762
+ * names (the main checkout's branch, or a bare repository's source checkout) is left out.
763
+ */
764
+ function linkedWorktreesOnDisk(commonDir) {
765
+ const admin = join$1(commonDir, "worktrees");
766
+ let ids;
767
+ let sourceBranch;
768
+ try {
769
+ ids = readdirSync$1(admin);
770
+ sourceBranch = branchOf(readFileSync$1(join$1(commonDir, "HEAD"), "utf-8").trim());
771
+ } catch {
772
+ return [];
773
+ }
774
+ return ids.flatMap((id) => {
775
+ try {
776
+ const gitdir = readFileSync$1(join$1(admin, id, "gitdir"), "utf-8").trim();
777
+ const branch = branchOf(readFileSync$1(join$1(admin, id, "HEAD"), "utf-8").trim());
778
+ if (branch && branch === sourceBranch) return [];
779
+ const path = dirname$1(resolve$1(admin, id, nativePath(gitdir)));
780
+ return [branch ? {
781
+ path,
782
+ branch
783
+ } : { path }];
784
+ } catch {
785
+ return [];
786
+ }
787
+ }).toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
788
+ }
789
+ /**
790
+ * The git common dir of the repository containing `start`, read from `.git` and `commondir` files without running
791
+ * git. Returns null when `start` is missing, unreadable, or not inside a repository.
792
+ */
793
+ function gitCommonDirOnDisk(start) {
794
+ try {
795
+ for (let dir = realpathSync$1.native(start);; dir = dirname$1(dir)) {
796
+ const dotGit = join$1(dir, ".git");
797
+ if (existsSync$1(dotGit)) {
798
+ if (statSync$1(dotGit).isDirectory()) return realpathSync$1.native(dotGit);
799
+ const gitdir = /^gitdir: (.+)$/m.exec(readFileSync$1(dotGit, "utf-8"))?.[1]?.trim();
800
+ if (!gitdir) return null;
801
+ const linked = resolve$1(dir, gitdir);
802
+ const commondir = join$1(linked, "commondir");
803
+ return realpathSync$1.native(existsSync$1(commondir) ? resolve$1(linked, readFileSync$1(commondir, "utf-8").trim()) : linked);
804
+ }
805
+ if (dirname$1(dir) === dir) return null;
806
+ }
807
+ } catch {
808
+ return null;
809
+ }
810
+ }
811
+ function selectSourceCheckout(entries, bareHead) {
812
+ const first = entries[0];
813
+ if (!first) return { refusal: "Git lists no worktrees for this repository." };
814
+ if (!first.bare) return { path: first.path };
815
+ const bare = first.path;
816
+ const checkouts = entries.filter((entry) => !entry.bare && !entry.prunable);
817
+ const listed = checkouts.map((entry) => `${entry.branch ?? "detached"} (${entry.path})`).join(", ") || "none";
818
+ const pointHead = ` git -C ${bare} symbolic-ref HEAD refs/heads/<branch>`;
819
+ if (!bareHead) return { refusal: `The bare repository at ${bare} has a detached HEAD, so Stim cannot tell which worktree is the source checkout. Point HEAD at the source branch, then retry:\n${pointHead}\nChecked-out branches: ${listed}` };
820
+ const matches = checkouts.filter((entry) => entry.branch === bareHead);
821
+ const [only] = matches;
822
+ if (only && matches.length === 1) return { path: only.path };
823
+ if (!only) {
824
+ const stale = entries.find((entry) => entry.prunable && entry.branch === bareHead);
825
+ const beside = checkouts[0] ? dirname$1(checkouts[0].path) : bare;
826
+ return { refusal: `The bare repository at ${bare} points HEAD at ${bareHead}, but no worktree has ${bareHead} checked out, so Stim has no source checkout to copy from. ${stale ? `Its worktree at ${stale.path} is missing. Recreate it, then retry:\n git -C ${bare} worktree prune\n git -C ${bare} worktree add ${stale.path} ${bareHead}\n` : `Create one, then retry:\n git -C ${bare} worktree add ${join$1(beside, bareHead)} ${bareHead}\n`}Or point HEAD at a branch that is checked out (${listed}):\n${pointHead}` };
827
+ }
828
+ return { refusal: `The bare repository at ${bare} points HEAD at ${bareHead}, which is checked out in more than one worktree: ${matches.map((entry) => entry.path).join(", ")}. Remove the extra worktrees, or point HEAD at a branch checked out once, then retry:\n${pointHead}` };
829
+ }
830
+ function bareHeadBranch(bare) {
831
+ const out = getExecutor().runFileQuiet("git", [
832
+ "-C",
833
+ bare,
834
+ "symbolic-ref",
835
+ "--quiet",
836
+ "HEAD"
837
+ ])?.trim();
838
+ return out?.startsWith("refs/heads/") ? out.slice(11) : null;
839
+ }
840
+ function sourceCheckoutOf(entries) {
841
+ const first = entries[0];
842
+ return selectSourceCheckout(entries, first?.bare ? bareHeadBranch(first.path) : null);
843
+ }
844
+ function resolveSourceCheckout(cwd) {
845
+ const entries = listWorktrees(cwd);
846
+ return {
847
+ entries,
848
+ ...sourceCheckoutOf(entries)
849
+ };
850
+ }
851
+ //#endregion
105
852
  //#region src/engine/metro-reach.ts
106
853
  const PUBLIC_METRO_ENV = "STIM_METRO_PUBLIC_URL";
107
854
  const MANAGED_PROVIDERS = ["ngrok", "cloudflared"];
@@ -347,15 +1094,15 @@ function androidAvdConfigSetting(settings, settingsRoot) {
347
1094
  if ("avdConfigFile" in android) {
348
1095
  if (typeof android.avdConfigFile !== "string" || !android.avdConfigFile.trim() || android.avdConfigFile !== android.avdConfigFile.trim() || /[\r\n\0]/.test(android.avdConfigFile) || isAbsolute$1(android.avdConfigFile)) throw new Error("Invalid android.avdConfigFile setting. Expected a relative file path inside the app directory.");
349
1096
  try {
350
- const root = realpathSync(settingsRoot);
1097
+ const root = realpathSync$1(settingsRoot);
351
1098
  const candidate = resolve$1(root, android.avdConfigFile);
352
1099
  if (pathEscapesRoot(root, candidate)) throw new Error("path escapes the settings root");
353
- const path = realpathSync(candidate);
1100
+ const path = realpathSync$1(candidate);
354
1101
  if (pathEscapesRoot(root, path)) throw new Error("symlink target escapes the settings root");
355
- const stat = statSync(path);
1102
+ const stat = statSync$1(path);
356
1103
  if (!stat.isFile()) throw new Error("path is not a regular file");
357
1104
  if (stat.size > 65536) throw new Error("file exceeds 64 KiB");
358
- const contents = readFileSync(path, "utf8");
1105
+ const contents = readFileSync$1(path, "utf8");
359
1106
  if (Buffer.byteLength(contents) > 65536) throw new Error("file exceeds 64 KiB");
360
1107
  entries = parseAndroidAvdConfigIni(contents);
361
1108
  } catch (error) {
@@ -384,12 +1131,12 @@ function iosSimSlimProfileSetting(settings, settingsRoot) {
384
1131
  const value = settings.ios.simslimProfile;
385
1132
  if (typeof value !== "string" || !value.trim() || value !== value.trim() || /[\r\n\0]/.test(value) || isAbsolute$1(value)) throw new Error("Invalid ios.simslimProfile setting. Expected a relative JSON file path inside the app directory.");
386
1133
  try {
387
- const root = realpathSync(settingsRoot);
1134
+ const root = realpathSync$1(settingsRoot);
388
1135
  const candidate = resolve$1(root, value);
389
1136
  if (pathEscapesRoot(root, candidate)) throw new Error("path escapes the settings root");
390
- const path = realpathSync(candidate);
1137
+ const path = realpathSync$1(candidate);
391
1138
  if (pathEscapesRoot(root, path)) throw new Error("symlink target escapes the settings root");
392
- const stat = statSync(path);
1139
+ const stat = statSync$1(path);
393
1140
  if (!stat.isFile()) throw new Error("path is not a regular file");
394
1141
  if (stat.size > 65536) throw new Error("file exceeds 64 KiB");
395
1142
  return path;
@@ -451,9 +1198,9 @@ function unknownSettingKeys(settings, prefix = "") {
451
1198
  function readCommittedSettings(directory) {
452
1199
  if (!directory) return {};
453
1200
  const p = join$1(directory, ".stim.json");
454
- if (!existsSync(p)) return {};
1201
+ if (!existsSync$1(p)) return {};
455
1202
  try {
456
- const parsed = JSON.parse(readFileSync(p, "utf-8"));
1203
+ const parsed = JSON.parse(readFileSync$1(p, "utf-8"));
457
1204
  return isPlainObject(parsed) ? parsed : {};
458
1205
  } catch {
459
1206
  return {};
@@ -588,9 +1335,11 @@ function cacheProviderSettingError(settings) {
588
1335
  if ("options" in block && !isPlainObject(block.options)) return `Invalid cache.options setting ${JSON.stringify(block.options)}. Expected an object.`;
589
1336
  return null;
590
1337
  }
1338
+ /** The remote target `remote` names, or null for `local`, which runs on this Mac whatever a lower layer sets. */
591
1339
  function parseIosRemote(remote) {
592
1340
  const selected = remote.trim();
593
1341
  const reserved = selected.toLowerCase();
1342
+ if (reserved === "local") return null;
594
1343
  return REMOTE_DEVICE_BACKENDS.includes(reserved) ? {
595
1344
  kind: "backend",
596
1345
  backend: reserved
@@ -603,6 +1352,9 @@ function remoteIosSetting(settings) {
603
1352
  const ios = settings.ios;
604
1353
  return isPlainObject(ios) && typeof ios.remote === "string" ? parseIosRemote(ios.remote) : null;
605
1354
  }
1355
+ function remoteEasFallbackSetting(settings) {
1356
+ return settingValueAt(settings, "remote.easFallback") === true;
1357
+ }
606
1358
  function remoteAndroidSetting(settings) {
607
1359
  const android = settings.android;
608
1360
  return isPlainObject(android) && typeof android.remote === "string" ? parseIosRemote(android.remote) : null;
@@ -698,4 +1450,4 @@ function webSettings(settings) {
698
1450
  };
699
1451
  }
700
1452
  //#endregion
701
- export { publicUrlSetting as A, settingValueAt as B, metroWarmupUrlSetting as C, projectMaintenancePinned as D, projectDeviceReclaimIdleMinutes as E, resolveSettings as F, PUBLIC_METRO_ENV as G, tunnelModeSetting as H, settingFile as I, resolveTailscaleBinary as J, detectProviders as K, settingOrigin as L, remoteAndroidSetting as M, remoteIosSetting as N, projectMetroSharedCache as O, resolveCacheProviderConfig as P, resolveOptimizations as Q, settingOriginScope as R, metroTunnelSettingError as S, parseIosRemote as T, unknownSettingKeys as U, settingsLayers as V, webSettings as W, compilerCacheFallbackMessage as X, artifactCachePolicy as Y, optimizationBuildProfile as Z, iosSigningIdentitySha1SettingError as _, androidAvdConfigSetting as a, metroIdleStopMinutesSetting as b, androidDataPartitionSizeGbSetting as c, deviceIdleShutdownMinutesSetting as d, iosLanHostSetting as f, iosSigningIdentitySha1Setting as g, iosSigningIdentitySettingError as h, SETTING_SHAPE_REMEDY as i, readCommittedSettings as j, projectOptimizations as k, androidDataPartitionSizeGbSettingError as l, iosSigningIdentitySetting as m, PATH_SETTINGS as n, androidAvdConfigSettingError as o, iosLanHostSettingError as p, planMetroReach as q, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as r, androidDataPartitionSizeBytes as s, ANDROID_AVD_CONFIG_HELP as t, cacheProviderSettingError as u, iosSimSlimProfileSetting as v, ngrokUrlSetting as w, metroPortSetting as x, mergeSettingsLayers as y, settingShapeErrors as z };
1453
+ export { depsOutOfSync as $, publicUrlSetting as A, settingShapeErrors as B, metroWarmupUrlSetting as C, removeTemporaryEntry as Ct, projectMaintenancePinned as D, optimizationBuildProfile as Dt, projectDeviceReclaimIdleMinutes as E, compilerCacheFallbackMessage as Et, resolveCacheProviderConfig as F, webSettings as G, settingsLayers as H, resolveSettings as I, planMetroReach as J, PUBLIC_METRO_ENV as K, settingFile as L, remoteAndroidSetting as M, remoteEasFallbackSetting as N, projectMetroSharedCache as O, resolveOptimizations as Ot, remoteIosSetting as P, deleteBranch as Q, settingOrigin as R, metroTunnelSettingError as S, makeTemporaryDirectory as St, parseIosRemote as T, artifactCachePolicy as Tt, tunnelModeSetting as U, settingValueAt as V, unknownSettingKeys as W, branchExists as X, resolveTailscaleBinary as Y, cloneIgnoredEntries as Z, iosSigningIdentitySha1SettingError as _, restoreFile as _t, androidAvdConfigSetting as a, hasRemote as at, metroIdleStopMinutesSetting as b, warmWorktreePaths as bt, androidDataPartitionSizeGbSetting as c, linkedWorktreesOnDisk as ct, deviceIdleShutdownMinutesSetting as d, podsOutOfSync as dt, dirtyFingerprintFiles as et, iosLanHostSetting as f, readWorktreeExclude as ft, iosSigningIdentitySha1Setting as g, resolveSourceCheckout as gt, iosSigningIdentitySettingError as h, resolveFullRef as ht, SETTING_SHAPE_REMEDY as i, hasPopulatedSubmodules as it, readCommittedSettings as j, projectOptimizations as k, androidDataPartitionSizeGbSettingError as l, listWorktrees as lt, iosSigningIdentitySetting as m, repoRoot as mt, PATH_SETTINGS as n, gitCommonDir as nt, androidAvdConfigSettingError as o, hasUncommittedWork as ot, iosLanHostSettingError as p, removeWorktree as pt, detectProviders as q, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as r, gitCommonDirOnDisk as rt, androidDataPartitionSizeBytes as s, isPodInstallChurn as st, ANDROID_AVD_CONFIG_HELP as t, dirtyPaths as tt, cacheProviderSettingError as u, locallyKnownUpstream as ut, iosSimSlimProfileSetting as v, sourceCheckoutOf as vt, ngrokUrlSetting as w, temporaryRoot as wt, metroPortSetting as x, filesystemDevice as xt, mergeSettingsLayers as y, unpushedCommits as yt, settingOriginScope as z };