stim 1.26.0 → 1.28.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 (172) hide show
  1. package/dist/{acquire-artifact-DVsvSwf7.mjs → acquire-artifact-CKByBnTD.mjs} +2 -2
  2. package/dist/{act-C-BqJEpu.mjs → act-8iswyfRa.mjs} +319 -126
  3. package/dist/{activity-Lnb_EoRY.mjs → activity-DRMg4_mD.mjs} +6 -6
  4. package/dist/{agent-device-usage-output-DbXy5tg8.mjs → agent-device-usage-output-tE90fDdo.mjs} +5 -5
  5. package/dist/{android-CiNQw3kq.mjs → android-CHmSU4B4.mjs} +101 -45
  6. package/dist/{android-DTAcRwBC.mjs → android-CsPs-7Mg.mjs} +23 -18
  7. package/dist/{android-B5P81yI-.mjs → android-D577ApKG.mjs} +37 -15
  8. package/dist/{android-CSbLRD53.mjs → android-YWCbmkVK.mjs} +5 -5
  9. package/dist/{android-cas-BTVhZ0Qs.mjs → android-cas-_aDifWW0.mjs} +4 -4
  10. package/dist/android-cas-compiler.mjs +1 -1
  11. package/dist/api.d.mts +14 -4
  12. package/dist/api.mjs +39 -29
  13. package/dist/{apk-signed-tail-B46U9hXc.mjs → apk-signed-tail-CQbwM0qO.mjs} +2 -2
  14. package/dist/{artifact-CsAP6AGK.mjs → artifact-DYtHjxsn.mjs} +19 -24
  15. package/dist/{artifact-BxREhAaV.mjs → artifact-bFkfD3vf.mjs} +18 -23
  16. package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
  17. package/dist/auto-placement-BVqs8AJi.mjs +350 -0
  18. package/dist/{browser-web-rYPyqhTf.mjs → browser-web-BUaLcafY.mjs} +16 -16
  19. package/dist/{build-DPhApsjV.mjs → build-cQURy_KW.mjs} +35 -31
  20. package/dist/{build-cache-DrXNCy3T.mjs → build-cache-CZULpXVl.mjs} +43 -21
  21. package/dist/{build-plan-DrMMdayj.mjs → build-plan-CxoYfxsc.mjs} +7 -6
  22. package/dist/{cache-manifest-BEZ9Bpl1.mjs → cache-manifest-DEjqGGat.mjs} +1 -1
  23. package/dist/cache-manifest.mjs +1 -1
  24. package/dist/{budget-k2mZGvvk.mjs → ccache-Bm_A1xX9.mjs} +562 -1604
  25. package/dist/{cdp-BG3FJCCx.mjs → cdp-C3svvXiE.mjs} +1 -1
  26. package/dist/{chrome-BvV8ssI3.mjs → chrome-DyDWurWG.mjs} +1 -1
  27. package/dist/{cli-BBKFGOFl.mjs → cli-CpbaLDa7.mjs} +24 -23
  28. package/dist/cli.mjs +1 -1
  29. package/dist/{client-D9CaRks-.mjs → client-YxCer6ab.mjs} +84 -65
  30. package/dist/collector-run.d.mts +10 -9
  31. package/dist/collector-run.mjs +42 -27
  32. package/dist/{command-output-BF5AR2dL.mjs → command-output-C8R1KIvi.mjs} +1 -1
  33. package/dist/{config-BktkY_zC.mjs → config-Cn94Jc0g.mjs} +23 -4
  34. package/dist/{dependencies-Dw6wfQdv.mjs → dependencies-DKeMzwXY.mjs} +108 -60
  35. package/dist/{dependency-state-DFB41vfr.mjs → dependency-state-CojA2o0t.mjs} +14 -7
  36. package/dist/{detached-entry-KmieOKgN.mjs → detached-entry-BPlSaCwC.mjs} +1 -1
  37. package/dist/{dev-client-DXR_tPVY.mjs → dev-client-D-BW5uiq.mjs} +2 -2
  38. package/dist/{device-BK-zwyd_.mjs → device-CgXfbcz5.mjs} +25 -24
  39. package/dist/{device-capacity-DCSvUF0l.mjs → device-capacity-Cd8lMSn3.mjs} +175 -22
  40. package/dist/{device-BcYeHSFu.mjs → device-eeK95Lir.mjs} +16 -16
  41. package/dist/device-host-worker.mjs +22 -20
  42. package/dist/{device-ios-BLGfXQeK.mjs → device-ios-Cc9ulihb.mjs} +251 -23
  43. package/dist/{device-lease-run-BmvIl7bI.mjs → device-lease-run-Mtzp4THX.mjs} +5 -5
  44. package/dist/{device-pool-Dluix4H3.mjs → device-pool-eRz6DtCg.mjs} +3 -3
  45. package/dist/{doctor-Bhg1ii70.mjs → doctor-Bz_ouYAW.mjs} +28 -16
  46. package/dist/{doctor-Cp-BhzTS.mjs → doctor-C2QyhejJ.mjs} +1 -1
  47. package/dist/{doctor-fingerprint-D3a04Mhu.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +1 -1
  48. package/dist/doctor-fingerprint.mjs +1 -1
  49. package/dist/{doctor-watchman-BStK05nt.mjs → doctor-watchman-BTW82PDC.mjs} +5 -5
  50. package/dist/{doctor-OnwP94ne.mjs → doctor-xf7ht-5n.mjs} +76 -32
  51. package/dist/{eas-build-Dsj93iM9.mjs → eas-build-Dm6q68QY.mjs} +4 -4
  52. package/dist/eas-fallback-DajNpxf-.mjs +87 -0
  53. package/dist/{eas-session-ledger-B5vygTiD.mjs → eas-session-ledger-CBFo_Uo1.mjs} +37 -8
  54. package/dist/{error-diagnostics-BOOm9Db7.mjs → error-diagnostics-D1QfyJzQ.mjs} +51 -25
  55. package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
  56. package/dist/{gc-ldgr-hXU.mjs → gc-DM5oMm-J.mjs} +161 -45
  57. package/dist/{gc-C_79zvz4.mjs → gc-PLFwb0k4.mjs} +2 -2
  58. package/dist/{guide-D7K0X6KG.mjs → guide-C4I46XAk.mjs} +674 -213
  59. package/dist/{hosted-android-Bk54ej6n.mjs → hosted-android-DlaKLbW0.mjs} +6 -7
  60. package/dist/{hosted-client-fHO8yqzc.mjs → hosted-client-DDRm9hPJ.mjs} +51 -20
  61. package/dist/{hosted-logs-BfbmDM4M.mjs → hosted-logs-bSebOKbz.mjs} +8 -8
  62. package/dist/{hosted-logs-sync-B0pvmOk-.mjs → hosted-logs-sync-B0c53W_c.mjs} +5 -5
  63. package/dist/{hosted-macos-CPl0OZ9h.mjs → hosted-macos-B7-8Pv4H.mjs} +6 -6
  64. package/dist/{hosted-native-CpDB3-PO.mjs → hosted-native-CDe33CSr.mjs} +22 -18
  65. package/dist/{idle-shutdown-FfxL1KdG.mjs → idle-shutdown-CQ0QwU9J.mjs} +7 -8
  66. package/dist/{ios-WxpDJ5T1.mjs → ios-B1DYuOjh.mjs} +27 -11
  67. package/dist/{ios-B7-lToDu.mjs → ios-B1HvafEG.mjs} +8 -8
  68. package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
  69. package/dist/{ios-device-CsyryvpT.mjs → ios-device-B4elVFKi.mjs} +3 -3
  70. package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
  71. package/dist/{ios-project-Ty5pHl9O.mjs → ios-project-CR4mZ7CH.mjs} +22 -9
  72. package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
  73. package/dist/{ios-state-Cw7-WQf2.mjs → ios-state-BPHqMDdZ.mjs} +1 -1
  74. package/dist/{ios-ftxdQbJS.mjs → ios-tg4tp3q1.mjs} +94 -37
  75. package/dist/{js-swap-BMhXYVDS.mjs → js-swap-CVpSW1fn.mjs} +8 -7
  76. package/dist/{launch-DOp8RjDz.mjs → launch-DoySmhjz.mjs} +42 -38
  77. package/dist/lightened-DFAJgfIk.mjs +171 -0
  78. package/dist/{logs-s1dRIG1E.mjs → logs-BGsW7iPe.mjs} +46 -21
  79. package/dist/{logs-dQDki6Tt.mjs → logs-DI5ILkYB.mjs} +7 -7
  80. package/dist/{macos-DBBPNnIA.mjs → macos-Bo9st9Di.mjs} +73 -38
  81. package/dist/{macos-B0VEV3Gf.mjs → macos-C12RMJQF.mjs} +1 -1
  82. package/dist/macos-run.mjs +1 -1
  83. package/dist/maintenance-run.mjs +7 -7
  84. package/dist/{metro-CjC10t6E.mjs → metro-BnhXV2Mj.mjs} +4 -4
  85. package/dist/{metro-gateway-B6_PgD0L.mjs → metro-request-DXyKjVDF.mjs} +26 -47
  86. package/dist/{named-ports-BG0j1X4g.mjs → named-ports-Phoi2POD.mjs} +3 -3
  87. package/dist/{native-android-CL2NGiik.mjs → native-android-vxgtLD7w.mjs} +17 -18
  88. package/dist/{native-gradle-artifact-inputs-btSUulme.mjs → native-gradle-artifact-inputs-BN96IVw8.mjs} +5 -5
  89. package/dist/{native-runtime-Dq3RBcON.mjs → native-runtime-DG4Rodzj.mjs} +9 -8
  90. package/dist/{native-source-D-4Dh4JU.mjs → native-source-D1AzWiuP.mjs} +1 -1
  91. package/dist/{native-xcode-inputs-BW7H8JGu.mjs → native-xcode-inputs-BKarCoKg.mjs} +3 -3
  92. package/dist/{native-xcode-ios-CBXJAxfC.mjs → native-xcode-ios-8A-efGa5.mjs} +17 -17
  93. package/dist/{ndjson-CgE_o3Dl.mjs → ndjson-Dy2W4vRa.mjs} +2 -2
  94. package/dist/offload-worker.mjs +23 -24
  95. package/dist/{operation-exec-CUZifp6Z.mjs → operation-exec-Dp4FuIGR.mjs} +1 -1
  96. package/dist/{ownership-BjYvMNX_.mjs → ownership-DJCq48IJ.mjs} +3 -3
  97. package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
  98. package/dist/{phone-reverses-lmj6kcPm.mjs → phone-reverses-BzTa8g1F.mjs} +18 -4
  99. package/dist/{placement-log-DIFPQAXp.mjs → placement-log-Cvhta5ib.mjs} +3 -3
  100. package/dist/{plan-placement-IiiSQhtz.mjs → plan-placement-WkZdccuN.mjs} +36 -10
  101. package/dist/{ports-C2_w1Z0Z.mjs → ports-UV4mJgyC.mjs} +3 -3
  102. package/dist/{prebuild-gmouvmJZ.mjs → prebuild-k8d_tqOq.mjs} +16 -17
  103. package/dist/{project-BUu6Is4k.mjs → project-Sui52ywT.mjs} +17 -17
  104. package/dist/{pull-request-CbNlkFok.mjs → pull-request-BzLmzAIQ.mjs} +2 -2
  105. package/dist/pull-requests.mjs +1 -1
  106. package/dist/{react-native-android-Cgg99REN.mjs → react-native-android-DANlGGQf.mjs} +32 -26
  107. package/dist/{react-native-build-oNwqF5Wb.mjs → react-native-build-jUHnIfZ9.mjs} +9 -9
  108. package/dist/{react-native-doctor-BhA3KUte.mjs → react-native-doctor-DCWRjS7K.mjs} +6 -6
  109. package/dist/{react-native-ios-B-nf4rjN.mjs → react-native-ios-BwMsFMXi.mjs} +23 -17
  110. package/dist/{recordings-BldzVKq0.mjs → recordings-iy0mkm7b.mjs} +1 -1
  111. package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
  112. package/dist/{reload-C9OduiNc.mjs → reload-Bj7QyuDy.mjs} +1 -1
  113. package/dist/{reload-CCR7KC_l.mjs → reload-c_uEyc_X.mjs} +16 -16
  114. package/dist/{remote-C8S7FlPF.mjs → remote-DFlpAqdV.mjs} +23 -10
  115. package/dist/{result-7F5hEwQJ.mjs → result-BIcXREyC.mjs} +32 -21
  116. package/dist/{run-BqB0v3pt.mjs → run-y2HwyNvg.mjs} +3 -3
  117. package/dist/{selection-BNPBZ6T5.mjs → selection-CXgM_VK_.mjs} +37 -29
  118. package/dist/{server-bare-A75rDIdD.mjs → server-bare-2N4vSRZG.mjs} +2 -2
  119. package/dist/{server-command-CssKFOD7.mjs → server-command-qneHPcRI.mjs} +6 -6
  120. package/dist/{server-expo-eQfOdydb.mjs → server-expo-Ccm9zB0o.mjs} +4 -4
  121. package/dist/server-expo-WulkyAwT.mjs +2 -0
  122. package/dist/{settings-CosW5X-S.mjs → settings-CY5JZlNN.mjs} +375 -62
  123. package/dist/{settings-OaGQF-ri.mjs → settings-Cfd_Q6ys.mjs} +24 -3
  124. package/dist/settings-payload-DwQiEMCn.mjs +257 -0
  125. package/dist/settings-write-CJpjkeAd.mjs +185 -0
  126. package/dist/settings.schema.json +51 -33
  127. package/dist/{simslim-Bax1qcxu.mjs → simslim-DCQwzoPy.mjs} +2 -2
  128. package/dist/{slot-launch-CYCEhfBY.mjs → slot-launch-BpmanOnk.mjs} +6 -6
  129. package/dist/{stage-jKQ7CP_B.mjs → stage-CmugrSG5.mjs} +2 -2
  130. package/dist/{start-C_wefNKB.mjs → start-CHH3zgIU.mjs} +1 -1
  131. package/dist/{start-_BdJ32cZ.mjs → start-DYLk6GXn.mjs} +27 -22
  132. package/dist/{state-C1i2nMOP.mjs → state-B2QJbDwz.mjs} +4 -4
  133. package/dist/{state-C4OdpOTF.mjs → state-BXC1Lfxw.mjs} +2 -2
  134. package/dist/{stats-tEpEEH-u.mjs → stats-DxKqhcGp.mjs} +5 -5
  135. package/dist/{stats-report-n2U5plhk.mjs → stats-report-B86Cv7Uc.mjs} +1 -1
  136. package/dist/{status-CRXz-Gtj.mjs → status-7ULDEJ1e.mjs} +1 -1
  137. package/dist/{status-DQrqodLj.mjs → status-BHCkOZga.mjs} +51 -28
  138. package/dist/{status-B9M7x4CZ.mjs → status-D_Ljc89p.mjs} +1 -1
  139. package/dist/{status-watch-B5wDIH_o.mjs → status-watch-BmsPqYSU.mjs} +18 -7
  140. package/dist/status-worker.mjs +1 -1
  141. package/dist/{stim-desktop-6Dqp-gjX.mjs → stim-desktop-CbWo21kb.mjs} +2 -2
  142. package/dist/{stop-DRqQVqDJ.mjs → stop-D-dGE9gh.mjs} +21 -20
  143. package/dist/{stop-ySNQHXMG.mjs → stop-DQvE-P76.mjs} +10 -6
  144. package/dist/{stop-CmdNhGlC.mjs → stop-b2pouxAO.mjs} +2 -2
  145. package/dist/supervisor-run.mjs +237 -63
  146. package/dist/{support-BGSCBoib.mjs → support-04IhBUTT.mjs} +6 -6
  147. package/dist/{support-CVOCp0Ft.mjs → support-BtlJKjyQ.mjs} +12 -11
  148. package/dist/{swiftpm-artifact-inputs-CfUzt_0Z.mjs → swiftpm-artifact-inputs-Cj2UpmPN.mjs} +4 -4
  149. package/dist/{swiftpm-macos-x6HPpl_2.mjs → swiftpm-macos-BhF2stxY.mjs} +11 -12
  150. package/dist/{toolchain-J4J8MrAr.mjs → toolchain-mLA_km-b.mjs} +321 -15
  151. package/dist/{toolchain-DoavrvIA.mjs → toolchain-qktiV8xc.mjs} +1 -1
  152. package/dist/{trigger-KVaWWNyn.mjs → trigger-DMou-X7j.mjs} +2 -2
  153. package/dist/trigger-qp2ji5wE.mjs +2 -0
  154. package/dist/{warm-progress-DvhTX_eu.mjs → warm-progress-B0Vpuvpl.mjs} +731 -727
  155. package/dist/{web-Bihbf7-u.mjs → web-BYmK0TjL.mjs} +9 -9
  156. package/dist/web-CrVLVQZY.mjs +2 -0
  157. package/dist/web-run.mjs +9 -9
  158. package/dist/windows-report.mjs +1 -1
  159. package/dist/{workspace-state-pUg3_RRA.mjs → workspace-state-kIZrdlSg.mjs} +3 -3
  160. package/dist/{workspaces-g2lhdBXF.mjs → workspaces-CmOcceDN.mjs} +1879 -74
  161. package/dist/{worktree-BKuklFh_.mjs → worktree-2dk5edza.mjs} +933 -534
  162. package/dist/worktree-nliAoHxB.mjs +2 -0
  163. package/package.json +7 -7
  164. package/dist/ccache-Bx5TbxwG.mjs +0 -143
  165. package/dist/eas-fallback-FwkeqqGi.mjs +0 -381
  166. package/dist/hosted-ios-D55QhYaD.mjs +0 -15
  167. package/dist/native-run-BfIDFKLH.mjs +0 -275
  168. package/dist/server-expo-wvcj5tiZ.mjs +0 -2
  169. package/dist/settings-write-QjYfSrjF.mjs +0 -360
  170. package/dist/trigger-DzJu208Q.mjs +0 -2
  171. package/dist/web-BFLueSh-.mjs +0 -2
  172. package/dist/worktree-Bm4cb-nU.mjs +0 -2
@@ -1,15 +1,16 @@
1
- import { c as throwIfCancelled, l as WorkspaceProcessCleanupError, n as isTimeoutError, t as getExecutor } from "./exec-VFRpu1iA.mjs";
2
- import { _ as loadConfig$1, d as getConfigDir, f as getConfigPath$1, h as getRepoSettings, m as getProjectSettings } from "./config-BktkY_zC.mjs";
3
- import { c as gitQuiet, l as gitQuietAsync, n as runOperationFileQuiet, o as git, r as childEnvironment, s as gitAsync, t as runOperationFile } from "./operation-exec-CUZifp6Z.mjs";
4
- import { accessSync, chmodSync, constants, lstatSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
1
+ import { D as ownership_claim_exports, c as throwIfCancelled, l as WorkspaceProcessCleanupError, n as isTimeoutError, t as getExecutor } from "./exec-aULwtNly.mjs";
2
+ import { _ as loadConfig$1, d as getConfigDir, f as getConfigPath$1, h as getRepoSettings, m as getProjectSettings } from "./config-Cn94Jc0g.mjs";
3
+ import { c as gitQuiet, l as gitQuietAsync, n as runOperationFileQuiet, o as git, r as childEnvironment, s as gitAsync, t as runOperationFile } from "./operation-exec-Dp4FuIGR.mjs";
4
+ import { accessSync, chmodSync, constants, existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
7
7
  import { ambientEnv, buildCacheRoot, compiledHelper, configDir } from "@stim-cli/core";
8
- import { REMOTE_DEVICE_BACKENDS, SETTINGS, SETTING_GROUPS, TUNNEL_MODES, WEB_VIEWPORTS, acceptsShape, coerceSettingText, expectedShape, isLayeredSetting, settingDefinition, settingValueError } from "@stim-cli/core/state";
8
+ import { REMOTE_DEVICE_BACKENDS, REPLACED_SETTINGS, SETTINGS, SETTING_GROUPS, TUNNEL_MODES, WEB_VIEWPORTS, acceptsShape, coerceSettingText, expectedShape, isLayeredSetting, isPathPrefix, placementWord, replacementAdvice, settingDefinition, settingValueError, trashRoot } from "@stim-cli/core/state";
9
9
  import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, normalize, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
10
10
  import { fileURLToPath } from "node:url";
11
+ import { captureProcessIdentity } from "@stim-cli/core/process-identity";
11
12
  import { existsSync as existsSync$1, lstatSync as lstatSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, statSync as statSync$1 } from "fs";
12
- import { chmod, lstat, mkdir, readdir, realpath, rm, utimes } from "node:fs/promises";
13
+ import { chmod, lstat, mkdir, mkdtemp, readdir, realpath, rename, rm, rmdir, utimes, writeFile } from "node:fs/promises";
13
14
  //#region src/temporary.ts
14
15
  function existingPath(path) {
15
16
  const missing = [];
@@ -108,6 +109,248 @@ async function removeTemporaryEntryAsync(path, signal) {
108
109
  signal?.throwIfAborted();
109
110
  }
110
111
  //#endregion
112
+ //#region src/workspace/worktree-trash.ts
113
+ const TRASH_MANIFEST = "trash.json";
114
+ const TRASH_ENTRY_PREFIX = "remove-";
115
+ const TRASH_ENTRIES = "entries";
116
+ const TRASH_CLAIMS = "claims";
117
+ const LIST_TIMEOUT_MS = 3e4;
118
+ const DELETE_NICENESS = "10";
119
+ function rethrowCancellation(error, signal) {
120
+ if (error instanceof WorkspaceProcessCleanupError || error instanceof Error && "reportCleanup" in error) throw error;
121
+ signal?.throwIfAborted();
122
+ }
123
+ async function isPlainDirectory(path) {
124
+ const stat = await lstat(path).catch(() => null);
125
+ return Boolean(stat?.isDirectory());
126
+ }
127
+ async function ignoredDirectories(worktree, options) {
128
+ const out = await gitAsync(worktree, [
129
+ "ls-files",
130
+ "--others",
131
+ "--ignored",
132
+ "--exclude-standard",
133
+ "--directory",
134
+ "--no-empty-directory",
135
+ "-z"
136
+ ], {
137
+ ...options.env ? childEnvironment(options.env) : {},
138
+ signal: options.signal,
139
+ declareFor: options.declareFor,
140
+ timeoutMs: LIST_TIMEOUT_MS,
141
+ untrimmed: true
142
+ });
143
+ const found = [];
144
+ for (const entry of out.split("\0")) {
145
+ if (!entry.endsWith("/")) continue;
146
+ const rel = entry.slice(0, -1);
147
+ const parts = rel.split("/");
148
+ let plain = true;
149
+ for (let depth = 1; depth <= parts.length && plain; depth++) plain = await isPlainDirectory(join(worktree, ...parts.slice(0, depth)));
150
+ if (plain) found.push(rel);
151
+ }
152
+ return found;
153
+ }
154
+ async function openTrash(worktree, options, kind) {
155
+ if ((options.platform ?? process.platform) === "win32") return null;
156
+ const root = trashRoot();
157
+ let dir = null;
158
+ let claim = null;
159
+ try {
160
+ await mkdir(root, { recursive: true });
161
+ if (filesystemDevice(root) !== filesystemDevice(worktree)) return null;
162
+ dir = await mkdtemp(join(root, TRASH_ENTRY_PREFIX));
163
+ claim = (0, ownership_claim_exports.tryAcquireClaim)({
164
+ root: join(dir, "claims"),
165
+ mode: "exclusive",
166
+ label: "worktree trash"
167
+ }).acquired ?? null;
168
+ if (!claim) throw new Error("the trash entry claim was not acquired");
169
+ const manifest = {
170
+ worktree,
171
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
172
+ ...kind ? { kind } : {}
173
+ };
174
+ await writeFile(join(dir, TRASH_MANIFEST), `${JSON.stringify(manifest)}\n`);
175
+ await mkdir(join(dir, TRASH_ENTRIES));
176
+ } catch (error) {
177
+ if (claim) (0, ownership_claim_exports.releaseClaim)(claim);
178
+ if (dir) await rm(dir, {
179
+ recursive: true,
180
+ force: true
181
+ }).catch(() => {});
182
+ rethrowCancellation(error, options.signal);
183
+ return null;
184
+ }
185
+ return {
186
+ dir,
187
+ worktree,
188
+ moved: [],
189
+ claim
190
+ };
191
+ }
192
+ /**
193
+ * Moves the worktree's ignored directories, which `git worktree remove` would delete, into a new entry under
194
+ * `$STIM_HOME/trash` held by an exclusive ownership claim. Null, with nothing moved, when the trash is on another
195
+ * filesystem, the platform is Windows, git cannot list the entries, or the claim cannot be taken. A directory that
196
+ * does not rename stays in the worktree for git to delete.
197
+ */
198
+ async function moveIgnoredTreesToTrash(worktree, options = {}) {
199
+ if ((options.platform ?? process.platform) === "win32") return null;
200
+ let listed;
201
+ try {
202
+ listed = await ignoredDirectories(worktree, options);
203
+ } catch (error) {
204
+ rethrowCancellation(error, options.signal);
205
+ return null;
206
+ }
207
+ if (!listed.length) return null;
208
+ const trash = await openTrash(worktree, options);
209
+ if (!trash) return null;
210
+ for (const from of listed) {
211
+ const to = String(trash.moved.length);
212
+ try {
213
+ await rename(join(worktree, from), join(trash.dir, TRASH_ENTRIES, to));
214
+ trash.moved.push({
215
+ from,
216
+ to
217
+ });
218
+ } catch {}
219
+ }
220
+ if (trash.moved.length) return trash;
221
+ await discardTrash(trash);
222
+ return null;
223
+ }
224
+ /**
225
+ * A trash entry that takes directories out of a live worktree while it warms, so the delete runs in the background.
226
+ * `take` is false, with the directory untouched, when the entry cannot be opened or the rename fails; the caller
227
+ * deletes it in place. gc deletes a crashed entry whatever the state of the worktree.
228
+ */
229
+ function warmTrash(worktree, options = {}) {
230
+ let trash;
231
+ return {
232
+ async take(path) {
233
+ if (trash === void 0) trash = await openTrash(worktree, options, "warm");
234
+ if (!trash) return false;
235
+ const to = String(trash.moved.length);
236
+ try {
237
+ await rename(path, join(trash.dir, TRASH_ENTRIES, to));
238
+ } catch {
239
+ return false;
240
+ }
241
+ trash.moved.push({
242
+ from: path,
243
+ to
244
+ });
245
+ return true;
246
+ },
247
+ async dispose(operation) {
248
+ if (!trash) return;
249
+ if (trash.moved.length) await disposeTrash(trash, operation);
250
+ else await discardTrash(trash);
251
+ }
252
+ };
253
+ }
254
+ async function discardTrash(trash) {
255
+ await rmdir(join(trash.dir, TRASH_ENTRIES)).catch(() => {});
256
+ await rm(join(trash.dir, TRASH_MANIFEST), { force: true }).catch(() => {});
257
+ (0, ownership_claim_exports.releaseClaim)(trash.claim);
258
+ await rmdir(trash.dir).catch(() => {});
259
+ }
260
+ /** Moves every tree back into the worktree. Returns the relative paths that stay in the trash for gc. */
261
+ async function restoreTrashedTrees(trash) {
262
+ const kept = [];
263
+ for (const entry of trash.moved.toReversed()) {
264
+ const target = join(trash.worktree, entry.from);
265
+ try {
266
+ if (await lstat(target).catch(() => null) || !await isPlainDirectory(dirname(target))) {
267
+ kept.push(entry.from);
268
+ continue;
269
+ }
270
+ await rename(join(trash.dir, TRASH_ENTRIES, entry.to), target);
271
+ } catch {
272
+ kept.push(entry.from);
273
+ }
274
+ }
275
+ if (kept.length) (0, ownership_claim_exports.releaseClaim)(trash.claim);
276
+ else await discardTrash(trash);
277
+ return kept;
278
+ }
279
+ /** Deletes one trash entry: `rm -rf` for the bulk, then a walk that also clears read-only directories. */
280
+ async function deleteTrashEntry(dir, operation) {
281
+ if (process.platform !== "win32") try {
282
+ await runOperationFile(operation, getExecutor(), "rm", [
283
+ "-rf",
284
+ "--",
285
+ join(dir, TRASH_ENTRIES)
286
+ ], {
287
+ timeoutMs: "unbounded",
288
+ signal: operation?.signal,
289
+ cwd: dirname(dir)
290
+ });
291
+ } catch (error) {
292
+ rethrowCancellation(error, operation?.signal);
293
+ }
294
+ await removeTemporaryEntryAsync(dir, operation?.signal);
295
+ }
296
+ function deleteInBackground(trash) {
297
+ try {
298
+ (0, ownership_claim_exports.markClaimChildPending)(trash.claim);
299
+ const child = getExecutor().spawn("nice", [
300
+ "-n",
301
+ DELETE_NICENESS,
302
+ "sh",
303
+ "-c",
304
+ "rm -rf -- \"$1\" && rm -rf -- \"$2\"",
305
+ "--",
306
+ join(trash.dir, TRASH_ENTRIES),
307
+ trash.dir
308
+ ], {
309
+ cwd: dirname(trash.dir),
310
+ detached: true,
311
+ stdio: "ignore"
312
+ });
313
+ child.on?.("error", () => {});
314
+ child.unref?.();
315
+ const captured = child.pid === void 0 ? null : captureProcessIdentity(child.pid);
316
+ if (captured?.ok === false && captured.reason.startsWith("NOT_FOUND")) {
317
+ (0, ownership_claim_exports.clearClaimChild)(trash.claim);
318
+ (0, ownership_claim_exports.releaseClaim)(trash.claim);
319
+ return existsSync(trash.dir) ? "left" : "deleted";
320
+ }
321
+ if (!captured?.ok || child.pid === void 0) throw new Error("the trash deletion process was not recorded");
322
+ (0, ownership_claim_exports.setClaimChild)(trash.claim, {
323
+ pid: child.pid,
324
+ processToken: captured.token
325
+ });
326
+ return "background";
327
+ } catch {
328
+ try {
329
+ (0, ownership_claim_exports.clearClaimChild)(trash.claim);
330
+ } catch {}
331
+ (0, ownership_claim_exports.releaseClaim)(trash.claim);
332
+ return "left";
333
+ }
334
+ }
335
+ /**
336
+ * Deletes the trash entry once its trees are out of the way. A CLI command starts a detached, low-priority `rm` recorded
337
+ * as the claim's child, so gc reports the entry as in use until `rm` exits. Inside a bounded report, such as the
338
+ * programmatic API, every child is stopped when the report settles, so the entry is deleted before returning.
339
+ * `left` means the entry waits for gc with its claim released.
340
+ */
341
+ async function disposeTrash(trash, operation) {
342
+ if (!getExecutor().reportSignal?.()) return deleteInBackground(trash);
343
+ try {
344
+ await deleteTrashEntry(trash.dir, operation);
345
+ return "deleted";
346
+ } catch (error) {
347
+ rethrowCancellation(error, operation?.signal);
348
+ return "left";
349
+ } finally {
350
+ (0, ownership_claim_exports.releaseClaim)(trash.claim);
351
+ }
352
+ }
353
+ //#endregion
111
354
  //#region src/clonefile.ts
112
355
  const SOURCE = "stim-clonefile.c";
113
356
  const COMPILE_TIMEOUT_MS = 12e4;
@@ -397,7 +640,7 @@ function knownCopiedPaths(rel) {
397
640
  function isMissingError(error) {
398
641
  return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
399
642
  }
400
- async function removeCopiedPath(root, rel, signal) {
643
+ async function removeCopiedPath(root, rel, signal, trash) {
401
644
  signal.throwIfAborted();
402
645
  const path = join$1(root, rel);
403
646
  let parent;
@@ -411,21 +654,22 @@ async function removeCopiedPath(root, rel, signal) {
411
654
  if (inside === ".." || inside.startsWith(`..${sep$1}`) || isAbsolute$1(inside)) return;
412
655
  const stat = await lstat(parent);
413
656
  const target = join$1(parent, basename$1(path));
657
+ let targetStat;
414
658
  try {
415
- await lstat(target);
659
+ targetStat = await lstat(target);
416
660
  } catch (error) {
417
661
  if (isMissingError(error)) return;
418
662
  throw error;
419
663
  }
420
664
  await chmod(parent, stat.mode | 448);
421
665
  try {
422
- await removeTemporaryEntryAsync(target, signal);
666
+ if (!(targetStat.isDirectory() && await trash.take(target))) await removeTemporaryEntryAsync(target, signal);
423
667
  } finally {
424
668
  await utimes(parent, stat.atime, stat.mtime);
425
669
  await chmod(parent, stat.mode);
426
670
  }
427
671
  }
428
- async function removeKnownCopiedPaths(path, rel, signal) {
672
+ async function removeKnownCopiedPaths(path, rel, signal, trash) {
429
673
  const paths = knownCopiedPaths(rel);
430
674
  if (basename$1(rel) === "node_modules") {
431
675
  const virtualStore = await readdir(join$1(path, ".pnpm")).catch((error) => {
@@ -435,7 +679,7 @@ async function removeKnownCopiedPaths(path, rel, signal) {
435
679
  for (const name of virtualStore) if (name.startsWith("expo-modules-jsi@")) paths.push(`.pnpm/${name}/node_modules/expo-modules-jsi/apple/.DerivedData`);
436
680
  }
437
681
  const root = await realpath(path);
438
- for (const known of paths) await removeCopiedPath(root, known, signal);
682
+ for (const known of paths) await removeCopiedPath(root, known, signal, trash);
439
683
  }
440
684
  async function cloneIgnoredEntries({ root, target, patterns, operation }) {
441
685
  const options = {
@@ -460,58 +704,65 @@ async function cloneIgnoredEntries({ root, target, patterns, operation }) {
460
704
  let cloned = true;
461
705
  let helper;
462
706
  const clonefile = () => helper ??= clonefileHelper(operation);
463
- for (const rel of entries) {
464
- operation.signal.throwIfAborted();
465
- const from = join$1(root, rel);
466
- const to = join$1(target, rel);
467
- let copying = false;
468
- try {
469
- const reason = guard.covers(rel) ? "tracked" : overlapsNestedWorktree(rel, nested) ? "nested worktree" : missingDestinationReason(target, rel);
470
- if (reason) {
471
- skipped.push({
472
- file: rel,
473
- reason
474
- });
475
- continue;
476
- }
477
- await mkdir(dirname$1(to), { recursive: true });
478
- copying = true;
479
- const copiedWith = async (file, args) => {
480
- try {
481
- await getExecutor().runFileAsync(file, args, options);
482
- return true;
483
- } catch (cause) {
484
- if (cause instanceof WorkspaceProcessCleanupError || cause instanceof Error && "reportCleanup" in cause) throw cause;
485
- operation.signal.throwIfAborted();
486
- await removeTemporaryEntryAsync(to);
487
- return false;
707
+ const trash = warmTrash(target, { signal: operation.signal });
708
+ try {
709
+ for (const rel of entries) {
710
+ operation.signal.throwIfAborted();
711
+ const from = join$1(root, rel);
712
+ const to = join$1(target, rel);
713
+ let copying = false;
714
+ try {
715
+ const reason = guard.covers(rel) ? "tracked" : overlapsNestedWorktree(rel, nested) ? "nested worktree" : missingDestinationReason(target, rel);
716
+ if (reason) {
717
+ skipped.push({
718
+ file: rel,
719
+ reason
720
+ });
721
+ continue;
488
722
  }
489
- };
490
- const directoryClone = (await lstat(from)).isDirectory() ? await clonefile() : null;
491
- if (!(directoryClone && await copiedWith(directoryClone, [from, to])) && !await copiedWith("cp", [
492
- "-Rc",
493
- from,
494
- to
495
- ])) {
496
- await getExecutor().runFileAsync("cp", [
497
- "-R",
723
+ await mkdir(dirname$1(to), { recursive: true });
724
+ copying = true;
725
+ const copiedWith = async (file, args) => {
726
+ try {
727
+ await getExecutor().runFileAsync(file, args, options);
728
+ return true;
729
+ } catch (cause) {
730
+ if (cause instanceof WorkspaceProcessCleanupError || cause instanceof Error && "reportCleanup" in cause) throw cause;
731
+ operation.signal.throwIfAborted();
732
+ await removeTemporaryEntryAsync(to);
733
+ return false;
734
+ }
735
+ };
736
+ const directoryClone = (await lstat(from)).isDirectory() ? await clonefile() : null;
737
+ if (!(directoryClone && await copiedWith(directoryClone, [from, to])) && !await copiedWith("cp", [
738
+ "-Rc",
498
739
  from,
499
740
  to
500
- ], options);
501
- cloned = false;
741
+ ])) {
742
+ await getExecutor().runFileAsync("cp", [
743
+ "-R",
744
+ from,
745
+ to
746
+ ], options);
747
+ cloned = false;
748
+ }
749
+ if ((await lstat(to)).isDirectory()) await removeKnownCopiedPaths(to, rel, operation.signal, trash);
750
+ copied.push(rel);
751
+ } catch (cause) {
752
+ if (cause instanceof WorkspaceProcessCleanupError || cause instanceof Error && "reportCleanup" in cause) throw cause;
753
+ if (copying) await removeTemporaryEntryAsync(to);
754
+ operation.signal.throwIfAborted();
755
+ failed.push({
756
+ file: rel,
757
+ error: String(cause?.message || cause)
758
+ });
502
759
  }
503
- if ((await lstat(to)).isDirectory()) await removeKnownCopiedPaths(to, rel, operation.signal);
504
- copied.push(rel);
505
- } catch (cause) {
506
- if (cause instanceof WorkspaceProcessCleanupError || cause instanceof Error && "reportCleanup" in cause) throw cause;
507
- if (copying) await removeTemporaryEntryAsync(to);
508
- operation.signal.throwIfAborted();
509
- failed.push({
510
- file: rel,
511
- error: String(cause?.message || cause)
512
- });
513
760
  }
761
+ } catch (error) {
762
+ await trash.dispose(operation).catch(() => {});
763
+ throw error;
514
764
  }
765
+ await trash.dispose(operation);
515
766
  return {
516
767
  copied,
517
768
  skipped,
@@ -811,6 +1062,32 @@ async function deleteBranchAsync(cwd, branch, expectedSha, options = {}) {
811
1062
  write: true
812
1063
  });
813
1064
  }
1065
+ function nativeCanonicalPath(path) {
1066
+ const missing = [];
1067
+ for (let existing = resolve$1(path);; existing = dirname$1(existing)) try {
1068
+ return resolve$1(realpathSync$1.native(existing), ...missing);
1069
+ } catch {
1070
+ if (dirname$1(existing) === existing) return resolve$1(path);
1071
+ missing.unshift(basename$1(existing));
1072
+ }
1073
+ }
1074
+ function matchWorktreeEntry(entries, path) {
1075
+ let best = null;
1076
+ const target = nativeCanonicalPath(path);
1077
+ (entries || []).forEach((entry, index) => {
1078
+ if (!entry?.path || !isPathPrefix(nativeCanonicalPath(entry.path), target)) return;
1079
+ if (!best || entry.path.length > best.path.length) best = {
1080
+ ...entry,
1081
+ index
1082
+ };
1083
+ });
1084
+ return best;
1085
+ }
1086
+ const LOCKED_REASON = "locked with git worktree lock";
1087
+ const LOCK_UNKNOWN_REASON = "git could not tell whether its worktree is locked";
1088
+ function lockReason(lock) {
1089
+ return lock === "locked" ? LOCKED_REASON : LOCK_UNKNOWN_REASON;
1090
+ }
814
1091
  function parseWorktrees(out) {
815
1092
  const entries = [];
816
1093
  let current = {};
@@ -856,6 +1133,24 @@ async function listWorktreesAsync(cwd, options = {}) {
856
1133
  ], options);
857
1134
  return out ? parseWorktrees(out) : [];
858
1135
  }
1136
+ function insideGitCheckout(root) {
1137
+ for (let dir = resolve$1(root);; dir = dirname$1(dir)) {
1138
+ if (existsSync$1(join$1(dir, ".git"))) return true;
1139
+ if (dirname$1(dir) === dir) return false;
1140
+ }
1141
+ }
1142
+ function lockOf(entries, root) {
1143
+ const entry = matchWorktreeEntry(entries, root);
1144
+ if (entry) return entry.locked ? "locked" : null;
1145
+ return existsSync$1(root) && insideGitCheckout(root) ? "unknown" : null;
1146
+ }
1147
+ /** Null when `root` is not in a locked worktree; 'unknown' when git lists nothing for a path inside a git checkout. */
1148
+ function worktreeLock(root) {
1149
+ return lockOf(listWorktrees(root), root);
1150
+ }
1151
+ async function worktreeLockAsync(root, options = {}) {
1152
+ return lockOf(await listWorktreesAsync(root, options), root);
1153
+ }
859
1154
  function branchOf(head) {
860
1155
  return head.startsWith("ref: refs/heads/") ? head.slice(16) : void 0;
861
1156
  }
@@ -1043,7 +1338,7 @@ function settingShapeErrors(settings) {
1043
1338
  if (SETTINGS_WITH_RESOLVE_TIME_FALLBACK.has(setting.key)) continue;
1044
1339
  const value = settingValueAt(settings, setting.key);
1045
1340
  if (value === void 0) continue;
1046
- const expected = setting.key === "ios.remote" || setting.key === "android.remote" || setting.key === "android.deviceProfile" || setting.type.kind === "number" && !BOUNDS_CHECKED_WHEN_USED.has(setting.key) ? settingValueError(setting, value) : acceptsShape(setting, value) ? null : expectedShape(setting.type);
1341
+ const expected = setting.key === "ios.remote" || setting.key === "android.remote" || setting.key === "macos.remote" || setting.key === "android.deviceProfile" || setting.type.kind === "number" && !BOUNDS_CHECKED_WHEN_USED.has(setting.key) ? settingValueError(setting, value) : acceptsShape(setting, value) ? null : expectedShape(setting.type);
1047
1342
  if (expected) errors.push(`Invalid ${setting.key} setting ${JSON.stringify(value)}. Expected ${expected}.`);
1048
1343
  }
1049
1344
  return errors;
@@ -1440,6 +1735,10 @@ function unknownSettingKeys(settings, prefix = "") {
1440
1735
  }
1441
1736
  return unknown;
1442
1737
  }
1738
+ function inertSettingWarning(settings, key) {
1739
+ const advice = replacementAdvice(key, settingValueAt(settings, key));
1740
+ return `Warning: setting "${key}" is not read by Stim and will be ignored.${advice ? advice.command ? ` Run \`${advice.command}\` instead.` : ` Use ${advice.key} instead.` : ""}`;
1741
+ }
1443
1742
  function readCommittedSettings(directory) {
1444
1743
  if (!directory) return {};
1445
1744
  const p = join$1(directory, ".stim.json");
@@ -1462,8 +1761,16 @@ function setSettingValueAt(settings, path, value) {
1462
1761
  node[segments[segments.length - 1]] = value;
1463
1762
  }
1464
1763
  const MACHINE_READABLE_SETTINGS = SETTINGS.filter((setting) => isLayeredSetting(setting) && setting.scopes.includes("machine") && !setting.key.startsWith("optimizations."));
1465
- function machineLayerSettings(machine) {
1764
+ function removedMachineSettings(machine) {
1466
1765
  const settings = {};
1766
+ for (const key of Object.keys(REPLACED_SETTINGS)) {
1767
+ const value = settingValueAt(machine, key);
1768
+ if (value !== void 0) setSettingValueAt(settings, key, value);
1769
+ }
1770
+ return settings;
1771
+ }
1772
+ function machineLayerSettings(machine) {
1773
+ const settings = removedMachineSettings(machine);
1467
1774
  const optimizations = settingValueAt(machine, "optimizations");
1468
1775
  if (optimizations !== void 0) settings.optimizations = optimizations;
1469
1776
  for (const setting of MACHINE_READABLE_SETTINGS) {
@@ -1635,13 +1942,19 @@ function cacheProviderSettingError(settings) {
1635
1942
  function parseIosRemote(remote) {
1636
1943
  const selected = remote.trim();
1637
1944
  const reserved = selected.toLowerCase();
1638
- if (reserved === "local") return null;
1945
+ const word = placementWord(selected);
1946
+ if (word === "local") return null;
1947
+ if (word) return {
1948
+ kind: "machine",
1949
+ machine: "auto",
1950
+ placement: word
1951
+ };
1639
1952
  return REMOTE_DEVICE_BACKENDS.includes(reserved) ? {
1640
1953
  kind: "backend",
1641
1954
  backend: reserved
1642
1955
  } : {
1643
1956
  kind: "machine",
1644
- machine: reserved === "auto" ? "auto" : selected
1957
+ machine: selected
1645
1958
  };
1646
1959
  }
1647
1960
  function remoteIosSetting(settings) {
@@ -1742,4 +2055,4 @@ function webSettings(settings) {
1742
2055
  };
1743
2056
  }
1744
2057
  //#endregion
1745
- export { settingOrigin as $, metroCommandSettingError as A, podsOutOfSync as At, readCommittedSettings as B, unpushedCommitsAsync as Bt, iosSigningIdentitySha1Setting as C, hasUncommittedWorkAsync as Ct, maintenanceKeepSetting as D, listWorktreesAsync as Dt, iosSimSlimProfileSetting as E, listWorktrees as Et, ngrokUrlSetting as F, resolveFullRef as Ft, resolveAndroidLayout as G, removeTemporaryEntryAsync as Gt, remoteAndroidSetting as H, filesystemDevice as Ht, parseIosRemote as I, resolveFullRefAsync as It, resolveProjectSettings as J, resolveCacheProviderConfig as K, temporaryRoot as Kt, projectSettingsContext as L, resolveSourceCheckoutAsync as Lt, metroPortSetting as M, removeWorktreeAsync as Mt, metroTunnelSettingError as N, repoRoot as Nt, mergeSettingsLayers as O, locallyKnownUpstream as Ot, metroWarmupUrlSetting as P, repoRootAsync as Pt, settingFile as Q, projectSettingsContextAsync as R, restoreFileAsync as Rt, iosSigningIdentitySettingError as S, hasRemoteAsync as St, iosSimSlimDefaultSetting as T, linkedWorktreesOnDisk as Tt, remoteEasFallbackSetting as U, makeTemporaryDirectory as Ut, realpathInside as V, warmWorktreePaths as Vt, remoteIosSetting as W, removeTemporaryEntry as Wt, resolveSettings as X, resolveProjectSettingsAsync as Y, runnableMetroCommand as Z, iosLanHostSetting as _, dirtyPathsAsync as _t, SETTING_SHAPE_REMEDY as a, unknownSettingKeys as at, iosProjectDirSettingError as b, gitCommonDirOnDisk as bt, androidDataPartitionSizeBytes as c, PUBLIC_METRO_ENV as ct, androidLayoutSetting as d, resolveTailscaleBinary as dt, settingOriginScope as et, androidLayoutSettingError as f, branchExistsAsync as ft, deviceReclaimIdleMinutesSetting as g, dirtyFingerprintFiles as gt, deviceIdleShutdownMinutesSetting as h, depsOutOfSync as ht, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as i, tunnelModeSetting as it, metroIdleStopMinutesSetting as j, readWorktreeExclude as jt, metroCommandSetting as k, locallyKnownUpstreamAsync as kt, androidDataPartitionSizeGbSetting as l, detectProviders as lt, defaultAndroidLayout as m, deleteBranchAsync as mt, METRO_COMMAND_PORT as n, settingValueAt as nt, androidAvdConfigSetting as o, webSettings as ot, cacheProviderSettingError as p, cloneIgnoredEntries as pt, resolveIosProjectDir as q, PATH_SETTINGS as r, settingsLayers as rt, androidAvdConfigSettingError as s, workspaceHiddenSetting as st, ANDROID_AVD_CONFIG_HELP as t, settingShapeErrors as tt, androidDataPartitionSizeGbSettingError as u, planMetroReach as ut, iosLanHostSettingError as v, gitCommonDir as vt, iosSigningIdentitySha1SettingError as w, isPodInstallChurn as wt, iosSigningIdentitySetting as x, hasPopulatedSubmodulesAsync as xt, iosProjectDirSetting as y, gitCommonDirAsync as yt, publicUrlSetting as z, sourceCheckoutOf as zt };
2058
+ export { runnableMetroCommand as $, TRASH_MANIFEST as $t, metroCommandSetting as A, listWorktrees as At, publicUrlSetting as B, repoRoot as Bt, iosSigningIdentitySettingError as C, gitCommonDirOnDisk as Ct, iosSimSlimProfileSetting as D, isPodInstallChurn as Dt, iosSimSlimDefaultSetting as E, hasUncommittedWorkAsync as Et, metroWarmupUrlSetting as F, matchWorktreeEntry as Ft, remoteIosSetting as G, restoreFileAsync as Gt, realpathInside as H, resolveFullRef as Ht, ngrokUrlSetting as I, nativeCanonicalPath as It, resolveCacheProviderConfig as J, warmWorktreePaths as Jt, removedMachineSettings as K, sourceCheckoutOf as Kt, parseIosRemote as L, podsOutOfSync as Lt, metroIdleStopMinutesSetting as M, locallyKnownUpstream as Mt, metroPortSetting as N, locallyKnownUpstreamAsync as Nt, maintenanceKeepSetting as O, linkedWorktreesOnDisk as Ot, metroTunnelSettingError as P, lockReason as Pt, resolveSettings as Q, TRASH_ENTRY_PREFIX as Qt, projectSettingsContext as R, readWorktreeExclude as Rt, iosSigningIdentitySetting as S, gitCommonDirAsync as St, iosSigningIdentitySha1SettingError as T, hasRemoteAsync as Tt, remoteAndroidSetting as U, resolveFullRefAsync as Ut, readCommittedSettings as V, repoRootAsync as Vt, remoteEasFallbackSetting as W, resolveSourceCheckoutAsync as Wt, resolveProjectSettings as X, worktreeLockAsync as Xt, resolveIosProjectDir as Y, worktreeLock as Yt, resolveProjectSettingsAsync as Z, TRASH_CLAIMS as Zt, inertSettingWarning as _, deleteBranchAsync as _t, SETTING_SHAPE_REMEDY as a, makeTemporaryDirectory as an, settingsLayers as at, iosProjectDirSetting as b, dirtyPathsAsync as bt, androidDataPartitionSizeBytes as c, temporaryRoot as cn, webSettings as ct, androidLayoutSetting as d, detectProviders as dt, deleteTrashEntry as en, settingFile as et, androidLayoutSettingError as f, planMetroReach as ft, deviceReclaimIdleMinutesSetting as g, cloneIgnoredEntries as gt, deviceIdleShutdownMinutesSetting as h, branchExistsAsync as ht, SETTINGS_WITH_RESOLVE_TIME_FALLBACK as i, filesystemDevice as in, settingValueAt as it, metroCommandSettingError as j, listWorktreesAsync as jt, mergeSettingsLayers as k, listCarryableIgnoredEntries as kt, androidDataPartitionSizeGbSetting as l, workspaceHiddenSetting as lt, defaultAndroidLayout as m, LOCKED_REASON as mt, METRO_COMMAND_PORT as n, moveIgnoredTreesToTrash as nn, settingOriginScope as nt, androidAvdConfigSetting as o, removeTemporaryEntry as on, tunnelModeSetting as ot, cacheProviderSettingError as p, resolveTailscaleBinary as pt, resolveAndroidLayout as q, unpushedCommitsAsync as qt, PATH_SETTINGS as r, restoreTrashedTrees as rn, settingShapeErrors as rt, androidAvdConfigSettingError as s, removeTemporaryEntryAsync as sn, unknownSettingKeys as st, ANDROID_AVD_CONFIG_HELP as t, disposeTrash as tn, settingOrigin as tt, androidDataPartitionSizeGbSettingError as u, PUBLIC_METRO_ENV as ut, iosLanHostSetting as v, depsOutOfSync as vt, iosSigningIdentitySha1Setting as w, hasPopulatedSubmodulesAsync as wt, iosProjectDirSettingError as x, gitCommonDir as xt, iosLanHostSettingError as y, dirtyFingerprintFiles as yt, projectSettingsContextAsync as z, removeWorktreeAsync as zt };
@@ -1,5 +1,6 @@
1
- import { a as layerFile, c as settingEntry, i as SettingsRefusal, n as readScope, o as readSettingsContext, r as requireSetting, s as readSettingsPayload, t as mutateSetting } from "./settings-write-QjYfSrjF.mjs";
2
- import { SETTING_SCOPES } from "@stim-cli/core/state";
1
+ import { c as readSettingsPayload, l as settingEntry, o as layerFile, s as readSettingsContext, t as SettingsRefusal } from "./settings-payload-DwQiEMCn.mjs";
2
+ import { i as unsetReplacedSetting, n as readScope, r as requireSetting, t as mutateSetting } from "./settings-write-CJpjkeAd.mjs";
3
+ import { REPLACED_SETTINGS, SETTING_SCOPES } from "@stim-cli/core/state";
3
4
  import chalk from "chalk";
4
5
  //#region src/commands/settings.ts
5
6
  function formatValue(value) {
@@ -45,7 +46,7 @@ function registerSettings(program, io = CONSOLE, env = process.env) {
45
46
  const shown = entry.origin === null ? "" : formatValue(entry.value);
46
47
  io.out(`${entry.key.padEnd(width)} ${shown}${shown ? " " : ""}${chalk.dim(`(${formatOrigin(entry)})`)}`);
47
48
  }
48
- for (const entry of payload.unknown) io.note(chalk.yellow(`Warning: ${entry.key} in ${entry.file} is not read by Stim.`));
49
+ for (const entry of payload.unknown) io.note(chalk.yellow(`Warning: ${entry.key} in ${entry.file} is not read by Stim.${entry.replacement ? ` Run \`${entry.replacement}\` instead.` : ""}`));
49
50
  }));
50
51
  settings.command("get <key>").description("Print the effective value of a setting, or its value in one layer").option("--scope <scope>", `read one layer: ${SETTING_SCOPES.join(", ")}`).option("--json", "print the setting entry as JSON").action((key, opts, command) => run(wantsJson(opts, command), io, async () => {
51
52
  const setting = requireSetting(key);
@@ -80,6 +81,18 @@ function registerSettings(program, io = CONSOLE, env = process.env) {
80
81
  report(io, wantsJson(opts, command), result, "set");
81
82
  }));
82
83
  settings.command("unset <key>").description("Remove a setting from one layer").option("--scope <scope>", `the layer to clear: ${SETTING_SCOPES.join(", ")}`).option("--json", "print the setting after removal as JSON").action((key, opts, command) => run(wantsJson(opts, command), io, async () => {
84
+ if (Object.hasOwn(REPLACED_SETTINGS, key)) {
85
+ const removal = await unsetReplacedSetting({
86
+ key,
87
+ scope: opts.scope
88
+ }, {
89
+ cwd: process.cwd(),
90
+ env,
91
+ note: io.note
92
+ });
93
+ reportRemoval(io, wantsJson(opts, command), removal, opts.scope);
94
+ return;
95
+ }
83
96
  const result = await mutateSetting({
84
97
  action: "unset",
85
98
  key,
@@ -92,6 +105,14 @@ function registerSettings(program, io = CONSOLE, env = process.env) {
92
105
  report(io, wantsJson(opts, command), result, "unset");
93
106
  }));
94
107
  }
108
+ function reportRemoval(io, json, removal, scope) {
109
+ if (json) {
110
+ io.out(JSON.stringify(removal));
111
+ return;
112
+ }
113
+ for (const { file } of removal.removed) io.out(`unset ${removal.key} in ${file}`);
114
+ if (removal.removed.length === 0) io.out(`${removal.key} was not set in ${scope ? `the ${scope} layer` : "any layer"}.`);
115
+ }
95
116
  function report(io, json, result, verb) {
96
117
  const { setting: entry, recordingsDeleted, ...write } = result;
97
118
  if (json) {