sootsim 0.1.291 → 0.1.293

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 (159) hide show
  1. package/detox/expectations.ts +32 -12
  2. package/dist-cli/bin.js +5 -5
  3. package/dist-cli/chunks/{agent-EDS4HRKB.js → agent-YWI2NWL7.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-ZCSAPGFF.js → agent-wrapper-IYJ7UZOA.js} +2 -2
  5. package/dist-cli/chunks/{app-fonts-4WW4EQEW.js → app-fonts-FQFUC4LR.js} +2 -2
  6. package/dist-cli/chunks/{assert-XEWAR4HT.js → assert-XUCELWAC.js} +2 -2
  7. package/dist-cli/chunks/{auth-SAYME64O.js → auth-4DQTV3OW.js} +2 -2
  8. package/dist-cli/chunks/beta-CFDAW6UN.js +2 -0
  9. package/dist-cli/chunks/{camera-2AHKTJ5I.js → camera-RYOHBVZA.js} +2 -2
  10. package/dist-cli/chunks/{chunk-7CU7FXRN.js → chunk-2M57EAWS.js} +1 -1
  11. package/dist-cli/chunks/{chunk-LJU4JU3N.js → chunk-2VKTOZQ5.js} +2 -2
  12. package/dist-cli/chunks/{chunk-NGPK2CLP.js → chunk-2XYCSFGN.js} +3 -3
  13. package/dist-cli/chunks/{chunk-UQLIMTO6.js → chunk-3UX6AY2B.js} +1 -1
  14. package/dist-cli/chunks/{chunk-R36NUSCM.js → chunk-4B4VFT73.js} +2 -2
  15. package/dist-cli/chunks/{chunk-KQKLLUX5.js → chunk-547W23BB.js} +2 -2
  16. package/dist-cli/chunks/{chunk-KSN2WTV6.js → chunk-67CIS55C.js} +1 -1
  17. package/dist-cli/chunks/{chunk-VK3IISND.js → chunk-6IFJLHDA.js} +1 -1
  18. package/dist-cli/chunks/{chunk-NRXMKMIJ.js → chunk-6VVLDYPV.js} +2 -2
  19. package/dist-cli/chunks/{chunk-LD5ZN4ZU.js → chunk-7B6RGFTM.js} +2 -2
  20. package/dist-cli/chunks/{chunk-HFJEB4UJ.js → chunk-7H34H74K.js} +2 -2
  21. package/dist-cli/chunks/{chunk-HQRKN435.js → chunk-7H5G4HUK.js} +2 -2
  22. package/dist-cli/chunks/{chunk-OC6PU44E.js → chunk-ACSTEPSD.js} +1 -1
  23. package/dist-cli/chunks/chunk-AFRXWKTA.js +118 -0
  24. package/dist-cli/chunks/{chunk-7GKJ3U2Z.js → chunk-B7TX4WFB.js} +2 -2
  25. package/dist-cli/chunks/{chunk-EFTPP4W3.js → chunk-BQT5YDTV.js} +3 -3
  26. package/dist-cli/chunks/{chunk-NPP6ZJLD.js → chunk-DE4ZA3NL.js} +2 -2
  27. package/dist-cli/chunks/{chunk-462J7KLI.js → chunk-E5WYXRGV.js} +3 -3
  28. package/dist-cli/chunks/chunk-HKMWUN7F.js +2 -0
  29. package/dist-cli/chunks/{chunk-5CJQNMXY.js → chunk-J6P2UPXH.js} +2 -2
  30. package/dist-cli/chunks/{chunk-GJDCBMAP.js → chunk-JOPKZVOW.js} +1 -1
  31. package/dist-cli/chunks/{chunk-EPJO7YNS.js → chunk-K5JEUI5G.js} +1 -1
  32. package/dist-cli/chunks/{chunk-5D5XSE5V.js → chunk-KC5SCOGS.js} +2 -2
  33. package/dist-cli/chunks/{chunk-FWC4J42U.js → chunk-LA5DIO33.js} +1 -1
  34. package/dist-cli/chunks/{chunk-653O3F3M.js → chunk-LOQLZFRK.js} +2 -2
  35. package/dist-cli/chunks/{chunk-QOIOK64H.js → chunk-MOU2WLO4.js} +1 -1
  36. package/dist-cli/chunks/{chunk-LHBU5QMM.js → chunk-NCCMRFXU.js} +1 -1
  37. package/dist-cli/chunks/{chunk-5IBT7JOS.js → chunk-PCAPHXN3.js} +2 -2
  38. package/dist-cli/chunks/chunk-QXDXUDJD.js +1 -0
  39. package/dist-cli/chunks/{chunk-NN4CZ2QW.js → chunk-RKXHQ2Q3.js} +1 -1
  40. package/dist-cli/chunks/{chunk-Z6I5M7VJ.js → chunk-RMLJXP7T.js} +2 -2
  41. package/dist-cli/chunks/chunk-RV67J726.js +2 -0
  42. package/dist-cli/chunks/{chunk-UZA3Q67P.js → chunk-TJS5IMOH.js} +1 -1
  43. package/dist-cli/chunks/{chunk-KTTLGU7Y.js → chunk-U3564F2Y.js} +2 -2
  44. package/dist-cli/chunks/{chunk-3FBFOGQJ.js → chunk-UOHGYYSO.js} +1 -1
  45. package/dist-cli/chunks/{chunk-DLMAMKWL.js → chunk-UPKYK52K.js} +2 -2
  46. package/dist-cli/chunks/{chunk-GZON2OYB.js → chunk-USJTVC7T.js} +1 -1
  47. package/dist-cli/chunks/{chunk-U6GFEFUD.js → chunk-VO74GDXL.js} +3 -3
  48. package/dist-cli/chunks/{chunk-76O3ZWTI.js → chunk-VZ44FQDG.js} +1 -1
  49. package/dist-cli/chunks/chunk-WI36YJ23.js +2 -0
  50. package/dist-cli/chunks/{chunk-5NGZRMTN.js → chunk-WOWLO4LL.js} +1 -1
  51. package/dist-cli/chunks/chunk-WP3TFHFL.js +10 -0
  52. package/dist-cli/chunks/{chunk-KBG6WN24.js → chunk-WPPMUUML.js} +2 -2
  53. package/dist-cli/chunks/{chunk-ZYS5SEB2.js → chunk-WVMYRKSS.js} +2 -2
  54. package/dist-cli/chunks/chunk-YNG4C3ZS.js +2 -0
  55. package/dist-cli/chunks/{chunk-JTZNB4PB.js → chunk-YRFWATLA.js} +2 -2
  56. package/dist-cli/chunks/{cleanup-KXX5W42A.js → cleanup-BLFDJSFS.js} +2 -2
  57. package/dist-cli/chunks/cli-version-TQHZOK4L.js +2 -0
  58. package/dist-cli/chunks/{compat-VDVJ2I74.js → compat-Q3WCSTB7.js} +3 -3
  59. package/dist-cli/chunks/{config-FIQQP5FR.js → config-NHNMRRNB.js} +2 -2
  60. package/dist-cli/chunks/control-I7YBDRJT.js +2 -0
  61. package/dist-cli/chunks/daemon-4R3SZLZY.js +2 -0
  62. package/dist-cli/chunks/{debug-LPLH46JF.js → debug-PGRMZFXA.js} +3 -3
  63. package/dist-cli/chunks/{desktop-4HDRWKMN.js → desktop-NVTQ37LH.js} +3 -3
  64. package/dist-cli/chunks/{detox-U23WKW23.js → detox-W3JDXS76.js} +2 -2
  65. package/dist-cli/chunks/{device-HZKTA7ZV.js → device-KQYN3EVK.js} +2 -2
  66. package/dist-cli/chunks/{diagnose-M64QUWBW.js → diagnose-CPUKSGNO.js} +2 -2
  67. package/dist-cli/chunks/disk-cleanup-2COWZWBC.js +2 -0
  68. package/dist-cli/chunks/drivers-RRZM6E72.js +2 -0
  69. package/dist-cli/chunks/{film-4IB44CT3.js → film-VZGAZ2YY.js} +3 -3
  70. package/dist-cli/chunks/flow-VH6DFDQ4.js +2 -0
  71. package/dist-cli/chunks/help-3HQ2RINO.js +2 -0
  72. package/dist-cli/chunks/{hidden-runtime-alias-UEU5POA4.js → hidden-runtime-alias-KWHABCNZ.js} +2 -2
  73. package/dist-cli/chunks/{home-paths-2C4YKPPX.js → home-paths-O4CGYVHF.js} +2 -2
  74. package/dist-cli/chunks/inspect-PKMJGXDH.js +2 -0
  75. package/dist-cli/chunks/install-desktop-K5TP3ZHJ.js +2 -0
  76. package/dist-cli/chunks/{login-MY54AOXW.js → login-KPN4Z26Q.js} +4 -4
  77. package/dist-cli/chunks/{logout-LYR2RDJY.js → logout-E3UCJAMC.js} +2 -2
  78. package/dist-cli/chunks/{maestro-4RAMCNZQ.js → maestro-PYA4AHTS.js} +3 -3
  79. package/dist-cli/chunks/{maestro-generate-CBSUR73A.js → maestro-generate-KCMYWPWL.js} +3 -3
  80. package/dist-cli/chunks/{mode-2KATMMXB.js → mode-AEB7G2SJ.js} +2 -2
  81. package/dist-cli/chunks/optional-demo-registry-AIWOBAAA.js +2 -0
  82. package/dist-cli/chunks/{perf-FVL2ZRQW.js → perf-YLXGZI3E.js} +2 -2
  83. package/dist-cli/chunks/permissions-7VMVZOUV.js +11 -0
  84. package/dist-cli/chunks/{record-TCD4VLNH.js → record-AVQO45PE.js} +3 -3
  85. package/dist-cli/chunks/runtime-HOGETVVD.js +2 -0
  86. package/dist-cli/chunks/{screenshot-command-ENCJ4W2W.js → screenshot-command-LACQLA4N.js} +3 -3
  87. package/dist-cli/chunks/{screenshots-capture-FVVMZPFO.js → screenshots-capture-PROOBSGB.js} +2 -2
  88. package/dist-cli/chunks/{serve-HNHS3QBP.js → serve-FJN2FRGW.js} +2 -2
  89. package/dist-cli/chunks/{setup-MRLIGVU4.js → setup-IVV4NRYQ.js} +3 -3
  90. package/dist-cli/chunks/{skills-2LW5BE7P.js → skills-WYR3PJOH.js} +2 -2
  91. package/dist-cli/chunks/{storage-KH5HQF3V.js → storage-GM7K4MGM.js} +2 -2
  92. package/dist-cli/chunks/store-YLVHPKG7.js +2 -0
  93. package/dist-cli/chunks/telemetry-MQKB6PFX.js +2 -0
  94. package/dist-cli/chunks/{timeline-BWFBU4VM.js → timeline-R5UL3N4T.js} +2 -2
  95. package/dist-cli/chunks/{upgrade-GZFX4JEO.js → upgrade-RWHSFZRX.js} +2 -2
  96. package/dist-cli/chunks/upload-RBH4XGJ2.js +2 -0
  97. package/dist-cli/chunks/{version-OKMVZCP5.js → version-7K6TVQOW.js} +2 -2
  98. package/dist-cli/chunks/web-46ZPQCAL.js +2 -0
  99. package/dist-cli/chunks/{what-happened-MC7JDW6C.js → what-happened-K24TSJZX.js} +2 -2
  100. package/dist-lib/agent-daemon-client.cjs +1 -1
  101. package/dist-lib/agent-events.cjs +1 -1
  102. package/dist-lib/agent-identity.cjs +1 -1
  103. package/dist-lib/agent-sessions.cjs +1 -1
  104. package/dist-lib/attached-projects.cjs +1 -1
  105. package/dist-lib/auth/shared-session.cjs +1 -1
  106. package/dist-lib/backend-origin.cjs +1 -1
  107. package/dist-lib/beta.cjs +1 -1
  108. package/dist-lib/beta.mjs +1 -1
  109. package/dist-lib/bridge-constants.cjs +1 -1
  110. package/dist-lib/cli-constants.cjs +1 -1
  111. package/dist-lib/config.cjs +1 -1
  112. package/dist-lib/detox/index.cjs +24 -6
  113. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  114. package/dist-lib/home-paths.cjs +1 -1
  115. package/dist-lib/host/bridge-host.cjs +411 -66
  116. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  117. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  118. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  119. package/dist-lib/host/websocket-proxy.cjs +1 -1
  120. package/dist-lib/index.cjs +1 -1
  121. package/dist-lib/jump-to-source-babel.cjs +1 -1
  122. package/dist-lib/menu.cjs +38 -2
  123. package/dist-lib/menu.mjs +38 -2
  124. package/dist-lib/metro.cjs +1 -1
  125. package/dist-lib/profiles.cjs +1 -1
  126. package/dist-lib/render-mode.cjs +1 -1
  127. package/dist-lib/scripts/dev-server-scanner.cjs +354 -2
  128. package/dist-lib/sdk.cjs +1 -1
  129. package/dist-lib/sdk.mjs +1 -1
  130. package/dist-lib/skills.cjs +443 -91
  131. package/dist-lib/vite.cjs +1 -1
  132. package/package.json +2 -1
  133. package/scripts/dev-server-scanner.ts +27 -1
  134. package/skills/contrast/SKILL.md +1 -0
  135. package/src/menu.ts +38 -1
  136. package/src/settings-bundle.ts +439 -0
  137. package/dist-cli/chunks/beta-HKVUNMLY.js +0 -2
  138. package/dist-cli/chunks/chunk-5ZBUNUUE.js +0 -2
  139. package/dist-cli/chunks/chunk-7NW75BHD.js +0 -5
  140. package/dist-cli/chunks/chunk-H7F2BILD.js +0 -118
  141. package/dist-cli/chunks/chunk-IDZP6WN5.js +0 -2
  142. package/dist-cli/chunks/chunk-IGPDVTHJ.js +0 -2
  143. package/dist-cli/chunks/chunk-KU3T3N2W.js +0 -1
  144. package/dist-cli/chunks/chunk-ZEYCE3XJ.js +0 -2
  145. package/dist-cli/chunks/cli-version-IQXVYN67.js +0 -2
  146. package/dist-cli/chunks/control-GDBZBVQC.js +0 -2
  147. package/dist-cli/chunks/daemon-Y76JSFGV.js +0 -2
  148. package/dist-cli/chunks/disk-cleanup-P662TT6J.js +0 -2
  149. package/dist-cli/chunks/drivers-CKWEDYVG.js +0 -2
  150. package/dist-cli/chunks/flow-WDFYSQKC.js +0 -2
  151. package/dist-cli/chunks/help-2S3OHQLT.js +0 -2
  152. package/dist-cli/chunks/inspect-SKU24VE3.js +0 -2
  153. package/dist-cli/chunks/install-desktop-RKURHJ34.js +0 -2
  154. package/dist-cli/chunks/optional-demo-registry-26Q7AW7X.js +0 -2
  155. package/dist-cli/chunks/runtime-Z3D53UGW.js +0 -2
  156. package/dist-cli/chunks/store-IBEI6PK4.js +0 -2
  157. package/dist-cli/chunks/telemetry-3T56HLDZ.js +0 -2
  158. package/dist-cli/chunks/upload-PCXRS5D7.js +0 -2
  159. package/dist-cli/chunks/web-ZHCP6WFY.js +0 -2
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.291 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.293 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -142,6 +142,339 @@ function normalizeNativeDevBundleUrl(bundleUrl) {
142
142
  }
143
143
  }
144
144
 
145
+ // src/settings-bundle.ts
146
+ var import_promises = require("node:fs/promises");
147
+ var import_node_path = require("node:path");
148
+ var import_plist = __toESM(require("@expo/plist"), 1);
149
+ var MAX_PLIST_BYTES = 1048576;
150
+ var MAX_CHILD_DEPTH = 8;
151
+ var MAX_PLIST_FILES = 32;
152
+ var MAX_SPECIFIERS = 512;
153
+ var settingsBundleCache = /* @__PURE__ */ new Map();
154
+ function isRecord(value) {
155
+ return typeof value === "object" && value !== null && !Array.isArray(value);
156
+ }
157
+ function resolvePlistParser(value) {
158
+ if (!isRecord(value)) return null;
159
+ const direct = value.parse;
160
+ if (typeof direct === "function") {
161
+ return (source) => Reflect.apply(direct, value, [source]);
162
+ }
163
+ const nested = value.default;
164
+ if (!isRecord(nested)) return null;
165
+ const nestedParse = nested.parse;
166
+ return typeof nestedParse === "function" ? (source) => Reflect.apply(nestedParse, nested, [source]) : null;
167
+ }
168
+ var parsePlist = resolvePlistParser(import_plist.default);
169
+ function optionalString(value) {
170
+ return typeof value === "string" ? value : void 0;
171
+ }
172
+ function requiredString(value) {
173
+ if (typeof value !== "string") return null;
174
+ const normalized = value.trim();
175
+ return normalized ? normalized : null;
176
+ }
177
+ function finiteNumber(value) {
178
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
179
+ }
180
+ function preferenceValue(value) {
181
+ if (typeof value === "string" || typeof value === "boolean") return value;
182
+ return finiteNumber(value);
183
+ }
184
+ function keyboardType(value) {
185
+ if (typeof value !== "string") return void 0;
186
+ switch (value.replaceAll(/[-_\s]/g, "").toLowerCase()) {
187
+ case "alphabet":
188
+ return "alphabet";
189
+ case "numbersandpunctuation":
190
+ return "numbers-and-punctuation";
191
+ case "numberpad":
192
+ return "number-pad";
193
+ case "url":
194
+ return "url";
195
+ case "emailaddress":
196
+ return "email-address";
197
+ case "namephonepad":
198
+ return "name-phone-pad";
199
+ case "asciicapable":
200
+ return "ascii-capable";
201
+ default:
202
+ return void 0;
203
+ }
204
+ }
205
+ function autocapitalization(value) {
206
+ if (typeof value !== "string") return void 0;
207
+ switch (value.replaceAll(/[-_\s]/g, "").toLowerCase()) {
208
+ case "none":
209
+ return "none";
210
+ case "sentences":
211
+ return "sentences";
212
+ case "words":
213
+ return "words";
214
+ case "allcharacters":
215
+ return "all-characters";
216
+ default:
217
+ return void 0;
218
+ }
219
+ }
220
+ function autocorrection(value) {
221
+ if (typeof value === "boolean") return value;
222
+ if (typeof value !== "string") return void 0;
223
+ switch (value.trim().toLowerCase()) {
224
+ case "yes":
225
+ return true;
226
+ case "no":
227
+ return false;
228
+ default:
229
+ return void 0;
230
+ }
231
+ }
232
+ function safeChildPlistName(value) {
233
+ const file = requiredString(value);
234
+ if (!file || file.includes("/") || file.includes("\\") || file.includes("..")) {
235
+ return null;
236
+ }
237
+ return {
238
+ file,
239
+ name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
240
+ };
241
+ }
242
+ async function readableSettingsBundle(path9) {
243
+ try {
244
+ const root = await (0, import_promises.stat)((0, import_node_path.join)(path9, "Root.plist"));
245
+ return root.isFile() && root.size <= MAX_PLIST_BYTES;
246
+ } catch {
247
+ return false;
248
+ }
249
+ }
250
+ async function findSettingsBundle(projectRoot) {
251
+ const directCandidates = [
252
+ (0, import_node_path.join)(projectRoot, "Settings.bundle"),
253
+ (0, import_node_path.join)(projectRoot, "ios", "Settings.bundle")
254
+ ];
255
+ for (const candidate of directCandidates) {
256
+ if (await readableSettingsBundle(candidate)) return candidate;
257
+ }
258
+ try {
259
+ const iosRoot = (0, import_node_path.join)(projectRoot, "ios");
260
+ const children = await (0, import_promises.readdir)(iosRoot, { withFileTypes: true });
261
+ const candidates = children.filter(
262
+ (entry) => entry.isDirectory() && entry.name !== "Pods" && entry.name !== "build" && !entry.name.startsWith(".")
263
+ ).map((entry) => (0, import_node_path.join)(iosRoot, entry.name, "Settings.bundle")).sort();
264
+ for (const candidate of candidates) {
265
+ if (await readableSettingsBundle(candidate)) return candidate;
266
+ }
267
+ } catch {
268
+ }
269
+ return null;
270
+ }
271
+ async function settingsBundleFingerprint(bundlePath) {
272
+ try {
273
+ const entries = await (0, import_promises.readdir)(bundlePath, { withFileTypes: true });
274
+ const names = entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".plist")).map((entry) => entry.name).sort().slice(0, MAX_PLIST_FILES + 1);
275
+ if (names.length === 0 || names.length > MAX_PLIST_FILES) return null;
276
+ const parts = await Promise.all(
277
+ names.map(async (name) => {
278
+ const metadata = await (0, import_promises.stat)((0, import_node_path.join)(bundlePath, name));
279
+ if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
280
+ return `${name}:${metadata.size}:${metadata.mtimeMs}:${metadata.ctimeMs}`;
281
+ })
282
+ );
283
+ if (parts.some((part) => part === null)) return null;
284
+ return parts.join("|");
285
+ } catch {
286
+ return null;
287
+ }
288
+ }
289
+ async function parsePlistRecord(path9) {
290
+ try {
291
+ if (!parsePlist) return null;
292
+ const metadata = await (0, import_promises.stat)(path9);
293
+ if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
294
+ const source = await (0, import_promises.readFile)(path9, "utf8");
295
+ const parsed = parsePlist(source);
296
+ return isRecord(parsed) ? parsed : null;
297
+ } catch {
298
+ return null;
299
+ }
300
+ }
301
+ function normalizeMultiValue(raw, key, title) {
302
+ if (!Array.isArray(raw.Values) || !Array.isArray(raw.Titles)) return null;
303
+ const values = [];
304
+ const titles = [];
305
+ let optionType;
306
+ const pairCount = Math.min(raw.Values.length, raw.Titles.length);
307
+ for (let index = 0; index < pairCount; index++) {
308
+ const value = preferenceValue(raw.Values[index]);
309
+ const optionTitle = optionalString(raw.Titles[index]);
310
+ if (value === null || optionTitle === void 0) continue;
311
+ const valueType = typeof value === "string" ? "string" : typeof value === "number" ? "number" : "boolean";
312
+ if (optionType !== void 0 && valueType !== optionType) continue;
313
+ optionType = valueType;
314
+ values.push(value);
315
+ titles.push(optionTitle);
316
+ }
317
+ const firstValue = values[0];
318
+ if (firstValue === void 0) return null;
319
+ const declaredDefault = preferenceValue(raw.DefaultValue);
320
+ const defaultValue = declaredDefault !== null && values.includes(declaredDefault) ? declaredDefault : firstValue;
321
+ return {
322
+ type: "multi-value",
323
+ key,
324
+ title,
325
+ defaultValue,
326
+ currentValue: defaultValue,
327
+ values,
328
+ titles
329
+ };
330
+ }
331
+ async function normalizeSpecifier(raw, context) {
332
+ if (!isRecord(raw)) return null;
333
+ if (context.budget.specifiers >= MAX_SPECIFIERS) return null;
334
+ const type = requiredString(raw.Type);
335
+ if (!type) return null;
336
+ context.budget.specifiers += 1;
337
+ if (type === "PSGroupSpecifier") {
338
+ const title2 = optionalString(raw.Title);
339
+ const footer = optionalString(raw.FooterText);
340
+ return {
341
+ type: "group",
342
+ ...title2 !== void 0 ? { title: title2 } : null,
343
+ ...footer !== void 0 ? { footer } : null
344
+ };
345
+ }
346
+ const key = requiredString(raw.Key);
347
+ if (type === "PSSliderSpecifier") {
348
+ if (!key) return null;
349
+ const minimumValue = finiteNumber(raw.MinimumValue);
350
+ const maximumValue = finiteNumber(raw.MaximumValue);
351
+ if (minimumValue === null || maximumValue === null || maximumValue <= minimumValue) {
352
+ return null;
353
+ }
354
+ const declaredDefault = finiteNumber(raw.DefaultValue);
355
+ const defaultValue = Math.min(
356
+ maximumValue,
357
+ Math.max(minimumValue, declaredDefault ?? minimumValue)
358
+ );
359
+ const title2 = optionalString(raw.Title);
360
+ const minimumValueImage = optionalString(raw.MinimumValueImage);
361
+ const maximumValueImage = optionalString(raw.MaximumValueImage);
362
+ return {
363
+ type: "slider",
364
+ key,
365
+ defaultValue,
366
+ currentValue: defaultValue,
367
+ minimumValue,
368
+ maximumValue,
369
+ ...title2 !== void 0 ? { title: title2 } : null,
370
+ ...minimumValueImage !== void 0 ? { minimumValueImage } : null,
371
+ ...maximumValueImage !== void 0 ? { maximumValueImage } : null
372
+ };
373
+ }
374
+ if (type === "PSChildPaneSpecifier") {
375
+ const title2 = requiredString(raw.Title);
376
+ const child = safeChildPlistName(raw.File);
377
+ if (!title2 || !child || context.depth >= MAX_CHILD_DEPTH) return null;
378
+ const childSpecifiers = await parseSpecifierFile(child.name, {
379
+ ...context,
380
+ depth: context.depth + 1
381
+ });
382
+ if (!childSpecifiers || childSpecifiers.length === 0) return null;
383
+ return {
384
+ type: "child-pane",
385
+ title: title2,
386
+ file: child.file,
387
+ specifiers: childSpecifiers
388
+ };
389
+ }
390
+ if (!key) return null;
391
+ const title = requiredString(raw.Title) ?? key;
392
+ if (type === "PSToggleSwitchSpecifier") {
393
+ const defaultValue = typeof raw.DefaultValue === "boolean" ? raw.DefaultValue : false;
394
+ return {
395
+ type: "toggle",
396
+ key,
397
+ title,
398
+ defaultValue,
399
+ currentValue: defaultValue
400
+ };
401
+ }
402
+ if (type === "PSTextFieldSpecifier") {
403
+ const defaultValue = optionalString(raw.DefaultValue) ?? "";
404
+ const placeholder = optionalString(raw.Placeholder);
405
+ const resolvedKeyboardType = keyboardType(raw.KeyboardType);
406
+ const resolvedAutocapitalization = autocapitalization(raw.AutocapitalizationType);
407
+ const resolvedAutocorrection = autocorrection(raw.AutocorrectionType);
408
+ return {
409
+ type: "text",
410
+ key,
411
+ title,
412
+ defaultValue,
413
+ currentValue: defaultValue,
414
+ ...placeholder !== void 0 ? { placeholder } : null,
415
+ ...typeof raw.IsSecure === "boolean" ? { secure: raw.IsSecure } : null,
416
+ ...resolvedKeyboardType ? { keyboardType: resolvedKeyboardType } : null,
417
+ ...resolvedAutocapitalization ? { autocapitalization: resolvedAutocapitalization } : null,
418
+ ...resolvedAutocorrection !== void 0 ? { autocorrection: resolvedAutocorrection } : null
419
+ };
420
+ }
421
+ if (type === "PSMultiValueSpecifier" || type === "PSRadioGroupSpecifier") {
422
+ return normalizeMultiValue(raw, key, title);
423
+ }
424
+ if (type === "PSTitleValueSpecifier") {
425
+ const defaultValue = preferenceValue(raw.DefaultValue) ?? "";
426
+ return {
427
+ type: "title-value",
428
+ key,
429
+ title,
430
+ defaultValue,
431
+ currentValue: defaultValue
432
+ };
433
+ }
434
+ return null;
435
+ }
436
+ async function parseSpecifierFile(fileName, context) {
437
+ const cached3 = context.fileCache.get(fileName);
438
+ if (cached3 !== void 0) return cached3;
439
+ if (context.stack.has(fileName) || context.budget.files >= MAX_PLIST_FILES) {
440
+ return null;
441
+ }
442
+ context.budget.files += 1;
443
+ const root = await parsePlistRecord((0, import_node_path.join)(context.bundlePath, fileName));
444
+ if (!root || !Array.isArray(root.PreferenceSpecifiers)) {
445
+ context.fileCache.set(fileName, null);
446
+ return null;
447
+ }
448
+ const stack = new Set(context.stack);
449
+ stack.add(fileName);
450
+ const specifiers = [];
451
+ for (const raw of root.PreferenceSpecifiers) {
452
+ if (context.budget.specifiers >= MAX_SPECIFIERS) break;
453
+ const specifier = await normalizeSpecifier(raw, { ...context, stack });
454
+ if (specifier) specifiers.push(specifier);
455
+ }
456
+ context.fileCache.set(fileName, specifiers);
457
+ return specifiers;
458
+ }
459
+ async function readAppSettingsBundle(projectRoot) {
460
+ const bundlePath = await findSettingsBundle(projectRoot);
461
+ if (!bundlePath) return null;
462
+ const fingerprint = await settingsBundleFingerprint(bundlePath);
463
+ if (!fingerprint) return null;
464
+ const cached3 = settingsBundleCache.get(bundlePath);
465
+ if (cached3?.fingerprint === fingerprint) return cached3.specifiers;
466
+ const specifiers = await parseSpecifierFile("Root.plist", {
467
+ bundlePath,
468
+ depth: 0,
469
+ budget: { files: 0, specifiers: 0 },
470
+ stack: /* @__PURE__ */ new Set(),
471
+ fileCache: /* @__PURE__ */ new Map()
472
+ });
473
+ const normalized = specifiers && specifiers.length > 0 ? specifiers : null;
474
+ settingsBundleCache.set(bundlePath, { fingerprint, specifiers: normalized });
475
+ return normalized;
476
+ }
477
+
145
478
  // scripts/dev-server-scanner.ts
146
479
  init_optional_demo_registry();
147
480
  var execP = (0, import_util.promisify)(import_child_process.exec);
@@ -508,6 +841,16 @@ function __shouldReuseScannerCacheEntry(entry, pid, now = Date.now()) {
508
841
  if (isWeakCachedResult(entry.result) && ageMs >= WEAK_RESULT_CACHE_TTL_MS) return false;
509
842
  return true;
510
843
  }
844
+ async function attachAppSettingsBundle(result, projectRoot) {
845
+ const settingsBundle = await readAppSettingsBundle(projectRoot);
846
+ if (settingsBundle) {
847
+ result.settingsBundle = settingsBundle;
848
+ result.settingsStorageScopeUrl = result.bundleUrl;
849
+ } else {
850
+ delete result.settingsBundle;
851
+ delete result.settingsStorageScopeUrl;
852
+ }
853
+ }
511
854
  async function scanDevServers(opts = {}) {
512
855
  await loadOptionalDemoApps();
513
856
  const processes = await discoverListeningProcesses(opts.excludePorts);
@@ -563,7 +906,9 @@ async function scanDevServers(opts = {}) {
563
906
  if (!pid) return;
564
907
  result.pid = pid;
565
908
  const cwd = await resolveProcessCwd(pid);
566
- if (cwd) result.cwd = cwd;
909
+ if (!cwd) return;
910
+ result.cwd = cwd;
911
+ await attachAppSettingsBundle(result, cwd);
567
912
  })
568
913
  );
569
914
  const livePids = new Set(pidByPort.values());
@@ -606,7 +951,7 @@ function getCliVersion() {
606
951
  // src/home-paths.ts
607
952
  var import_node_fs2 = __toESM(require("node:fs"), 1);
608
953
  var import_node_os = require("node:os");
609
- var import_node_path = __toESM(require("node:path"), 1);
954
+ var import_node_path2 = __toESM(require("node:path"), 1);
610
955
  var SOOTSIM_HOME_ENV = "SOOTSIM_HOME";
611
956
  var ACTIVE_RUNTIME_FILE = "active";
612
957
  var DAEMON_LOCKFILE = "daemon.json";
@@ -615,8 +960,8 @@ var CONFIG_FILE = "config.json";
615
960
  var DAEMON_HEARTBEAT_STALE_MS = 3e4;
616
961
  function sootsimHomeDir() {
617
962
  const override = process.env[SOOTSIM_HOME_ENV];
618
- if (override && override.length > 0) return import_node_path.default.resolve(override);
619
- return import_node_path.default.join((0, import_node_os.homedir)(), ".sootsim");
963
+ if (override && override.length > 0) return import_node_path2.default.resolve(override);
964
+ return import_node_path2.default.join((0, import_node_os.homedir)(), ".sootsim");
620
965
  }
621
966
  function isSootsimDevCheckout() {
622
967
  if (process.env.SOOTSIM_FORCE_DAEMON_INSTALL === "1") return false;
@@ -627,40 +972,40 @@ function isSootsimDevCheckout() {
627
972
  if (!argv1) return false;
628
973
  try {
629
974
  const real = import_node_fs2.default.realpathSync(argv1);
630
- return real.includes(`${import_node_path.default.sep}packages${import_node_path.default.sep}sootsim${import_node_path.default.sep}`);
975
+ return real.includes(`${import_node_path2.default.sep}packages${import_node_path2.default.sep}sootsim${import_node_path2.default.sep}`);
631
976
  } catch {
632
977
  return false;
633
978
  }
634
979
  }
635
980
  function runtimesDir() {
636
- return import_node_path.default.join(sootsimHomeDir(), "runtimes");
981
+ return import_node_path2.default.join(sootsimHomeDir(), "runtimes");
637
982
  }
638
983
  function runtimeDir(version) {
639
- return import_node_path.default.join(runtimesDir(), version);
984
+ return import_node_path2.default.join(runtimesDir(), version);
640
985
  }
641
986
  function activeRuntimeFile() {
642
- return import_node_path.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
987
+ return import_node_path2.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
643
988
  }
644
989
  function electronDir() {
645
- return import_node_path.default.join(sootsimHomeDir(), "electron");
990
+ return import_node_path2.default.join(sootsimHomeDir(), "electron");
646
991
  }
647
992
  function electronUserDataDir() {
648
- return import_node_path.default.join(electronDir(), "userData");
993
+ return import_node_path2.default.join(electronDir(), "userData");
649
994
  }
650
995
  function profilesDir() {
651
- return import_node_path.default.join(sootsimHomeDir(), "profiles");
996
+ return import_node_path2.default.join(sootsimHomeDir(), "profiles");
652
997
  }
653
998
  function cacheDir() {
654
- return import_node_path.default.join(sootsimHomeDir(), "cache");
999
+ return import_node_path2.default.join(sootsimHomeDir(), "cache");
655
1000
  }
656
1001
  function daemonLockfilePath() {
657
- return import_node_path.default.join(sootsimHomeDir(), DAEMON_LOCKFILE);
1002
+ return import_node_path2.default.join(sootsimHomeDir(), DAEMON_LOCKFILE);
658
1003
  }
659
1004
  function devBridgeLockfilePath() {
660
- return import_node_path.default.join(sootsimHomeDir(), DEV_BRIDGE_LOCKFILE);
1005
+ return import_node_path2.default.join(sootsimHomeDir(), DEV_BRIDGE_LOCKFILE);
661
1006
  }
662
1007
  function configFilePath() {
663
- return import_node_path.default.join(sootsimHomeDir(), CONFIG_FILE);
1008
+ return import_node_path2.default.join(sootsimHomeDir(), CONFIG_FILE);
664
1009
  }
665
1010
  function readSharedConfig() {
666
1011
  try {
@@ -688,7 +1033,7 @@ function writeSharedConfig(patch) {
688
1033
  return next;
689
1034
  }
690
1035
  function runtimeUpgradeNoticePath() {
691
- return import_node_path.default.join(sootsimHomeDir(), "runtime-upgraded.json");
1036
+ return import_node_path2.default.join(sootsimHomeDir(), "runtime-upgraded.json");
692
1037
  }
693
1038
  function writeRuntimeUpgradeNotice(notice) {
694
1039
  ensureSootsimHome();
@@ -826,13 +1171,13 @@ function resolveDevCheckoutRuntimeRoot() {
826
1171
  var import_node_child_process = require("node:child_process");
827
1172
  var import_node_crypto = __toESM(require("node:crypto"), 1);
828
1173
  var import_node_fs4 = __toESM(require("node:fs"), 1);
829
- var import_node_path3 = __toESM(require("node:path"), 1);
1174
+ var import_node_path4 = __toESM(require("node:path"), 1);
830
1175
  var import_node_stream = require("node:stream");
831
- var import_promises = require("node:stream/promises");
1176
+ var import_promises2 = require("node:stream/promises");
832
1177
 
833
1178
  // ../contrast-runtime-delivery/src/product.ts
834
1179
  var import_node_fs3 = __toESM(require("node:fs"), 1);
835
- var import_node_path2 = __toESM(require("node:path"), 1);
1180
+ var import_node_path3 = __toESM(require("node:path"), 1);
836
1181
  function listInstalledRuntimes(product) {
837
1182
  try {
838
1183
  return import_node_fs3.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
@@ -841,7 +1186,7 @@ function listInstalledRuntimes(product) {
841
1186
  }
842
1187
  }
843
1188
  function runtimeTarballCacheName(product, version) {
844
- return import_node_path2.default.posix.basename(product.tarballPath(version));
1189
+ return import_node_path3.default.posix.basename(product.tarballPath(version));
845
1190
  }
846
1191
  function compareSemver(a, b) {
847
1192
  const parse = (v) => {
@@ -933,7 +1278,7 @@ function createRuntimeDelivery(product) {
933
1278
  const destDir = product.runtimeDir(version);
934
1279
  const setActive = opts.setActive !== false;
935
1280
  pruneLocalRetention({ protectVersions: [version] });
936
- if (!opts.force && import_node_fs4.default.existsSync(import_node_path3.default.join(destDir, product.installedMarker))) {
1281
+ if (!opts.force && import_node_fs4.default.existsSync(import_node_path4.default.join(destDir, product.installedMarker))) {
937
1282
  if (setActive) product.writeActiveRuntime(version);
938
1283
  pruneLocalRetention({ protectVersions: [version] });
939
1284
  return {
@@ -947,7 +1292,7 @@ function createRuntimeDelivery(product) {
947
1292
  };
948
1293
  }
949
1294
  const tarUrl = entry.tarball || tarballUrl(version, cdnOrigin);
950
- const tarCachePath = import_node_path3.default.join(
1295
+ const tarCachePath = import_node_path4.default.join(
951
1296
  product.cacheDir(),
952
1297
  runtimeTarballCacheName(product, version)
953
1298
  );
@@ -956,8 +1301,8 @@ function createRuntimeDelivery(product) {
956
1301
  await downloadToFile(tarUrl, tarCachePath);
957
1302
  process.stderr.write(`${product.id}: extracting runtime ${version}\u2026
958
1303
  `);
959
- const tmpDir = import_node_path3.default.join(
960
- import_node_path3.default.dirname(destDir),
1304
+ const tmpDir = import_node_path4.default.join(
1305
+ import_node_path4.default.dirname(destDir),
961
1306
  `.installing-${version}-${process.pid}`
962
1307
  );
963
1308
  import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
@@ -970,7 +1315,7 @@ function createRuntimeDelivery(product) {
970
1315
  }
971
1316
  import_node_fs4.default.mkdirSync(tmpDir, { recursive: true });
972
1317
  await extractTarball(tarCachePath, tmpDir);
973
- if (!import_node_fs4.default.existsSync(import_node_path3.default.join(tmpDir, product.installedMarker))) {
1318
+ if (!import_node_fs4.default.existsSync(import_node_path4.default.join(tmpDir, product.installedMarker))) {
974
1319
  throw new Error(
975
1320
  `extracted tarball for runtime ${version} is missing ${product.installedMarker}`
976
1321
  );
@@ -1004,7 +1349,7 @@ function createRuntimeDelivery(product) {
1004
1349
  if (pin) {
1005
1350
  const activeVersion2 = product.readActiveRuntime();
1006
1351
  const pinInstalled = import_node_fs4.default.existsSync(
1007
- import_node_path3.default.join(product.runtimeDir(pin), product.installedMarker)
1352
+ import_node_path4.default.join(product.runtimeDir(pin), product.installedMarker)
1008
1353
  );
1009
1354
  if (activeVersion2 === pin && pinInstalled) {
1010
1355
  return {
@@ -1052,7 +1397,7 @@ function createRuntimeDelivery(product) {
1052
1397
  }
1053
1398
  const activeVersion = product.readActiveRuntime();
1054
1399
  const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
1055
- const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path3.default.join(activeDir, product.installedMarker)) : false;
1400
+ const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path4.default.join(activeDir, product.installedMarker)) : false;
1056
1401
  const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
1057
1402
  if (!shouldInstall) {
1058
1403
  return {
@@ -1128,7 +1473,7 @@ function createRuntimeDelivery(product) {
1128
1473
  const complete = entry.name.startsWith(cachePrefix) && entry.name.endsWith(cacheSuffix);
1129
1474
  const partial = entry.name.startsWith(cachePrefix) && entry.name.endsWith(`${cacheSuffix}.partial`);
1130
1475
  return complete || partial;
1131
- }).map((entry) => import_node_path3.default.join(product.cacheDir(), entry.name)).sort();
1476
+ }).map((entry) => import_node_path4.default.join(product.cacheDir(), entry.name)).sort();
1132
1477
  } catch {
1133
1478
  }
1134
1479
  }
@@ -1172,10 +1517,10 @@ async function downloadToFile(url, destPath) {
1172
1517
  if (!res.ok || !res.body) {
1173
1518
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
1174
1519
  }
1175
- import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(destPath), { recursive: true });
1520
+ import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(destPath), { recursive: true });
1176
1521
  const tmp = `${destPath}.partial`;
1177
1522
  try {
1178
- await (0, import_promises.pipeline)(
1523
+ await (0, import_promises2.pipeline)(
1179
1524
  import_node_stream.Readable.fromWeb(res.body),
1180
1525
  import_node_fs4.default.createWriteStream(tmp)
1181
1526
  );
@@ -1238,13 +1583,13 @@ var sootsimRuntime = createRuntimeDelivery(SOOTSIM_RUNTIME_PRODUCT);
1238
1583
 
1239
1584
  // src/host/agent-host.ts
1240
1585
  var import_node_fs7 = __toESM(require("node:fs"), 1);
1241
- var import_node_path6 = __toESM(require("node:path"), 1);
1586
+ var import_node_path7 = __toESM(require("node:path"), 1);
1242
1587
 
1243
1588
  // src/agent-sessions.ts
1244
1589
  var import_node_child_process2 = require("node:child_process");
1245
1590
  var import_node_crypto3 = require("node:crypto");
1246
1591
  var import_node_fs6 = __toESM(require("node:fs"), 1);
1247
- var import_node_path5 = __toESM(require("node:path"), 1);
1592
+ var import_node_path6 = __toESM(require("node:path"), 1);
1248
1593
  var import_node_readline = __toESM(require("node:readline"), 1);
1249
1594
 
1250
1595
  // src/agent-events.ts
@@ -1289,7 +1634,7 @@ function encodeAgentPromptEnvelope(input) {
1289
1634
  // src/attached-projects.ts
1290
1635
  var import_node_crypto2 = require("node:crypto");
1291
1636
  var import_node_fs5 = __toESM(require("node:fs"), 1);
1292
- var import_node_path4 = __toESM(require("node:path"), 1);
1637
+ var import_node_path5 = __toESM(require("node:path"), 1);
1293
1638
  var overrideDir = null;
1294
1639
  function userDataDir() {
1295
1640
  if (overrideDir) return overrideDir;
@@ -1301,7 +1646,7 @@ function getUserDataDir() {
1301
1646
  return userDataDir();
1302
1647
  }
1303
1648
  function storeFile() {
1304
- return import_node_path4.default.join(userDataDir(), "attached-projects.json");
1649
+ return import_node_path5.default.join(userDataDir(), "attached-projects.json");
1305
1650
  }
1306
1651
  function cloneEmpty() {
1307
1652
  return {
@@ -1343,7 +1688,7 @@ function loadStore() {
1343
1688
  }
1344
1689
  function writeStore(store) {
1345
1690
  const file = storeFile();
1346
- import_node_fs5.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
1691
+ import_node_fs5.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
1347
1692
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
1348
1693
  const fd = import_node_fs5.default.openSync(tmp, "w", 384);
1349
1694
  try {
@@ -1361,13 +1706,13 @@ function mutateStore(fn) {
1361
1706
  return store;
1362
1707
  }
1363
1708
  function projectIdForCwd(cwd) {
1364
- return (0, import_node_crypto2.createHash)("sha256").update(import_node_path4.default.resolve(cwd)).digest("hex").slice(0, 16);
1709
+ return (0, import_node_crypto2.createHash)("sha256").update(import_node_path5.default.resolve(cwd)).digest("hex").slice(0, 16);
1365
1710
  }
1366
1711
  function newSessionId() {
1367
1712
  return `s_${(0, import_node_crypto2.randomBytes)(10).toString("hex")}`;
1368
1713
  }
1369
1714
  function upsertProject(input) {
1370
- const cwd = import_node_path4.default.resolve(input.cwd);
1715
+ const cwd = import_node_path5.default.resolve(input.cwd);
1371
1716
  const id = projectIdForCwd(cwd);
1372
1717
  let result;
1373
1718
  mutateStore((store) => {
@@ -1393,7 +1738,7 @@ function upsertProject(input) {
1393
1738
  const now = Date.now();
1394
1739
  const created = {
1395
1740
  id,
1396
- name: input.name ?? import_node_path4.default.basename(cwd),
1741
+ name: input.name ?? import_node_path5.default.basename(cwd),
1397
1742
  cwd,
1398
1743
  repoRoot: input.repoRoot,
1399
1744
  sourceRoots: input.sourceRoots ?? [cwd],
@@ -1540,7 +1885,7 @@ async function seedFromDemoAppRegistry() {
1540
1885
  mutateStore((store) => {
1541
1886
  for (const app of apps) {
1542
1887
  if (!import_node_fs5.default.existsSync(app.dir)) continue;
1543
- const cwd = import_node_path4.default.resolve(app.dir);
1888
+ const cwd = import_node_path5.default.resolve(app.dir);
1544
1889
  const id = projectIdForCwd(cwd);
1545
1890
  if (store.attachedProjects.some((p) => p.id === id)) continue;
1546
1891
  const now = Date.now();
@@ -1564,16 +1909,16 @@ async function seedFromDemoAppRegistry() {
1564
1909
 
1565
1910
  // src/agent-sessions.ts
1566
1911
  function sessionDir(sessionId) {
1567
- return import_node_path5.default.join(getUserDataDir(), "sessions", sessionId);
1912
+ return import_node_path6.default.join(getUserDataDir(), "sessions", sessionId);
1568
1913
  }
1569
1914
  function promptFifoPath(sessionId) {
1570
- return import_node_path5.default.join(sessionDir(sessionId), "prompt.in");
1915
+ return import_node_path6.default.join(sessionDir(sessionId), "prompt.in");
1571
1916
  }
1572
1917
  function eventsFifoPath(sessionId) {
1573
- return import_node_path5.default.join(sessionDir(sessionId), "events.out");
1918
+ return import_node_path6.default.join(sessionDir(sessionId), "events.out");
1574
1919
  }
1575
1920
  function transcriptPath(sessionId) {
1576
- return import_node_path5.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
1921
+ return import_node_path6.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
1577
1922
  }
1578
1923
  function pidIsAlive(pid, sessionId) {
1579
1924
  if (!pid) return false;
@@ -1595,8 +1940,8 @@ function resolveSootsimInvocation() {
1595
1940
  const resourcesPath = process.resourcesPath;
1596
1941
  if (resourcesPath) {
1597
1942
  const candidates = [
1598
- import_node_path5.default.join(resourcesPath, "bin", "sootsim"),
1599
- import_node_path5.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
1943
+ import_node_path6.default.join(resourcesPath, "bin", "sootsim"),
1944
+ import_node_path6.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
1600
1945
  ];
1601
1946
  for (const c of candidates) {
1602
1947
  if (import_node_fs6.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
@@ -1622,12 +1967,12 @@ function tryWorkspaceSootsim() {
1622
1967
  const sootsimDir = resolveSootsimPackageDir();
1623
1968
  if (!sootsimDir) return null;
1624
1969
  const binaryName = `sootsim-${process.platform}-${process.arch}`;
1625
- const distBinary = import_node_path5.default.join(sootsimDir, "dist-bin", binaryName);
1970
+ const distBinary = import_node_path6.default.join(sootsimDir, "dist-bin", binaryName);
1626
1971
  if (import_node_fs6.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
1627
- const distBin = import_node_path5.default.join(sootsimDir, "dist-cli", "bin.js");
1972
+ const distBin = import_node_path6.default.join(sootsimDir, "dist-cli", "bin.js");
1628
1973
  if (import_node_fs6.default.existsSync(distBin)) {
1629
1974
  try {
1630
- const src = import_node_path5.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
1975
+ const src = import_node_path6.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
1631
1976
  if (import_node_fs6.default.existsSync(src)) {
1632
1977
  const srcMtime = import_node_fs6.default.statSync(src).mtimeMs;
1633
1978
  const buildMtime = import_node_fs6.default.statSync(distBin).mtimeMs;
@@ -1649,14 +1994,14 @@ function tryWorkspaceSootsim() {
1649
1994
  function resolveSootsimPackageDir() {
1650
1995
  try {
1651
1996
  const resolved = require.resolve("sootsim/package.json");
1652
- return import_node_path5.default.dirname(resolved);
1997
+ return import_node_path6.default.dirname(resolved);
1653
1998
  } catch {
1654
1999
  }
1655
2000
  const here = fileFromImportMeta();
1656
2001
  if (!here) return null;
1657
- let cur = import_node_path5.default.dirname(here);
2002
+ let cur = import_node_path6.default.dirname(here);
1658
2003
  for (let i = 0; i < 8; i++) {
1659
- const pkg = import_node_path5.default.join(cur, "package.json");
2004
+ const pkg = import_node_path6.default.join(cur, "package.json");
1660
2005
  try {
1661
2006
  if (import_node_fs6.default.existsSync(pkg)) {
1662
2007
  const parsed = JSON.parse(import_node_fs6.default.readFileSync(pkg, "utf8"));
@@ -1664,7 +2009,7 @@ function resolveSootsimPackageDir() {
1664
2009
  }
1665
2010
  } catch {
1666
2011
  }
1667
- const parent = import_node_path5.default.dirname(cur);
2012
+ const parent = import_node_path6.default.dirname(cur);
1668
2013
  if (parent === cur) break;
1669
2014
  cur = parent;
1670
2015
  }
@@ -1680,13 +2025,13 @@ function fileFromImportMeta() {
1680
2025
  }
1681
2026
  }
1682
2027
  async function withStartLock(projectId, provider, fn) {
1683
- const lockDir = import_node_path5.default.join(getUserDataDir(), "locks");
2028
+ const lockDir = import_node_path6.default.join(getUserDataDir(), "locks");
1684
2029
  import_node_fs6.default.mkdirSync(lockDir, { recursive: true });
1685
2030
  try {
1686
2031
  import_node_fs6.default.chmodSync(lockDir, 448);
1687
2032
  } catch {
1688
2033
  }
1689
- const lockPath = import_node_path5.default.join(lockDir, `start-${projectId}-${provider}.lock`);
2034
+ const lockPath = import_node_path6.default.join(lockDir, `start-${projectId}-${provider}.lock`);
1690
2035
  const deadline = Date.now() + 4e3;
1691
2036
  let fd = null;
1692
2037
  while (fd === null) {
@@ -1737,7 +2082,7 @@ function isProcessAlive(pid) {
1737
2082
  }
1738
2083
  }
1739
2084
  function mkfifoSync(p) {
1740
- const parent = import_node_path5.default.dirname(p);
2085
+ const parent = import_node_path6.default.dirname(p);
1741
2086
  import_node_fs6.default.mkdirSync(parent, { recursive: true });
1742
2087
  try {
1743
2088
  import_node_fs6.default.chmodSync(parent, 448);
@@ -1745,8 +2090,8 @@ function mkfifoSync(p) {
1745
2090
  }
1746
2091
  if (import_node_fs6.default.existsSync(p)) {
1747
2092
  try {
1748
- const stat = import_node_fs6.default.statSync(p);
1749
- if (stat.isFIFO()) {
2093
+ const stat2 = import_node_fs6.default.statSync(p);
2094
+ if (stat2.isFIFO()) {
1750
2095
  try {
1751
2096
  import_node_fs6.default.chmodSync(p, 384);
1752
2097
  } catch {
@@ -1802,7 +2147,7 @@ async function startSession(opts) {
1802
2147
  const transcript = transcriptPath(session.id);
1803
2148
  mkfifoSync(promptIn);
1804
2149
  mkfifoSync(eventsOut);
1805
- const transcriptDir = import_node_path5.default.dirname(transcript);
2150
+ const transcriptDir = import_node_path6.default.dirname(transcript);
1806
2151
  import_node_fs6.default.mkdirSync(transcriptDir, { recursive: true });
1807
2152
  try {
1808
2153
  import_node_fs6.default.chmodSync(transcriptDir, 448);
@@ -2260,7 +2605,7 @@ var AgentHost = class {
2260
2605
  );
2261
2606
  const project = upsertProject({
2262
2607
  cwd: match.cwd,
2263
- name: match.projectName ?? import_node_path6.default.basename(match.cwd),
2608
+ name: match.projectName ?? import_node_path7.default.basename(match.cwd),
2264
2609
  preferredProvider: input.provider ?? existing?.preferredProvider,
2265
2610
  sourceRoots: existing?.sourceRoots ?? [match.cwd],
2266
2611
  knownBundleUrls,
@@ -2280,9 +2625,9 @@ var AgentHost = class {
2280
2625
  const dir = getUserDataDir();
2281
2626
  return {
2282
2627
  userDataDir: dir,
2283
- storeFile: import_node_path6.default.join(dir, "attached-projects.json"),
2284
- sessionsDir: import_node_path6.default.join(dir, "sessions"),
2285
- transcriptsDir: import_node_path6.default.join(dir, "transcripts")
2628
+ storeFile: import_node_path7.default.join(dir, "attached-projects.json"),
2629
+ sessionsDir: import_node_path7.default.join(dir, "sessions"),
2630
+ transcriptsDir: import_node_path7.default.join(dir, "transcripts")
2286
2631
  };
2287
2632
  }
2288
2633
  // --- subscription management ---
@@ -2580,7 +2925,7 @@ function mapFrameworkToProjectFramework(fw) {
2580
2925
  // src/host/fetch-proxy-handler.ts
2581
2926
  var import_http2 = __toESM(require("http"), 1);
2582
2927
  var import_https = __toESM(require("https"), 1);
2583
- var import_promises2 = require("stream/promises");
2928
+ var import_promises3 = require("stream/promises");
2584
2929
 
2585
2930
  // src/backend-origin.ts
2586
2931
  function normalizeHostname(hostname) {
@@ -2792,7 +3137,7 @@ async function handleFetchProxyRequest(req, res) {
2792
3137
  const switchToGet = (status === 301 || status === 302) && method === "POST" || status === 303 && method !== "GET" && method !== "HEAD";
2793
3138
  const redirectUrl = new URL(location, targetUrl2);
2794
3139
  proxyRes.resume();
2795
- await (0, import_promises2.finished)(proxyRes);
3140
+ await (0, import_promises3.finished)(proxyRes);
2796
3141
  await proxy(
2797
3142
  redirectUrl,
2798
3143
  switchToGet ? "GET" : method,
@@ -2817,7 +3162,7 @@ async function handleFetchProxyRequest(req, res) {
2817
3162
  );
2818
3163
  }
2819
3164
  res.statusCode = status;
2820
- await (0, import_promises2.pipeline)(proxyRes, res);
3165
+ await (0, import_promises3.pipeline)(proxyRes, res);
2821
3166
  };
2822
3167
  try {
2823
3168
  await proxy(upstreamUrl, originalMethod, body, 0);