stim 1.17.2 → 1.18.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 (150) hide show
  1. package/README.md +50 -1
  2. package/dist/{activity-IRvJY_ru.mjs → activity-BxnkDZDi.mjs} +4 -4
  3. package/dist/{agent-device-usage-output-BK41vnzN.mjs → agent-device-usage-output-CZ66YA4T.mjs} +8 -8
  4. package/dist/android-BKA16DTf.mjs +4 -0
  5. package/dist/{android-B9yaNKwa.mjs → android-BvwuMUJ9.mjs} +192 -98
  6. package/dist/{android-DE4v59Mb.mjs → android-CBwCNicO.mjs} +2 -2
  7. package/dist/{android-B_YNZy61.mjs → android-DC3ZLuw0.mjs} +9 -9
  8. package/dist/{android-cas-ZFpjJBL_.mjs → android-cas-BBFyr9CA.mjs} +5 -5
  9. package/dist/android-cas-compiler.mjs +2 -2
  10. package/dist/api-D0VtFhqk.mjs +152 -0
  11. package/dist/api-run.d.mts +1 -0
  12. package/dist/api-run.mjs +145 -0
  13. package/dist/api.d.mts +212 -0
  14. package/dist/api.mjs +2 -0
  15. package/dist/{app-install-VPkI5WEg.mjs → app-install-D-PUENug.mjs} +3 -3
  16. package/dist/{attempt-Bk2ouQVL.mjs → attempt-DW-mQqM7.mjs} +14 -4
  17. package/dist/{budget-DfcgFdQB.mjs → budget-DIhL2BKx.mjs} +1578 -58
  18. package/dist/build-facts-DcLv2HSd.d.mts +111 -0
  19. package/dist/{cache-manifest-DnUHBJaU.mjs → cache-manifest-BI7ozfmH.mjs} +3 -3
  20. package/dist/cache-manifest.mjs +1 -1
  21. package/dist/{chrome-BrcVWQyD.mjs → chrome-DJnmnS5q.mjs} +1 -1
  22. package/dist/cli-DNJMwADx.mjs +68 -0
  23. package/dist/cli.mjs +1 -1
  24. package/dist/{client-SvBdgObD.mjs → client-DzhapoMB.mjs} +139 -32
  25. package/dist/collector-run.mjs +9 -9
  26. package/dist/{command-output-CDAIFD-8.mjs → command-output-CBtzyIgF.mjs} +2 -2
  27. package/dist/{config-D0DbpZtM.mjs → config-CgYMahz7.mjs} +5 -5
  28. package/dist/{created-devices-CpvzBL25.mjs → created-devices-DKbeWsiK.mjs} +2 -2
  29. package/dist/{dependency-state-CLcBHH2M.mjs → dependency-state-xKoOypBm.mjs} +2 -2
  30. package/dist/{detached-entry-CiTEgMR1.mjs → detached-entry-BLfcgc4O.mjs} +1 -1
  31. package/dist/{dev-client-B-XC4uRH.mjs → dev-client-CLnIH02x.mjs} +2 -2
  32. package/dist/{device-C8IOoJPv.mjs → device-D7oCHGWi.mjs} +8 -8
  33. package/dist/{device-capacity-ZC4XSZ4R.mjs → device-capacity-EUOOYr8T.mjs} +13 -13
  34. package/dist/device-host-worker.mjs +19 -19
  35. package/dist/{device-ios-C2Um-XUR.mjs → device-ios-6MewKKnc.mjs} +13 -13
  36. package/dist/{device-lease-DpoS36_u.mjs → device-lease-Co-EwifR.mjs} +9 -9
  37. package/dist/{device-lease-run-B8YltIH_.mjs → device-lease-run-w1xhCqIW.mjs} +4 -4
  38. package/dist/{device-pool-3o7s5lo4.mjs → device-pool-F5WvRPtD.mjs} +3 -3
  39. package/dist/{device-remote-hFSkpfQu.mjs → device-remote-tHbd1fKy.mjs} +15 -15
  40. package/dist/{doctor-CFv1fCrF.mjs → doctor-B9ckYUoU.mjs} +33 -30
  41. package/dist/{error-diagnostics-C-NMnhrk.mjs → error-diagnostics-BRXOqDzG.mjs} +11 -11
  42. package/dist/{exec-CaErVv7t.mjs → exec-DWhCZDGm.mjs} +65 -2
  43. package/dist/{gc-DEmkg3Xh.mjs → gc-Dh6mXOKC.mjs} +23 -469
  44. package/dist/{gradle-dJpre3Yn.mjs → gradle-C6GKnunQ.mjs} +6 -6
  45. package/dist/{guide-status-Du-ZQ3FD.mjs → guide-status-Bhf9SJXc.mjs} +3 -3
  46. package/dist/{guide-CSmhMTf8.mjs → guide-tm6igAaa.mjs} +290 -53
  47. package/dist/{hosted-android-E1Heoqnv.mjs → hosted-android-Bv285t_t.mjs} +3 -3
  48. package/dist/{hosted-client-Bp4knSwu.mjs → hosted-client-C-rMtppF.mjs} +2 -2
  49. package/dist/{hosted-ios-BnbeYOUD.mjs → hosted-ios-D5mNmtj4.mjs} +1 -1
  50. package/dist/{hosted-logs-OcgIBvCT.mjs → hosted-logs-DN8Iz4mJ.mjs} +9 -9
  51. package/dist/{hosted-macos-DcxKjtfH.mjs → hosted-macos-B-wEjlwG.mjs} +5 -5
  52. package/dist/{hosted-native-1Ebbig4w.mjs → hosted-native-DeeOG8xZ.mjs} +6 -6
  53. package/dist/{idle-shutdown-IGyNV8Cr.mjs → idle-shutdown-jjtxAn5C.mjs} +7 -8
  54. package/dist/{ios-DSfnPfse.mjs → ios-B3SbOWdw.mjs} +19 -7
  55. package/dist/{ios-Cr1h5gnO.mjs → ios-Bvbf0SGY.mjs} +1 -1
  56. package/dist/{ios-BJ4XUSe1.mjs → ios-CPdkoKaa.mjs} +181 -95
  57. package/dist/ios-DNpdygiv.mjs +7 -0
  58. package/dist/{ios-device-Ee7sDXfp.mjs → ios-device-Bn7jWDB1.mjs} +1 -1
  59. package/dist/{ios-device-pAN4t54-.mjs → ios-device-vOaByMhw.mjs} +3 -3
  60. package/dist/{ios-state-8L3lgum6.mjs → ios-state-B2pES6Vs.mjs} +1 -1
  61. package/dist/{launch-verify-lTnWZikR.mjs → launch-verify-hskNcWkZ.mjs} +5 -5
  62. package/dist/{logs-BAaS7gS2.mjs → logs-1Ylc1Ri6.mjs} +13 -13
  63. package/dist/macos-Ck7OBMNY.mjs +2 -0
  64. package/dist/{macos-BIRQS90f.mjs → macos-DF6C7wUU.mjs} +118 -34
  65. package/dist/macos-run.mjs +1 -1
  66. package/dist/maintenance-run.mjs +349 -47
  67. package/dist/{metro-g8NqiJp-.mjs → metro-Dh8T4Ytd.mjs} +5 -5
  68. package/dist/{metro-gateway-C-ijGI2F.mjs → metro-gateway-CEUw9RMH.mjs} +4 -4
  69. package/dist/{metro-store-CDDZHtPl.mjs → metro-store-BAHFcJm6.mjs} +16 -2
  70. package/dist/{named-ports-C8m8EQs2.mjs → named-ports-BFIz1Shz.mjs} +61 -6
  71. package/dist/{native-run-D1Q56rAD.mjs → native-run-B06FkmZx.mjs} +4 -4
  72. package/dist/{native-runtime-BEK171xQ.mjs → native-runtime-D_603JiC.mjs} +6 -6
  73. package/dist/{ndjson-PclOIwVY.mjs → ndjson-LGZAMsqa.mjs} +8 -4
  74. package/dist/offload-worker.d.mts +3 -17
  75. package/dist/offload-worker.mjs +10 -11
  76. package/dist/{ownership-DyRQru0q.mjs → ownership-D6Se7gg_.mjs} +3 -3
  77. package/dist/{page-QF_Ke10s.mjs → page-Bv9s2KwY.mjs} +1 -1
  78. package/dist/placement-log-BcPhRwR4.mjs +84 -0
  79. package/dist/{build-plan-BDsSi09V.mjs → plan-placement-CtxkCO54.mjs} +122 -48
  80. package/dist/{ports-4nYqxPWC.mjs → ports-BLTtfBq-.mjs} +3 -3
  81. package/dist/{prebuild-D7RUMkwN.mjs → prebuild-juCyreaR.mjs} +5 -5
  82. package/dist/preview-D5V07Nrl.mjs +987 -0
  83. package/dist/{rolldown-runtime-BsOwBuO_.mjs → process-identity-Biv3arCO.mjs} +11 -1
  84. package/dist/{project-D47Rh0ly.mjs → project-C3ChRLZy.mjs} +4 -68
  85. package/dist/projects-DD7dBTCj.mjs +92 -0
  86. package/dist/{pull-request-pxnDCQzn.mjs → pull-request-u4vp7zmK.mjs} +1 -1
  87. package/dist/pull-requests.mjs +1 -1
  88. package/dist/{recordings-BNgsD1Tr.mjs → recordings-BAWltsVt.mjs} +1 -1
  89. package/dist/{reload-DcRxj3qG.mjs → reload-DvyWzVjJ.mjs} +15 -15
  90. package/dist/{remote-cache-Ci4DQYYj.mjs → remote-cache-BGg7aGIZ.mjs} +5 -5
  91. package/dist/{run-CkE9y0nc.mjs → run-vhtDgpHO.mjs} +5 -5
  92. package/dist/{server-bare-BkrSxSsZ.mjs → server-bare-B9E7S1aR.mjs} +4 -5
  93. package/dist/server-expo-Db9HBUoa.mjs +2 -0
  94. package/dist/{server-expo-CHTyXD0G.mjs → server-expo-DoBHhuzK.mjs} +5 -6
  95. package/dist/{settings-SR9OmW9h.mjs → settings-Byp2AQ_E.mjs} +6 -5
  96. package/dist/{settings-Cfd-0r2d.mjs → settings-CQyMElEP.mjs} +24 -763
  97. package/dist/{settings-BBpMcDbD.mjs → settings-Djl-mpjX.mjs} +1 -1
  98. package/dist/settings.schema.json +126 -3
  99. package/dist/{simslim-BWNrc3M3.mjs → simslim-EHBQ2R4G.mjs} +7 -7
  100. package/dist/{slot-launch-DmjBmpQV.mjs → slot-launch-C1nqh4mu.mjs} +6 -6
  101. package/dist/{spawn-claims-D0XfSe8u.mjs → spawn-claims-Kqiifsk2.mjs} +1 -1
  102. package/dist/{spawn-entry-jw19m8Nl.mjs → spawn-entry-Dcb7sDUz.mjs} +1 -0
  103. package/dist/{stage-CzaiwFsI.mjs → stage-g_WqWeaE.mjs} +14 -3
  104. package/dist/{start-DUz3mYdb.mjs → start-D-IeOyoK.mjs} +19 -19
  105. package/dist/{start-AlfCPRVU.mjs → start-NTc1Ifqs.mjs} +1 -1
  106. package/dist/{state-PeQiJuIu.mjs → state-BG-aAk4k.mjs} +4 -4
  107. package/dist/{state-B4PQFXMW.d.mts → state-lKh8shBp.d.mts} +2 -3
  108. package/dist/{state-DyaNTgfR.mjs → state-xnqpx3AD.mjs} +2 -2
  109. package/dist/{stats-Bq4fJOdB.mjs → stats-DY6ekz8F.mjs} +5 -5
  110. package/dist/{status-DlKvVJBE.mjs → status-BEeL6IKz.mjs} +6 -4
  111. package/dist/{status-BA2pehwf.mjs → status-DCjZeE-K.mjs} +33 -34
  112. package/dist/{status-CzS4bPO9.mjs → status-Dcr0Qexd.mjs} +5 -5
  113. package/dist/{stim-desktop-Cnz8CPnl.mjs → stim-desktop-Behws_fi.mjs} +1 -1
  114. package/dist/{stim-installations-QMEI32v1.mjs → stim-installations-aR_WsNOA.mjs} +1 -1
  115. package/dist/{stop-BIiM49EY.mjs → stop-BGhKMOuH.mjs} +5 -5
  116. package/dist/{stop-DQIasgKp.mjs → stop-BTjs3xbc.mjs} +17 -18
  117. package/dist/{stop-zF1y04f2.mjs → stop-DIJtD2GL.mjs} +2 -2
  118. package/dist/supervisor-run.d.mts +24 -22
  119. package/dist/supervisor-run.mjs +21 -22
  120. package/dist/{support-CsJNVfOc.mjs → support-BaayeYCf.mjs} +7 -7
  121. package/dist/{support-WvD__tSV.mjs → support-Bwvbrq5-.mjs} +5 -5
  122. package/dist/{toolchain-DNyR3NPq.mjs → toolchain-Bnyd_K3A.mjs} +471 -22
  123. package/dist/{trigger-Bemu8ytw.mjs → trigger-CJMhwXe8.mjs} +5 -5
  124. package/dist/trigger-DWAq9hkw.mjs +2 -0
  125. package/dist/{warm-progress-DF4JRvYI.mjs → warm-progress-CjB-MP6H.mjs} +7 -7
  126. package/dist/web-B6_bFDn7.mjs +2 -0
  127. package/dist/{web-Dl0KSRHf.mjs → web-DTU0uiWj.mjs} +22 -22
  128. package/dist/web-run.mjs +10 -10
  129. package/dist/{workspace-state-DqcCbpE7.mjs → workspace-state-C59dqG-Z.mjs} +3 -3
  130. package/dist/{ownership-BMLqyBgJ.mjs → workspaces-xXItD8Dj.mjs} +577 -23
  131. package/dist/{worktree-j3IcFAI5.mjs → worktree-BJfnU6r5.mjs} +1 -1
  132. package/dist/{worktree-Be_7NLKy.mjs → worktree-BSYlofkq.mjs} +234 -35
  133. package/dist/worktree-CsKYexJM.mjs +753 -0
  134. package/package.json +10 -5
  135. package/dist/build-progress-D0WkjCPd.mjs +0 -1036
  136. package/dist/build-slots-41v_d2x9.mjs +0 -142
  137. package/dist/cli-CYXb29oE.mjs +0 -51
  138. package/dist/deps-iKw0eD4P.mjs +0 -438
  139. package/dist/errors-B6W7FkxQ.mjs +0 -15
  140. package/dist/idle-BXG__1BA.mjs +0 -176
  141. package/dist/in-use-CvGOUn-x.mjs +0 -130
  142. package/dist/preview-B-g9d7kV.mjs +0 -318
  143. package/dist/process-identity-BmRm1qV0.mjs +0 -12
  144. package/dist/server-expo-CeakhI8P.mjs +0 -2
  145. package/dist/state-BKa8wNN5.mjs +0 -148
  146. package/dist/stop-cause-rhmGfwvt.mjs +0 -97
  147. package/dist/trigger-CXts6qt1.mjs +0 -2
  148. package/dist/watchman-APYjXSQa.mjs +0 -48
  149. package/dist/workspace-process-lock-2mNzOlaB.mjs +0 -58
  150. package/dist/workspaces-Bcib97-6.mjs +0 -306
@@ -1,757 +1,10 @@
1
- import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
- import { _ as loadConfig$1, d as getConfigDir, f as getConfigPath$1, h as getRepoSettings, m as getProjectSettings } from "./config-D0DbpZtM.mjs";
3
- import { createHash } from "node:crypto";
4
- import { accessSync, chmodSync, constants, lstatSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
5
- import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
- 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";
7
- 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";
8
- import { buildCacheRoot } from "@stim-cli/core";
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";
9
5
  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";
10
- import { tmpdir } from "node:os";
11
- //#region src/temporary.ts
12
- function existingPath(path) {
13
- const missing = [];
14
- let current = resolve(path);
15
- while (!lstatSync(current, { throwIfNoEntry: false })) {
16
- missing.unshift(basename(current));
17
- current = dirname(current);
18
- }
19
- const existing = realpathSync(current);
20
- return {
21
- existing,
22
- resolved: join(existing, ...missing)
23
- };
24
- }
25
- function filesystemDevice(path) {
26
- return statSync(existingPath(path).existing).dev;
27
- }
28
- function outsideWorkingTree(path) {
29
- let current = path;
30
- while (true) {
31
- if (lstatSync(join(current, ".git"), { throwIfNoEntry: false })) return false;
32
- const parent = dirname(current);
33
- if (parent === current) return true;
34
- current = parent;
35
- }
36
- }
37
- function inside(parent, path) {
38
- const rel = relative(parent, path);
39
- return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
40
- }
41
- function temporaryRoot(near) {
42
- const reference = existingPath(near);
43
- const insideReference = (path) => inside(reference.resolved, path);
44
- const override = process.env.STIM_TMPDIR ?? loadConfig$1()?.tempDir;
45
- if (override !== void 0) {
46
- if (typeof override !== "string" || !isAbsolute(override)) throw new Error("STIM_TMPDIR / tempDir must be an absolute directory path.");
47
- const { existing, resolved } = existingPath(override);
48
- if (!statSync(existing).isDirectory() || !outsideWorkingTree(existing)) throw new Error(`Temporary directory ${override} must be outside Git working trees.`);
49
- if (insideReference(resolved)) throw new Error(`Temporary directory ${override} must not be inside ${near}.`);
50
- accessSync(existing, constants.W_OK);
51
- return resolved;
52
- }
53
- const { existing } = reference;
54
- const cache = existingPath(buildCacheRoot()).resolved;
55
- const device = statSync(existing).dev;
56
- const candidates = [tmpdir()];
57
- let current = existing === reference.resolved || !statSync(existing).isDirectory() ? dirname(existing) : existing;
58
- while (statSync(current).dev === device) {
59
- candidates.push(current);
60
- const parent = dirname(current);
61
- if (parent === current) break;
62
- current = parent;
63
- }
64
- for (const candidate of candidates) try {
65
- const path = realpathSync(candidate);
66
- if (statSync(path).dev !== device || insideReference(path) || inside(cache, path) || !outsideWorkingTree(path)) continue;
67
- accessSync(path, constants.W_OK);
68
- return path;
69
- } catch {}
70
- 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.`);
71
- }
72
- function makeTemporaryDirectory(near, prefix) {
73
- const root = temporaryRoot(near);
74
- mkdirSync(root, {
75
- recursive: true,
76
- mode: 448
77
- });
78
- return mkdtempSync(join(root, prefix));
79
- }
80
- function removeTemporaryEntry(path) {
81
- const stat = lstatSync(path, { throwIfNoEntry: false });
82
- if (stat?.isDirectory()) {
83
- chmodSync(path, stat.mode | 448);
84
- for (const entry of readdirSync(path, { withFileTypes: true })) if (entry.isDirectory()) removeTemporaryEntry(join(path, entry.name));
85
- }
86
- rmSync(path, {
87
- recursive: true,
88
- force: true
89
- });
90
- }
91
- //#endregion
92
- //#region src/workspace/worktree.ts
93
- const CARRY_SKIP_BASENAMES = /* @__PURE__ */ new Set([
94
- ".DerivedData",
95
- ".DS_Store",
96
- ".idea",
97
- ".jj"
98
- ]);
99
- function isCarrySkipped(rel) {
100
- return /(^|\/)android\/build\/generated\/autolinking(\/|$)/.test(rel) || String(rel).split("/").some((seg) => CARRY_SKIP_BASENAMES.has(seg));
101
- }
102
- function nativePath(path) {
103
- return sep$1 === "/" ? path : path.replaceAll("/", sep$1);
104
- }
105
- function gitCommonDir(cwd) {
106
- const out = getExecutor().runFileQuiet("git", [
107
- "-C",
108
- cwd,
109
- "rev-parse",
110
- "--path-format=absolute",
111
- "--git-common-dir"
112
- ]);
113
- return out ? nativePath(out.trim()) : null;
114
- }
115
- function repoRoot(cwd) {
116
- const out = getExecutor().runFileQuiet("git", [
117
- "-C",
118
- cwd,
119
- "rev-parse",
120
- "--show-toplevel"
121
- ]);
122
- return out ? nativePath(out.trim()) : null;
123
- }
124
- function locallyKnownUpstream(projectRoot) {
125
- try {
126
- const name = getExecutor().runFile("git", [
127
- "-C",
128
- projectRoot,
129
- "rev-parse",
130
- "--abbrev-ref",
131
- "--symbolic-full-name",
132
- "@{upstream}"
133
- ], { timeoutMs: 5e3 });
134
- const counts = getExecutor().runFile("git", [
135
- "-C",
136
- projectRoot,
137
- "rev-list",
138
- "--left-right",
139
- "--count",
140
- "HEAD...@{upstream}"
141
- ], { timeoutMs: 5e3 }).trim().split(/\s+/).map(Number);
142
- const ahead = counts[0] ?? NaN;
143
- const behind = counts[1] ?? NaN;
144
- if (!name || !Number.isInteger(ahead) || !Number.isInteger(behind)) return null;
145
- return {
146
- name,
147
- ahead,
148
- behind
149
- };
150
- } catch {
151
- return null;
152
- }
153
- }
154
- function warmWorktreePaths(cwd) {
155
- const currentRoot = repoRoot(cwd);
156
- if (!currentRoot) throw new Error("Not a git repository.");
157
- const target = realpathSync$1(currentRoot);
158
- const source = resolveSourceCheckout(target);
159
- if ("refusal" in source) throw new Error(source.refusal);
160
- if (!source.entries.find((entry) => canonicalPath(entry.path) === target)) throw new Error("Could not identify the linked worktree and its source checkout.");
161
- const root = realpathSync$1(source.path);
162
- if (root === target) throw new Error("Run stim worktree warm from a linked worktree, not the source checkout.");
163
- const sourceRoot = repoRoot(root);
164
- const sourceCommon = gitCommonDir(root);
165
- const targetCommon = gitCommonDir(target);
166
- 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.");
167
- return {
168
- root,
169
- target,
170
- common: realpathSync$1(targetCommon)
171
- };
172
- }
173
- function matchesInclude(path, patterns) {
174
- for (const pattern of patterns || []) {
175
- const rooted = pattern.startsWith("/");
176
- const escaped = (rooted ? pattern.slice(1) : pattern).replace(/[.+^${}()|[\]\\?]/g, "\\$&").replace(/\*\*\//g, "::GLOBSTAR::").replace(/\*/g, "[^/]+").replace(/::GLOBSTAR::/g, "(?:.*/)?").replace(/\\\?/g, "[^/]");
177
- if (new RegExp(`${rooted ? "^" : "(^|/)"}${escaped}$`).test(path)) return true;
178
- }
179
- return false;
180
- }
181
- function readWorktreeExclude(root) {
182
- return readPatternFile(join$1(root, ".worktreeexclude"));
183
- }
184
- function readPatternFile(p) {
185
- if (!existsSync$1(p)) return null;
186
- return readFileSync$1(p, "utf-8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
187
- }
188
- function canonicalPath(path) {
189
- try {
190
- return realpathSync$1(path);
191
- } catch {
192
- return resolve$1(path);
193
- }
194
- }
195
- function nestedWorktreePaths(root) {
196
- const source = canonicalPath(root);
197
- const paths = /* @__PURE__ */ new Set();
198
- const out = getExecutor().runFileQuiet("git", [
199
- "-C",
200
- root,
201
- "worktree",
202
- "list",
203
- "--porcelain"
204
- ]);
205
- if (out === null) throw new Error("Could not list Git worktrees. Refusing to carry ignored files.");
206
- for (const entry of parseWorktrees(out)) {
207
- const rel = relative$1(source, canonicalPath(entry.path));
208
- if (!rel || rel === ".." || rel.startsWith(`..${sep$1}`) || isAbsolute$1(rel)) continue;
209
- paths.add(rel.split(sep$1).join("/"));
210
- }
211
- return [...paths];
212
- }
213
- function overlapsNestedWorktree(rel, nestedPaths) {
214
- const path = String(rel).replaceAll("\\", "/").replace(/^\.\//, "").replace(/\/$/, "");
215
- return nestedPaths.some((nested) => path === nested || path.startsWith(`${nested}/`) || nested.startsWith(`${path}/`));
216
- }
217
- function listTrackedPaths(dir) {
218
- const out = getExecutor().runFileQuiet("git", [
219
- "-C",
220
- dir,
221
- "ls-files",
222
- "-z"
223
- ]);
224
- if (out === null) return null;
225
- return out.split("\0").filter(Boolean);
226
- }
227
- function trackedGuard(dir) {
228
- const paths = listTrackedPaths(dir);
229
- if (paths === null) return {
230
- known: false,
231
- covers: () => false
232
- };
233
- const entries = new Set(paths);
234
- const covered = new Set(paths);
235
- for (const p of paths) for (let i = p.indexOf("/"); i !== -1; i = p.indexOf("/", i + 1)) covered.add(p.slice(0, i));
236
- return {
237
- known: true,
238
- covers: (rel) => {
239
- if (covered.has(rel)) return true;
240
- for (let i = rel.indexOf("/"); i !== -1; i = rel.indexOf("/", i + 1)) if (entries.has(rel.slice(0, i))) return true;
241
- return false;
242
- }
243
- };
244
- }
245
- function listGitignoredEntries(root) {
246
- const args = [
247
- "-C",
248
- root,
249
- "ls-files",
250
- "--others",
251
- "--ignored",
252
- "--exclude-standard",
253
- "--directory",
254
- "--no-empty-directory",
255
- "-z"
256
- ];
257
- const out = getExecutor().runFile("git", args);
258
- if (!out) return [];
259
- return out.split("\0").filter(Boolean).map((e) => e.endsWith("/") ? e.slice(0, -1) : e);
260
- }
261
- function listCarryableIgnoredEntries(root, patterns) {
262
- const nested = nestedWorktreePaths(root);
263
- return listGitignoredEntries(root).filter((rel) => !isCarrySkipped(rel) && !overlapsNestedWorktree(rel, nested) && !matchesInclude(rel, patterns));
264
- }
265
- function missingDestinationReason(target, rel) {
266
- const parts = rel.split("/");
267
- for (let i = 1; i < parts.length; i++) {
268
- const parent = parts.slice(0, i).join("/");
269
- const stat = lstatSync$1(join$1(target, parent), { throwIfNoEntry: false });
270
- if (stat?.isSymbolicLink()) return `symlink ancestor: ${parent}`;
271
- if (stat && !stat.isDirectory()) return `non-directory ancestor: ${parent}`;
272
- }
273
- return lstatSync$1(join$1(target, rel), { throwIfNoEntry: false }) ? "exists" : null;
274
- }
275
- function removeCopiedExclusions(path, rel) {
276
- const entries = readdirSync$1(path, { withFileTypes: true });
277
- const excluded = entries.filter((entry) => isCarrySkipped(`${rel}/${entry.name}`));
278
- if (excluded.length > 0) {
279
- const stat = lstatSync$1(path);
280
- chmodSync$1(path, stat.mode | 448);
281
- try {
282
- for (const entry of excluded) removeTemporaryEntry(join$1(path, entry.name));
283
- } finally {
284
- utimesSync$1(path, stat.atime, stat.mtime);
285
- chmodSync$1(path, stat.mode);
286
- }
287
- }
288
- for (const entry of entries) {
289
- const child = `${rel}/${entry.name}`;
290
- if (entry.isDirectory() && !isCarrySkipped(child)) removeCopiedExclusions(join$1(path, entry.name), child);
291
- }
292
- }
293
- function cloneIgnoredEntries({ root, target, patterns }) {
294
- const copied = [];
295
- const skipped = [];
296
- const failed = [];
297
- let cloned = true;
298
- const guard = trackedGuard(target);
299
- if (!guard.known) throw new Error("Could not list the destination's tracked files.");
300
- const nested = nestedWorktreePaths(target);
301
- for (const rel of listCarryableIgnoredEntries(root, patterns)) {
302
- const from = join$1(root, rel);
303
- const to = join$1(target, rel);
304
- try {
305
- const reason = guard.covers(rel) ? "tracked" : overlapsNestedWorktree(rel, nested) ? "nested worktree" : missingDestinationReason(target, rel);
306
- if (reason) {
307
- skipped.push({
308
- file: rel,
309
- reason
310
- });
311
- continue;
312
- }
313
- mkdirSync$1(dirname$1(to), { recursive: true });
314
- try {
315
- getExecutor().runFile("cp", [
316
- "-Rc",
317
- from,
318
- to
319
- ]);
320
- } catch {
321
- removeTemporaryEntry(to);
322
- getExecutor().runFile("cp", [
323
- "-R",
324
- from,
325
- to
326
- ]);
327
- cloned = false;
328
- }
329
- if (lstatSync$1(to).isDirectory()) removeCopiedExclusions(to, rel);
330
- copied.push(rel);
331
- } catch (e) {
332
- failed.push({
333
- file: rel,
334
- error: String(e?.message || e)
335
- });
336
- }
337
- }
338
- return {
339
- copied,
340
- skipped,
341
- failed,
342
- cloned
343
- };
344
- }
345
- function podsOutOfSync(target, copiedEntries, { read = readFileSync$1 } = {}) {
346
- const problems = [];
347
- for (const rel of copiedEntries || []) {
348
- if (rel !== "Pods" && !rel.endsWith("/Pods")) continue;
349
- const iosDir = rel === "Pods" ? "" : rel.slice(0, -5);
350
- const manifest = join$1(target, rel, "Manifest.lock");
351
- const podfileLock = join$1(target, iosDir, "Podfile.lock");
352
- if (!existsSync$1(manifest)) continue;
353
- if (!existsSync$1(podfileLock)) {
354
- problems.push({
355
- dir: iosDir || ".",
356
- reason: "missing"
357
- });
358
- continue;
359
- }
360
- try {
361
- if (read(manifest, "utf-8") !== read(podfileLock, "utf-8")) problems.push({
362
- dir: iosDir || ".",
363
- reason: "mismatch"
364
- });
365
- } catch {}
366
- }
367
- return problems;
368
- }
369
- const LOCKFILE_NAMES = [
370
- "pnpm-lock.yaml",
371
- "yarn.lock",
372
- "bun.lock",
373
- "bun.lockb",
374
- "package-lock.json"
375
- ];
376
- function npmInstallMatches(wanted, installed) {
377
- if (!wanted.packages || !installed.packages) return null;
378
- for (const [key, entry] of Object.entries(wanted.packages)) {
379
- if (!key.includes("node_modules/") || entry.link) continue;
380
- const present = installed.packages[key];
381
- if (!present && (entry.optional || entry.devOptional)) continue;
382
- if (present?.version !== entry.version) return false;
383
- }
384
- return true;
385
- }
386
- function lastYamlDocument(text) {
387
- return (text.split(/^---$/m).at(-1) ?? "").trim();
388
- }
389
- function yarnClassicInstallMatches(lockfile, integrity) {
390
- if (!integrity.lockfileEntries) return null;
391
- const wanted = [...lockfile.matchAll(/^ {2}resolved "([^"]+)"$/gm)].flatMap((m) => m[1] ?? []);
392
- if (wanted.length === 0) return null;
393
- const installed = new Set(Object.values(integrity.lockfileEntries));
394
- return wanted.every((url) => installed.has(url));
395
- }
396
- function yarnBerryInstallMatches(lockfile, state) {
397
- const installed = new Set([...state.matchAll(/^"?([^\s"#][^"]*?)"?:$/gm)].flatMap((m) => m[1]?.replace(/@virtual:[^#]+#/, "@") ?? []));
398
- let entries = 0;
399
- for (const entry of lockfile.split(/\n(?=\S)/)) {
400
- const resolution = /^ {2}resolution: "([^"]+)"$/m.exec(entry)?.[1];
401
- if (!resolution) continue;
402
- entries += 1;
403
- if (installed.has(resolution) || /^ {2}conditions: /m.test(entry)) continue;
404
- return false;
405
- }
406
- return entries === 0 ? null : true;
407
- }
408
- function installedMatchesLockfile(dir, lockfile, { read = readFileSync$1 } = {}) {
409
- const text = (rel) => {
410
- try {
411
- return read(join$1(dir, rel), "utf-8").replaceAll("\r\n", "\n");
412
- } catch {
413
- return null;
414
- }
415
- };
416
- const wanted = text(lockfile);
417
- if (wanted === null) return null;
418
- try {
419
- if (lockfile === "package-lock.json") {
420
- const installed = text("node_modules/.package-lock.json");
421
- return installed === null ? null : npmInstallMatches(JSON.parse(wanted), JSON.parse(installed));
422
- }
423
- if (lockfile === "pnpm-lock.yaml") {
424
- const installed = text("node_modules/.pnpm/lock.yaml");
425
- return installed === null ? null : lastYamlDocument(wanted) === lastYamlDocument(installed);
426
- }
427
- if (lockfile === "yarn.lock") {
428
- if (/^__metadata:$/m.test(wanted)) {
429
- const berry = text("node_modules/.yarn-state.yml");
430
- return berry === null ? null : yarnBerryInstallMatches(wanted, berry);
431
- }
432
- const classic = text("node_modules/.yarn-integrity");
433
- return classic === null ? null : yarnClassicInstallMatches(wanted, JSON.parse(classic));
434
- }
435
- } catch {}
436
- return null;
437
- }
438
- function depsOutOfSync(root, target, copiedEntries, { read = readFileSync$1 } = {}) {
439
- const problems = [];
440
- for (const rel of copiedEntries || []) {
441
- if (rel !== "node_modules" && !rel.endsWith("/node_modules")) continue;
442
- const dir = rel === "node_modules" ? "" : rel.slice(0, -13);
443
- const name = LOCKFILE_NAMES.find((candidate) => existsSync$1(join$1(target, dir, candidate)));
444
- if (!name) continue;
445
- const installed = installedMatchesLockfile(join$1(target, dir), name, { read });
446
- if (installed === false) {
447
- problems.push({
448
- dir: dir || ".",
449
- lockfile: name,
450
- reason: "installed"
451
- });
452
- continue;
453
- }
454
- const source = join$1(root, dir, name);
455
- if (installed === true || !existsSync$1(source)) continue;
456
- try {
457
- if (read(source, "utf-8") !== read(join$1(target, dir, name), "utf-8")) problems.push({
458
- dir: dir || ".",
459
- lockfile: name,
460
- reason: "lockfile"
461
- });
462
- } catch {}
463
- }
464
- return problems;
465
- }
466
- const FINGERPRINT_INPUT_FILES = [
467
- "app.json",
468
- "app.config.ts",
469
- "app.config.js",
470
- "app.config.mjs",
471
- "package.json"
472
- ];
473
- function dirtyFingerprintFiles(root) {
474
- const out = getExecutor().runFileQuiet("git", [
475
- "-C",
476
- root,
477
- "status",
478
- "--porcelain",
479
- "--",
480
- ...FINGERPRINT_INPUT_FILES
481
- ]);
482
- if (out === null || out.trim() === "") return [];
483
- return out.split("\n").map((line) => normalizePorcelainLine(line.trimEnd())).filter((line) => line !== "").map((line) => line.slice(3).trim()).filter((path) => path !== "");
484
- }
485
- function hasUncommittedWork(dir) {
486
- const out = getExecutor().runFileQuiet("git", [
487
- "--no-optional-locks",
488
- "-C",
489
- dir,
490
- "status",
491
- "--porcelain"
492
- ]);
493
- if (out === null) return null;
494
- return out.trim().length > 0;
495
- }
496
- function dirtyPaths(dir, { limit = 10 } = {}) {
497
- const out = getExecutor().runFileQuiet("git", [
498
- "--no-optional-locks",
499
- "-C",
500
- dir,
501
- "status",
502
- "--porcelain"
503
- ]);
504
- if (out === null) return [];
505
- return out.split("\n").map((l) => normalizePorcelainLine(l.trimEnd())).filter(Boolean).slice(0, limit);
506
- }
507
- function normalizePorcelainLine(line) {
508
- if (line === "" || line[2] === " ") return line;
509
- return ` ${line}`;
510
- }
511
- function restoreFile(dir, file) {
512
- return getExecutor().runFileQuiet("git", [
513
- "-C",
514
- dir,
515
- "checkout",
516
- "--",
517
- file
518
- ]) !== null;
519
- }
520
- function isPodInstallChurn(paths) {
521
- if (!paths || paths.length === 0) return false;
522
- return paths.every((line) => /(?:^|\/)(?:Podfile\.lock|project\.pbxproj)$/.test(line.slice(3).trim()));
523
- }
524
- const SAFE_BRANCH_NAME = /^[A-Za-z0-9@._/-]+$/;
525
- function unpushedCommits(dir) {
526
- const exec = getExecutor();
527
- const branch = exec.runFileQuiet("git", [
528
- "-C",
529
- dir,
530
- "symbolic-ref",
531
- "--quiet",
532
- "--short",
533
- "HEAD"
534
- ]);
535
- const own = branch === null ? "" : branch.trim();
536
- const protection = own && SAFE_BRANCH_NAME.test(own) ? [
537
- "--remotes",
538
- `--exclude=${own}`,
539
- "--branches"
540
- ] : ["--remotes"];
541
- if (!own && exec.runFileQuiet("git", [
542
- "-C",
543
- dir,
544
- "rev-parse",
545
- "--abbrev-ref",
546
- "HEAD"
547
- ]) === "HEAD") protection.push("--branches");
548
- const out = exec.runFileQuiet("git", [
549
- "-C",
550
- dir,
551
- "log",
552
- "--oneline",
553
- "HEAD",
554
- "--not",
555
- ...protection
556
- ]);
557
- if (out === null) return null;
558
- return out.split("\n").map((l) => l.trim()).filter(Boolean);
559
- }
560
- function hasRemote(dir) {
561
- const out = getExecutor().runFileQuiet("git", [
562
- "-C",
563
- dir,
564
- "remote"
565
- ]);
566
- return Boolean(out && out.trim().length > 0);
567
- }
568
- function branchExists(cwd, branch) {
569
- const out = getExecutor().runFileQuiet("git", [
570
- "-C",
571
- cwd,
572
- "rev-parse",
573
- "--verify",
574
- "--quiet",
575
- `refs/heads/${branch}`
576
- ]);
577
- return Boolean(out);
578
- }
579
- function resolveFullRef(cwd, ref) {
580
- try {
581
- const out = getExecutor().runFile("git", [
582
- "-C",
583
- cwd,
584
- "rev-parse",
585
- "--verify",
586
- "--quiet",
587
- "--end-of-options",
588
- `${ref}^{commit}`
589
- ]);
590
- return out && out.trim() ? out.trim() : null;
591
- } catch {
592
- return null;
593
- }
594
- }
595
- function removeWorktree(path, { from, force = false, platform = process.platform }) {
596
- const args = [
597
- ...platform === "win32" ? ["-c", "core.longpaths=true"] : [],
598
- "-C",
599
- from,
600
- "worktree",
601
- "remove",
602
- ...force ? ["--force"] : [],
603
- "--",
604
- path
605
- ];
606
- getExecutor().runFile("git", args);
607
- }
608
- function deleteBranch(cwd, branch, expectedSha) {
609
- if (!SAFE_BRANCH_NAME.test(branch) || branch.startsWith("-")) throw new Error(`Refusing branch ${JSON.stringify(branch)}: it is not a safe local branch name.`);
610
- getExecutor().runFile("git", [
611
- "-C",
612
- cwd,
613
- "update-ref",
614
- "-d",
615
- `refs/heads/${branch}`,
616
- expectedSha
617
- ]);
618
- }
619
- function parseWorktrees(out) {
620
- const entries = [];
621
- let current = {};
622
- for (const line of out.split("\n")) if (line.startsWith("worktree ")) {
623
- if (current.path) entries.push(current);
624
- current = { path: nativePath(line.slice(9)) };
625
- } else if (line.startsWith("branch ")) current.branch = line.slice(7).replace("refs/heads/", "");
626
- else if (line === "prunable" || line.startsWith("prunable ")) current.prunable = true;
627
- else if (line === "locked" || line.startsWith("locked ")) current.locked = true;
628
- else if (line === "bare") current.bare = true;
629
- if (current.path) entries.push(current);
630
- return entries;
631
- }
632
- function hasPopulatedSubmodules(worktree) {
633
- const modules = getExecutor().runFileQuiet("git", [
634
- "-C",
635
- worktree,
636
- "rev-parse",
637
- "--git-path",
638
- "modules"
639
- ]);
640
- if (modules && existsSync$1(resolve$1(worktree, nativePath(modules)))) return true;
641
- return (getExecutor().runFileQuiet("git", [
642
- "-C",
643
- worktree,
644
- "ls-files",
645
- "--stage",
646
- "-z"
647
- ]) ?? "").split("\0").some((line) => line.startsWith("160000 ") && existsSync$1(join$1(worktree, line.slice(line.indexOf(" ") + 1), ".git")));
648
- }
649
- function listWorktrees(cwd) {
650
- const out = getExecutor().runFileQuiet("git", [
651
- "-C",
652
- cwd,
653
- "worktree",
654
- "list",
655
- "--porcelain"
656
- ]);
657
- return out ? parseWorktrees(out) : [];
658
- }
659
- function branchOf(head) {
660
- return head.startsWith("ref: refs/heads/") ? head.slice(16) : void 0;
661
- }
662
- /**
663
- * The linked worktrees recorded under a git common dir, read from `worktrees/<id>/gitdir` and `HEAD` without running
664
- * git or touching the worktree directories, sorted by path. The worktree with the branch the common dir's own `HEAD`
665
- * names (the main checkout's branch, or a bare repository's source checkout) is left out.
666
- */
667
- function linkedWorktreesOnDisk(commonDir) {
668
- const admin = join$1(commonDir, "worktrees");
669
- let ids;
670
- let sourceBranch;
671
- try {
672
- ids = readdirSync$1(admin);
673
- sourceBranch = branchOf(readFileSync$1(join$1(commonDir, "HEAD"), "utf-8").trim());
674
- } catch {
675
- return [];
676
- }
677
- return ids.flatMap((id) => {
678
- try {
679
- const gitdir = readFileSync$1(join$1(admin, id, "gitdir"), "utf-8").trim();
680
- const branch = branchOf(readFileSync$1(join$1(admin, id, "HEAD"), "utf-8").trim());
681
- if (branch && branch === sourceBranch) return [];
682
- const path = dirname$1(resolve$1(admin, id, nativePath(gitdir)));
683
- return [branch ? {
684
- path,
685
- branch
686
- } : { path }];
687
- } catch {
688
- return [];
689
- }
690
- }).toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
691
- }
692
- /**
693
- * The git common dir of the repository containing `start`, read from `.git` and `commondir` files without running
694
- * git. Returns null when `start` is missing, unreadable, or not inside a repository.
695
- */
696
- function gitCommonDirOnDisk(start) {
697
- try {
698
- for (let dir = realpathSync$1.native(start);; dir = dirname$1(dir)) {
699
- const dotGit = join$1(dir, ".git");
700
- if (existsSync$1(dotGit)) {
701
- if (statSync$1(dotGit).isDirectory()) return realpathSync$1.native(dotGit);
702
- const gitdir = /^gitdir: (.+)$/m.exec(readFileSync$1(dotGit, "utf-8"))?.[1]?.trim();
703
- if (!gitdir) return null;
704
- const linked = resolve$1(dir, gitdir);
705
- const commondir = join$1(linked, "commondir");
706
- return realpathSync$1.native(existsSync$1(commondir) ? resolve$1(linked, readFileSync$1(commondir, "utf-8").trim()) : linked);
707
- }
708
- if (dirname$1(dir) === dir) return null;
709
- }
710
- } catch {
711
- return null;
712
- }
713
- }
714
- function selectSourceCheckout(entries, bareHead) {
715
- const first = entries[0];
716
- if (!first) return { refusal: "Git lists no worktrees for this repository." };
717
- if (!first.bare) return { path: first.path };
718
- const bare = first.path;
719
- const checkouts = entries.filter((entry) => !entry.bare && !entry.prunable);
720
- const listed = checkouts.map((entry) => `${entry.branch ?? "detached"} (${entry.path})`).join(", ") || "none";
721
- const pointHead = ` git -C ${bare} symbolic-ref HEAD refs/heads/<branch>`;
722
- 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}` };
723
- const matches = checkouts.filter((entry) => entry.branch === bareHead);
724
- const [only] = matches;
725
- if (only && matches.length === 1) return { path: only.path };
726
- if (!only) {
727
- const stale = entries.find((entry) => entry.prunable && entry.branch === bareHead);
728
- const beside = checkouts[0] ? dirname$1(checkouts[0].path) : bare;
729
- 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}` };
730
- }
731
- 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}` };
732
- }
733
- function bareHeadBranch(bare) {
734
- const out = getExecutor().runFileQuiet("git", [
735
- "-C",
736
- bare,
737
- "symbolic-ref",
738
- "--quiet",
739
- "HEAD"
740
- ])?.trim();
741
- return out?.startsWith("refs/heads/") ? out.slice(11) : null;
742
- }
743
- function sourceCheckoutOf(entries) {
744
- const first = entries[0];
745
- return selectSourceCheckout(entries, first?.bare ? bareHeadBranch(first.path) : null);
746
- }
747
- function resolveSourceCheckout(cwd) {
748
- const entries = listWorktrees(cwd);
749
- return {
750
- entries,
751
- ...sourceCheckoutOf(entries)
752
- };
753
- }
754
- //#endregion
6
+ import { existsSync, readFileSync, realpathSync, statSync } from "fs";
7
+ import { createHash } from "node:crypto";
755
8
  //#region src/optimizations.ts
756
9
  function compilerCacheFallbackMessage({ fallback, compilerCache, file = null }) {
757
10
  const origin = fallback.fromEnvironment ? "the environment" : file;
@@ -1094,15 +347,15 @@ function androidAvdConfigSetting(settings, settingsRoot) {
1094
347
  if ("avdConfigFile" in android) {
1095
348
  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.");
1096
349
  try {
1097
- const root = realpathSync$1(settingsRoot);
350
+ const root = realpathSync(settingsRoot);
1098
351
  const candidate = resolve$1(root, android.avdConfigFile);
1099
352
  if (pathEscapesRoot(root, candidate)) throw new Error("path escapes the settings root");
1100
- const path = realpathSync$1(candidate);
353
+ const path = realpathSync(candidate);
1101
354
  if (pathEscapesRoot(root, path)) throw new Error("symlink target escapes the settings root");
1102
- const stat = statSync$1(path);
355
+ const stat = statSync(path);
1103
356
  if (!stat.isFile()) throw new Error("path is not a regular file");
1104
357
  if (stat.size > 65536) throw new Error("file exceeds 64 KiB");
1105
- const contents = readFileSync$1(path, "utf8");
358
+ const contents = readFileSync(path, "utf8");
1106
359
  if (Buffer.byteLength(contents) > 65536) throw new Error("file exceeds 64 KiB");
1107
360
  entries = parseAndroidAvdConfigIni(contents);
1108
361
  } catch (error) {
@@ -1131,12 +384,12 @@ function iosSimSlimProfileSetting(settings, settingsRoot) {
1131
384
  const value = settings.ios.simslimProfile;
1132
385
  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.");
1133
386
  try {
1134
- const root = realpathSync$1(settingsRoot);
387
+ const root = realpathSync(settingsRoot);
1135
388
  const candidate = resolve$1(root, value);
1136
389
  if (pathEscapesRoot(root, candidate)) throw new Error("path escapes the settings root");
1137
- const path = realpathSync$1(candidate);
390
+ const path = realpathSync(candidate);
1138
391
  if (pathEscapesRoot(root, path)) throw new Error("symlink target escapes the settings root");
1139
- const stat = statSync$1(path);
392
+ const stat = statSync(path);
1140
393
  if (!stat.isFile()) throw new Error("path is not a regular file");
1141
394
  if (stat.size > 65536) throw new Error("file exceeds 64 KiB");
1142
395
  return path;
@@ -1198,9 +451,9 @@ function unknownSettingKeys(settings, prefix = "") {
1198
451
  function readCommittedSettings(directory) {
1199
452
  if (!directory) return {};
1200
453
  const p = join$1(directory, ".stim.json");
1201
- if (!existsSync$1(p)) return {};
454
+ if (!existsSync(p)) return {};
1202
455
  try {
1203
- const parsed = JSON.parse(readFileSync$1(p, "utf-8"));
456
+ const parsed = JSON.parse(readFileSync(p, "utf-8"));
1204
457
  return isPlainObject(parsed) ? parsed : {};
1205
458
  } catch {
1206
459
  return {};
@@ -1369,6 +622,14 @@ function deviceIdleShutdownMinutesSetting(settings) {
1369
622
  function deviceReclaimIdleMinutesSetting(settings) {
1370
623
  return minutesSetting(settings, "devices", "reclaimIdleMinutes");
1371
624
  }
625
+ function projectMaintenancePinned(root) {
626
+ try {
627
+ const value = settingValueAt(settingsForProject(root), "maintenance.keep");
628
+ return value !== void 0 && value !== false;
629
+ } catch {
630
+ return true;
631
+ }
632
+ }
1372
633
  function projectDeviceReclaimIdleMinutes(root) {
1373
634
  return deviceReclaimIdleMinutesSetting(settingsForProject(root));
1374
635
  }
@@ -1437,4 +698,4 @@ function webSettings(settings) {
1437
698
  };
1438
699
  }
1439
700
  //#endregion
1440
- export { cloneIgnoredEntries as $, readCommittedSettings as A, settingsLayers as B, metroWarmupUrlSetting as C, filesystemDevice as Ct, projectMetroSharedCache as D, projectDeviceReclaimIdleMinutes as E, temporaryRoot as Et, settingFile as F, detectProviders as G, unknownSettingKeys as H, settingOrigin as I, artifactCachePolicy as J, planMetroReach as K, settingOriginScope as L, remoteIosSetting as M, resolveCacheProviderConfig as N, projectOptimizations as O, resolveSettings as P, branchExists as Q, settingShapeErrors as R, metroTunnelSettingError as S, warmWorktreePaths as St, parseIosRemote as T, removeTemporaryEntry as Tt, webSettings as U, tunnelModeSetting as V, PUBLIC_METRO_ENV as W, optimizationBuildProfile as X, compilerCacheFallbackMessage as Y, resolveOptimizations as Z, iosSigningIdentitySha1SettingError as _, resolveFullRef as _t, androidAvdConfigSetting as a, gitCommonDirOnDisk as at, metroIdleStopMinutesSetting as b, sourceCheckoutOf as bt, androidDataPartitionSizeGbSetting as c, hasUncommittedWork as ct, deviceIdleShutdownMinutesSetting as d, listWorktrees as dt, deleteBranch as et, iosLanHostSetting as f, locallyKnownUpstream as ft, iosSigningIdentitySha1Setting as g, repoRoot as gt, iosSigningIdentitySettingError as h, removeWorktree as ht, SETTING_SHAPE_REMEDY as i, gitCommonDir as it, remoteAndroidSetting as j, publicUrlSetting as k, androidDataPartitionSizeGbSettingError as l, isPodInstallChurn as lt, iosSigningIdentitySetting as m, readWorktreeExclude as mt, PATH_SETTINGS as n, dirtyFingerprintFiles as nt, androidAvdConfigSettingError as o, hasPopulatedSubmodules as ot, iosLanHostSettingError as p, podsOutOfSync as pt, resolveTailscaleBinary as q, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as r, dirtyPaths as rt, androidDataPartitionSizeBytes as s, hasRemote as st, ANDROID_AVD_CONFIG_HELP as t, depsOutOfSync as tt, cacheProviderSettingError as u, linkedWorktreesOnDisk as ut, iosSimSlimProfileSetting as v, resolveSourceCheckout as vt, ngrokUrlSetting as w, makeTemporaryDirectory as wt, metroPortSetting as x, unpushedCommits as xt, mergeSettingsLayers as y, restoreFile as yt, settingValueAt as z };
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 };