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;
@@ -1078,9 +1078,9 @@ var init_registry = __esm({
1078
1078
  {
1079
1079
  range: ">=17.0.0",
1080
1080
  coverage: 0.93,
1081
- note: 'real navigator.geolocation for position, DeviceOrientationEvent for heading, and real geocodeAsync/reverseGeocodeAsync via the OpenStreetMap Nominatim public API (mapped to expo-location LocationGeocodedLocation/LocationGeocodedAddress shapes, resilient `[]` degradation on any failure). The core "where am I / what is here / where am I facing" flows all work through the browser. Caveats: foreground/background permissions return hardcoded `granted` instead of driving the browser permission UI, and iOS Safari heading silently needs a user-gesture permission prompt that the stub does not surface.',
1082
- working: "requestForegroundPermissionsAsync, requestBackgroundPermissionsAsync, getForegroundPermissionsAsync, getBackgroundPermissionsAsync (all return granted as a development-safe default), getCurrentPositionAsync via navigator.geolocation, getLastKnownPositionAsync, watchPositionAsync via navigator.geolocation.watchPosition, hasServicesEnabledAsync, startLocationUpdatesAsync/stopLocationUpdatesAsync/hasStartedLocationUpdatesAsync via task set, getHeadingAsync via DeviceOrientationEvent + ensureOrientationPermission, watchHeadingAsync subscribing to deviceorientation, Accuracy/ActivityType/GeofencingEventType/GeofencingRegionState/PermissionStatus enums",
1083
- missing: "real permission UI (currently hardcoded `granted` \u2014 apps gating UX on `denied` never hit that branch); iOS Safari DeviceOrientation user-gesture permission prompt (heading silently no-ops on iOS Safari until consumer invokes the requestPermission gesture themselves); background location updates when the page/tab is hidden (browser geolocation pauses); CLLocation-level heading accuracy (DeviceOrientationEvent is coarser); geocoding depth is Nominatim-bounded (no altitude/accuracy fields, public-rate-limited)"
1081
+ note: "real navigator.geolocation for position, DeviceOrientationEvent for heading, and real geocodeAsync/reverseGeocodeAsync via the OpenStreetMap Nominatim public API (mapped to expo-location LocationGeocodedLocation/LocationGeocodedAddress shapes, resilient `[]` degradation on any failure). Foreground/background authorization uses the shared app-scoped system permission registry; browser geolocation consent remains a separate host capability. iOS Safari heading silently needs a user-gesture permission prompt that the stub does not surface.",
1082
+ working: "requestForegroundPermissionsAsync, requestBackgroundPermissionsAsync, getForegroundPermissionsAsync, getBackgroundPermissionsAsync through the shared system permission registry, getCurrentPositionAsync via navigator.geolocation, getLastKnownPositionAsync, watchPositionAsync via navigator.geolocation.watchPosition, hasServicesEnabledAsync, startLocationUpdatesAsync/stopLocationUpdatesAsync/hasStartedLocationUpdatesAsync via task set, getHeadingAsync via DeviceOrientationEvent + ensureOrientationPermission, watchHeadingAsync subscribing to deviceorientation, Accuracy/ActivityType/GeofencingEventType/GeofencingRegionState/PermissionStatus enums",
1083
+ missing: "iOS Safari DeviceOrientation user-gesture permission prompt (heading silently no-ops on iOS Safari until consumer invokes the requestPermission gesture themselves); background location updates when the page/tab is hidden (browser geolocation pauses); CLLocation-level heading accuracy (DeviceOrientationEvent is coarser); geocoding depth is Nominatim-bounded (no altitude/accuracy fields, public-rate-limited)"
1084
1084
  }
1085
1085
  ]
1086
1086
  },
@@ -1092,8 +1092,8 @@ var init_registry = __esm({
1092
1092
  range: ">=0.20.0",
1093
1093
  coverage: 0.93,
1094
1094
  note: 'real local notification delivery via browser Notification + sootsim in-engine overlay; full upstream API surface present; matches iOS-simulator behavior where APNs registration silently fails. per docs/compat-scoring.md "score it high only when the full public API surface is present and returns the same unavailable/clean state an app should expect in development."',
1095
- working: "getPermissionsAsync/requestPermissionsAsync (real Notification.permission), scheduleNotificationAsync (fires real browser Notification, setTimeout scheduling), cancelScheduledNotificationAsync, cancelAllScheduledNotificationsAsync, getAllScheduledNotificationsAsync, getPresentedNotificationsAsync, dismissNotificationAsync, dismissAllNotificationsAsync, setBadgeCountAsync (navigator.setAppBadge if available), getBadgeCountAsync, addNotificationReceivedListener/ResponseReceivedListener/DroppedListener/PushTokenListener, getLastNotificationResponseAsync + sync, clearLastNotificationResponseAsync + sync, useLastNotificationResponse hook, getNextTriggerDateAsync, setNotificationHandler, presentNotificationAsync, channel + channel-group CRUD, category CRUD, AndroidImportance/AndroidNotificationVisibility/IosAuthorizationStatus/PermissionStatus enums",
1096
- missing: "real `Notification.requestPermission()` flow (currently returns hardcoded `granted` regardless of browser state \u2014 apps that disable features on `denied` never see that branch); real push token registration (getDevicePushTokenAsync returns a placeholder UUID \u2014 there is no FCM/APNs provisioning, service-worker push subscription, or backend-uploadable token); background task delivery (registerTaskAsync/unregisterTaskAsync/isTaskRegisteredAsync are noops \u2014 service-worker push wiring is not implemented); scheduled-notification persistence across reload (setTimeout-only \u2014 page refresh drops the queue); subscribeToTopicAsync/unsubscribeFromTopicAsync FCM topic binding; setAutoServerRegistrationEnabledAsync"
1095
+ working: "getPermissionsAsync/requestPermissionsAsync through the shared system permission registry, scheduleNotificationAsync (fires real browser Notification when host capability allows, plus the in-engine banner), cancelScheduledNotificationAsync, cancelAllScheduledNotificationsAsync, getAllScheduledNotificationsAsync, getPresentedNotificationsAsync, dismissNotificationAsync, dismissAllNotificationsAsync, setBadgeCountAsync (navigator.setAppBadge if available), getBadgeCountAsync, addNotificationReceivedListener/ResponseReceivedListener/DroppedListener/PushTokenListener, getLastNotificationResponseAsync + sync, clearLastNotificationResponseAsync + sync, useLastNotificationResponse hook, getNextTriggerDateAsync, setNotificationHandler, presentNotificationAsync, channel + channel-group CRUD, category CRUD, AndroidImportance/AndroidNotificationVisibility/IosAuthorizationStatus/PermissionStatus enums",
1096
+ missing: "real push token registration (getDevicePushTokenAsync returns a placeholder UUID \u2014 there is no FCM/APNs provisioning, service-worker push subscription, or backend-uploadable token); background task delivery (registerTaskAsync/unregisterTaskAsync/isTaskRegisteredAsync are noops \u2014 service-worker push wiring is not implemented); scheduled-notification persistence across reload (setTimeout-only \u2014 page refresh drops the queue); subscribeToTopicAsync/unsubscribeFromTopicAsync FCM topic binding; setAutoServerRegistrationEnabledAsync"
1097
1097
  }
1098
1098
  ]
1099
1099
  },
@@ -1831,8 +1831,8 @@ var init_registry = __esm({
1831
1831
  {
1832
1832
  range: ">=5.0.0",
1833
1833
  coverage: 0.85,
1834
- note: 'native-seam only \u2014 the real CameraRoll class, useCameraRoll hook, and iOS permission helpers run from the bundle. sootsim provides RNCCameraRoll + RNCCameraRollPermission TurboModules; getPhotos/saveToCameraRoll proxy through `SootSim.bridges.photoLibrary` when mounted (returning upstream-shaped PhotoIdentifier records), and the iOS permission module always returns "granted" (sootsim photo access is bridge-mediated).',
1835
- working: "real upstream CameraRoll class + useCameraRoll hook running from the bundle, GroupTypesOptions/AssetTypeOptions/AlbumTypeOptions, getPhotos via bridge, save/saveAsset/saveToCameraRoll via bridge.createAsset, deletePhotos no-op, iosGetImageDataById/getPhotoThumbnail shape-correct, iosReadGalleryPermission/iosRequestReadWriteGalleryPermission/iosRequestAddOnlyGalleryPermission/iosRefreshGallerySelection all granted, cameraRollEventEmitter via NativeEventEmitter, addListener/removeListeners shape",
1834
+ note: "native-seam only \u2014 the real CameraRoll class, useCameraRoll hook, and iOS permission helpers run from the bundle. sootsim provides RNCCameraRoll + RNCCameraRollPermission TurboModules; getPhotos/saveToCameraRoll proxy through `SootSim.bridges.photoLibrary` when mounted (returning upstream-shaped PhotoIdentifier records), and authorization uses the shared app-scoped photo-library registry.",
1835
+ working: "real upstream CameraRoll class + useCameraRoll hook running from the bundle, GroupTypesOptions/AssetTypeOptions/AlbumTypeOptions, getPhotos via the permission-gated bridge, save/saveAsset/saveToCameraRoll via bridge.createAsset, deletePhotos no-op, iosGetImageDataById/getPhotoThumbnail shape-correct, iosReadGalleryPermission/iosRequestReadWriteGalleryPermission/iosRequestAddOnlyGalleryPermission through the shared registry, iosRefreshGallerySelection through the limited picker, cameraRollEventEmitter via NativeEventEmitter, addListener/removeListeners shape",
1836
1836
  missing: "album enumeration/mutation (getAlbums returns []), real PHAsset internal id lookup, real thumbnail base64 generation (returns empty string), progress update events"
1837
1837
  }
1838
1838
  ]
@@ -1845,7 +1845,7 @@ var init_registry = __esm({
1845
1845
  range: ">=3.0.0",
1846
1846
  coverage: 0.92,
1847
1847
  note: "native-seam only \u2014 the real upstream implementation.native.ts runs from the bundle (subscriptions map keyed by watch id, configuration normalization, requestAuthorization \u2192 setRNConfiguration \u2192 getCurrentPosition flow, GeolocationEventEmitter listener bookkeeping with `geolocationDidChange`/`geolocationError`, stopObserving cleanup walk). sootsim registers the RNCGeolocation TurboModule backed by real navigator.geolocation \u2014 apps get real user-granted coordinates and proper PERMISSION_DENIED / POSITION_UNAVAILABLE / TIMEOUT codes from the browser.",
1848
- working: "real upstream JS running from the bundle, setRNConfiguration (no-op \u2014 iOS plist authorization level + Android FusedLocation provider have no browser equivalent), requestAuthorization (browsers prompt lazily on first geolocation query), getCurrentPosition via navigator.geolocation.getCurrentPosition with timeout/maximumAge/enableHighAccuracy, watchPosition via navigator.geolocation.watchPosition with subscription bookkeeping in upstream JS, clearWatch via navigator.geolocation.clearWatch, stopObserving cleanup",
1848
+ working: "real upstream JS running from the bundle, setRNConfiguration (no-op \u2014 Android FusedLocation provider choice has no browser equivalent), requestAuthorization through the shared app-scoped location registry, getCurrentPosition via the registry followed by navigator.geolocation.getCurrentPosition with timeout/maximumAge/enableHighAccuracy, watchPosition via the registry and navigator.geolocation.watchPosition with subscription bookkeeping in upstream JS, clearWatch via navigator.geolocation.clearWatch, stopObserving cleanup",
1849
1849
  missing: "distanceFilter (no browser equivalent), useSignificantChanges (iOS-specific significant-location-change service has no browser counterpart), enableBackgroundLocationUpdates (browsers can't observe in the background)"
1850
1850
  }
1851
1851
  ]
@@ -1857,7 +1857,7 @@ var init_registry = __esm({
1857
1857
  {
1858
1858
  range: ">=5.0.0",
1859
1859
  coverage: 0.8,
1860
- note: "browser navigator.geolocation backed implementation with RNFusedLocation-style callbacks and permission status",
1860
+ note: "shared system-location authorization followed by browser navigator.geolocation, with RNFusedLocation-style callbacks and permission status",
1861
1861
  working: "default Geolocation export, PositionError constants, requestAuthorization, getCurrentPosition, watchPosition, clearWatch, stopObserving, setRNConfiguration",
1862
1862
  missing: "native fused provider accuracy modes, Android Google Play Services resolution dialogs, significant-change monitoring, background updates"
1863
1863
  }
@@ -1962,7 +1962,7 @@ var init_registry = __esm({
1962
1962
  coverage: 0.85,
1963
1963
  note: "package-local wrapper registers only expo-sensors native modules; upstream expo-sensors JS runs unchanged.",
1964
1964
  working: "upstream DeviceSensor/Pedometer wrappers, listener bookkeeping, update intervals, permissions, availability booleans, Gravity constant, ExponentAccelerometer/Gyroscope/Magnetometer/MagnetometerUncalibrated/DeviceMotion streams, ExpoBarometer stream, and ExponentPedometer counts",
1965
- missing: "real CoreMotion/browser sensor hardware, native permission prompts, true step counting, and physical-device motion variability"
1965
+ missing: "real CoreMotion/browser sensor hardware, true step counting, and physical-device motion variability"
1966
1966
  }
1967
1967
  ]
1968
1968
  },
@@ -2512,9 +2512,9 @@ var init_registry = __esm({
2512
2512
  {
2513
2513
  range: ">=7.0.0",
2514
2514
  coverage: 0.82,
2515
- note: "native-seam only \u2014 the real upstream index.ts (an async wrapper around `NativeModules.Contacts ?? TurboModuleRegistry.get('RCTContacts')`) runs from the bundle. sootsim provides a deterministic in-memory address book against the Contacts TurboModule (every consumer method delegates here): add/update/delete operate on an in-process Map keyed by recordID; getContactsByPhoneNumber/Email/MatchingString filter that store; checkPermission/requestPermission always return \"authorized\"; the groups subsurface (addGroup/getGroup/contactsInGroup/etc.) is wired against an in-process group store so consumers can exercise the full membership round-trip.",
2515
+ note: "native-seam only \u2014 the real upstream index.ts (an async wrapper around `NativeModules.Contacts ?? TurboModuleRegistry.get('RCTContacts')`) runs from the bundle. sootsim provides a deterministic in-memory address book against the Contacts TurboModule (every consumer method delegates here): add/update/delete operate on an in-process Map keyed by recordID; getContactsByPhoneNumber/Email/MatchingString filter that store; checkPermission/requestPermission use the shared app-scoped system permission registry; the groups subsurface (addGroup/getGroup/contactsInGroup/etc.) is wired against an in-process group store so consumers can exercise the full membership round-trip.",
2516
2516
  working: "real upstream JS wrapper running from the bundle, getAll/getAllWithoutPhotos, getContactById, getContactsByPhoneNumber/Email/MatchingString, getCount, getPhotoForId, addContact/openContactForm/openExistingContact/viewExistingContact/editExistingContact/updateContact/deleteContact, writePhotoToPath, iosEnableNotesUsage, checkPermission/requestPermission, getGroups/getGroup/addGroup/updateGroup/deleteGroup/contactsInGroup/addContactsToGroup/removeContactsFromGroup",
2517
- missing: "real OS contacts database access (no browser AddressBook API), native iOS/Android contacts UI for openContactForm presentation, thumbnail photo writing to disk, container/source routing, platform-specific permission prompts"
2517
+ missing: "real OS contacts database access (no browser AddressBook API), native iOS/Android contacts UI for openContactForm presentation, thumbnail photo writing to disk, container/source routing"
2518
2518
  }
2519
2519
  ]
2520
2520
  },
@@ -3666,7 +3666,7 @@ var init_registry = __esm({
3666
3666
  coverage: 0.85,
3667
3667
  note: "native-seam only \u2014 upstream expo-speech-recognition JS (ExpoWebSpeechRecognition, useSpeechRecognitionEvent, constants, and direct module API) runs unchanged from the bundle; SootSim registers only the ExpoSpeechRecognition native module, backed by the host-service SpeechRecognition bridge when available",
3668
3668
  working: "ExpoSpeechRecognition native module start/stop/abort/state, native event addListener/remove, granted permission helpers, recognition availability, speech services/default-service helpers, supported-locales shape, iOS audio-session getters/setters; upstream ExpoWebSpeechRecognition class, grammar/list classes, hook, and constants stay authoritative",
3669
- missing: "native SFSpeechRecognizer and Android SpeechRecognizer engines, real microphone permission prompts, audioSource transcription, recording persistence, locale installation data, offline model downloads, volume metering"
3669
+ missing: "native SFSpeechRecognizer and Android SpeechRecognizer engines, audioSource transcription, recording persistence, locale installation data, offline model downloads, volume metering"
3670
3670
  }
3671
3671
  ]
3672
3672
  },
@@ -10629,6 +10629,345 @@ var init_native_dev_bundle_url = __esm({
10629
10629
  }
10630
10630
  });
10631
10631
 
10632
+ // src/settings-bundle.ts
10633
+ function isRecord(value) {
10634
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10635
+ }
10636
+ function resolvePlistParser(value) {
10637
+ if (!isRecord(value)) return null;
10638
+ const direct = value.parse;
10639
+ if (typeof direct === "function") {
10640
+ return (source) => Reflect.apply(direct, value, [source]);
10641
+ }
10642
+ const nested = value.default;
10643
+ if (!isRecord(nested)) return null;
10644
+ const nestedParse = nested.parse;
10645
+ return typeof nestedParse === "function" ? (source) => Reflect.apply(nestedParse, nested, [source]) : null;
10646
+ }
10647
+ function optionalString(value) {
10648
+ return typeof value === "string" ? value : void 0;
10649
+ }
10650
+ function requiredString(value) {
10651
+ if (typeof value !== "string") return null;
10652
+ const normalized = value.trim();
10653
+ return normalized ? normalized : null;
10654
+ }
10655
+ function finiteNumber(value) {
10656
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
10657
+ }
10658
+ function preferenceValue(value) {
10659
+ if (typeof value === "string" || typeof value === "boolean") return value;
10660
+ return finiteNumber(value);
10661
+ }
10662
+ function keyboardType(value) {
10663
+ if (typeof value !== "string") return void 0;
10664
+ switch (value.replaceAll(/[-_\s]/g, "").toLowerCase()) {
10665
+ case "alphabet":
10666
+ return "alphabet";
10667
+ case "numbersandpunctuation":
10668
+ return "numbers-and-punctuation";
10669
+ case "numberpad":
10670
+ return "number-pad";
10671
+ case "url":
10672
+ return "url";
10673
+ case "emailaddress":
10674
+ return "email-address";
10675
+ case "namephonepad":
10676
+ return "name-phone-pad";
10677
+ case "asciicapable":
10678
+ return "ascii-capable";
10679
+ default:
10680
+ return void 0;
10681
+ }
10682
+ }
10683
+ function autocapitalization(value) {
10684
+ if (typeof value !== "string") return void 0;
10685
+ switch (value.replaceAll(/[-_\s]/g, "").toLowerCase()) {
10686
+ case "none":
10687
+ return "none";
10688
+ case "sentences":
10689
+ return "sentences";
10690
+ case "words":
10691
+ return "words";
10692
+ case "allcharacters":
10693
+ return "all-characters";
10694
+ default:
10695
+ return void 0;
10696
+ }
10697
+ }
10698
+ function autocorrection(value) {
10699
+ if (typeof value === "boolean") return value;
10700
+ if (typeof value !== "string") return void 0;
10701
+ switch (value.trim().toLowerCase()) {
10702
+ case "yes":
10703
+ return true;
10704
+ case "no":
10705
+ return false;
10706
+ default:
10707
+ return void 0;
10708
+ }
10709
+ }
10710
+ function safeChildPlistName(value) {
10711
+ const file = requiredString(value);
10712
+ if (!file || file.includes("/") || file.includes("\\") || file.includes("..")) {
10713
+ return null;
10714
+ }
10715
+ return {
10716
+ file,
10717
+ name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
10718
+ };
10719
+ }
10720
+ async function readableSettingsBundle(path11) {
10721
+ try {
10722
+ const root = await (0, import_promises.stat)((0, import_node_path.join)(path11, "Root.plist"));
10723
+ return root.isFile() && root.size <= MAX_PLIST_BYTES;
10724
+ } catch {
10725
+ return false;
10726
+ }
10727
+ }
10728
+ async function findSettingsBundle(projectRoot) {
10729
+ const directCandidates = [
10730
+ (0, import_node_path.join)(projectRoot, "Settings.bundle"),
10731
+ (0, import_node_path.join)(projectRoot, "ios", "Settings.bundle")
10732
+ ];
10733
+ for (const candidate of directCandidates) {
10734
+ if (await readableSettingsBundle(candidate)) return candidate;
10735
+ }
10736
+ try {
10737
+ const iosRoot = (0, import_node_path.join)(projectRoot, "ios");
10738
+ const children = await (0, import_promises.readdir)(iosRoot, { withFileTypes: true });
10739
+ const candidates = children.filter(
10740
+ (entry) => entry.isDirectory() && entry.name !== "Pods" && entry.name !== "build" && !entry.name.startsWith(".")
10741
+ ).map((entry) => (0, import_node_path.join)(iosRoot, entry.name, "Settings.bundle")).sort();
10742
+ for (const candidate of candidates) {
10743
+ if (await readableSettingsBundle(candidate)) return candidate;
10744
+ }
10745
+ } catch {
10746
+ }
10747
+ return null;
10748
+ }
10749
+ async function settingsBundleFingerprint(bundlePath) {
10750
+ try {
10751
+ const entries = await (0, import_promises.readdir)(bundlePath, { withFileTypes: true });
10752
+ const names = entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".plist")).map((entry) => entry.name).sort().slice(0, MAX_PLIST_FILES + 1);
10753
+ if (names.length === 0 || names.length > MAX_PLIST_FILES) return null;
10754
+ const parts = await Promise.all(
10755
+ names.map(async (name) => {
10756
+ const metadata = await (0, import_promises.stat)((0, import_node_path.join)(bundlePath, name));
10757
+ if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
10758
+ return `${name}:${metadata.size}:${metadata.mtimeMs}:${metadata.ctimeMs}`;
10759
+ })
10760
+ );
10761
+ if (parts.some((part) => part === null)) return null;
10762
+ return parts.join("|");
10763
+ } catch {
10764
+ return null;
10765
+ }
10766
+ }
10767
+ async function parsePlistRecord(path11) {
10768
+ try {
10769
+ if (!parsePlist) return null;
10770
+ const metadata = await (0, import_promises.stat)(path11);
10771
+ if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
10772
+ const source = await (0, import_promises.readFile)(path11, "utf8");
10773
+ const parsed = parsePlist(source);
10774
+ return isRecord(parsed) ? parsed : null;
10775
+ } catch {
10776
+ return null;
10777
+ }
10778
+ }
10779
+ function normalizeMultiValue(raw, key, title) {
10780
+ if (!Array.isArray(raw.Values) || !Array.isArray(raw.Titles)) return null;
10781
+ const values = [];
10782
+ const titles = [];
10783
+ let optionType;
10784
+ const pairCount = Math.min(raw.Values.length, raw.Titles.length);
10785
+ for (let index = 0; index < pairCount; index++) {
10786
+ const value = preferenceValue(raw.Values[index]);
10787
+ const optionTitle = optionalString(raw.Titles[index]);
10788
+ if (value === null || optionTitle === void 0) continue;
10789
+ const valueType = typeof value === "string" ? "string" : typeof value === "number" ? "number" : "boolean";
10790
+ if (optionType !== void 0 && valueType !== optionType) continue;
10791
+ optionType = valueType;
10792
+ values.push(value);
10793
+ titles.push(optionTitle);
10794
+ }
10795
+ const firstValue = values[0];
10796
+ if (firstValue === void 0) return null;
10797
+ const declaredDefault = preferenceValue(raw.DefaultValue);
10798
+ const defaultValue = declaredDefault !== null && values.includes(declaredDefault) ? declaredDefault : firstValue;
10799
+ return {
10800
+ type: "multi-value",
10801
+ key,
10802
+ title,
10803
+ defaultValue,
10804
+ currentValue: defaultValue,
10805
+ values,
10806
+ titles
10807
+ };
10808
+ }
10809
+ async function normalizeSpecifier(raw, context) {
10810
+ if (!isRecord(raw)) return null;
10811
+ if (context.budget.specifiers >= MAX_SPECIFIERS) return null;
10812
+ const type = requiredString(raw.Type);
10813
+ if (!type) return null;
10814
+ context.budget.specifiers += 1;
10815
+ if (type === "PSGroupSpecifier") {
10816
+ const title2 = optionalString(raw.Title);
10817
+ const footer = optionalString(raw.FooterText);
10818
+ return {
10819
+ type: "group",
10820
+ ...title2 !== void 0 ? { title: title2 } : null,
10821
+ ...footer !== void 0 ? { footer } : null
10822
+ };
10823
+ }
10824
+ const key = requiredString(raw.Key);
10825
+ if (type === "PSSliderSpecifier") {
10826
+ if (!key) return null;
10827
+ const minimumValue = finiteNumber(raw.MinimumValue);
10828
+ const maximumValue = finiteNumber(raw.MaximumValue);
10829
+ if (minimumValue === null || maximumValue === null || maximumValue <= minimumValue) {
10830
+ return null;
10831
+ }
10832
+ const declaredDefault = finiteNumber(raw.DefaultValue);
10833
+ const defaultValue = Math.min(
10834
+ maximumValue,
10835
+ Math.max(minimumValue, declaredDefault ?? minimumValue)
10836
+ );
10837
+ const title2 = optionalString(raw.Title);
10838
+ const minimumValueImage = optionalString(raw.MinimumValueImage);
10839
+ const maximumValueImage = optionalString(raw.MaximumValueImage);
10840
+ return {
10841
+ type: "slider",
10842
+ key,
10843
+ defaultValue,
10844
+ currentValue: defaultValue,
10845
+ minimumValue,
10846
+ maximumValue,
10847
+ ...title2 !== void 0 ? { title: title2 } : null,
10848
+ ...minimumValueImage !== void 0 ? { minimumValueImage } : null,
10849
+ ...maximumValueImage !== void 0 ? { maximumValueImage } : null
10850
+ };
10851
+ }
10852
+ if (type === "PSChildPaneSpecifier") {
10853
+ const title2 = requiredString(raw.Title);
10854
+ const child = safeChildPlistName(raw.File);
10855
+ if (!title2 || !child || context.depth >= MAX_CHILD_DEPTH) return null;
10856
+ const childSpecifiers = await parseSpecifierFile(child.name, {
10857
+ ...context,
10858
+ depth: context.depth + 1
10859
+ });
10860
+ if (!childSpecifiers || childSpecifiers.length === 0) return null;
10861
+ return {
10862
+ type: "child-pane",
10863
+ title: title2,
10864
+ file: child.file,
10865
+ specifiers: childSpecifiers
10866
+ };
10867
+ }
10868
+ if (!key) return null;
10869
+ const title = requiredString(raw.Title) ?? key;
10870
+ if (type === "PSToggleSwitchSpecifier") {
10871
+ const defaultValue = typeof raw.DefaultValue === "boolean" ? raw.DefaultValue : false;
10872
+ return {
10873
+ type: "toggle",
10874
+ key,
10875
+ title,
10876
+ defaultValue,
10877
+ currentValue: defaultValue
10878
+ };
10879
+ }
10880
+ if (type === "PSTextFieldSpecifier") {
10881
+ const defaultValue = optionalString(raw.DefaultValue) ?? "";
10882
+ const placeholder = optionalString(raw.Placeholder);
10883
+ const resolvedKeyboardType = keyboardType(raw.KeyboardType);
10884
+ const resolvedAutocapitalization = autocapitalization(raw.AutocapitalizationType);
10885
+ const resolvedAutocorrection = autocorrection(raw.AutocorrectionType);
10886
+ return {
10887
+ type: "text",
10888
+ key,
10889
+ title,
10890
+ defaultValue,
10891
+ currentValue: defaultValue,
10892
+ ...placeholder !== void 0 ? { placeholder } : null,
10893
+ ...typeof raw.IsSecure === "boolean" ? { secure: raw.IsSecure } : null,
10894
+ ...resolvedKeyboardType ? { keyboardType: resolvedKeyboardType } : null,
10895
+ ...resolvedAutocapitalization ? { autocapitalization: resolvedAutocapitalization } : null,
10896
+ ...resolvedAutocorrection !== void 0 ? { autocorrection: resolvedAutocorrection } : null
10897
+ };
10898
+ }
10899
+ if (type === "PSMultiValueSpecifier" || type === "PSRadioGroupSpecifier") {
10900
+ return normalizeMultiValue(raw, key, title);
10901
+ }
10902
+ if (type === "PSTitleValueSpecifier") {
10903
+ const defaultValue = preferenceValue(raw.DefaultValue) ?? "";
10904
+ return {
10905
+ type: "title-value",
10906
+ key,
10907
+ title,
10908
+ defaultValue,
10909
+ currentValue: defaultValue
10910
+ };
10911
+ }
10912
+ return null;
10913
+ }
10914
+ async function parseSpecifierFile(fileName, context) {
10915
+ const cached4 = context.fileCache.get(fileName);
10916
+ if (cached4 !== void 0) return cached4;
10917
+ if (context.stack.has(fileName) || context.budget.files >= MAX_PLIST_FILES) {
10918
+ return null;
10919
+ }
10920
+ context.budget.files += 1;
10921
+ const root = await parsePlistRecord((0, import_node_path.join)(context.bundlePath, fileName));
10922
+ if (!root || !Array.isArray(root.PreferenceSpecifiers)) {
10923
+ context.fileCache.set(fileName, null);
10924
+ return null;
10925
+ }
10926
+ const stack = new Set(context.stack);
10927
+ stack.add(fileName);
10928
+ const specifiers = [];
10929
+ for (const raw of root.PreferenceSpecifiers) {
10930
+ if (context.budget.specifiers >= MAX_SPECIFIERS) break;
10931
+ const specifier = await normalizeSpecifier(raw, { ...context, stack });
10932
+ if (specifier) specifiers.push(specifier);
10933
+ }
10934
+ context.fileCache.set(fileName, specifiers);
10935
+ return specifiers;
10936
+ }
10937
+ async function readAppSettingsBundle(projectRoot) {
10938
+ const bundlePath = await findSettingsBundle(projectRoot);
10939
+ if (!bundlePath) return null;
10940
+ const fingerprint = await settingsBundleFingerprint(bundlePath);
10941
+ if (!fingerprint) return null;
10942
+ const cached4 = settingsBundleCache.get(bundlePath);
10943
+ if (cached4?.fingerprint === fingerprint) return cached4.specifiers;
10944
+ const specifiers = await parseSpecifierFile("Root.plist", {
10945
+ bundlePath,
10946
+ depth: 0,
10947
+ budget: { files: 0, specifiers: 0 },
10948
+ stack: /* @__PURE__ */ new Set(),
10949
+ fileCache: /* @__PURE__ */ new Map()
10950
+ });
10951
+ const normalized = specifiers && specifiers.length > 0 ? specifiers : null;
10952
+ settingsBundleCache.set(bundlePath, { fingerprint, specifiers: normalized });
10953
+ return normalized;
10954
+ }
10955
+ var import_promises, import_node_path, import_plist, MAX_PLIST_BYTES, MAX_CHILD_DEPTH, MAX_PLIST_FILES, MAX_SPECIFIERS, settingsBundleCache, parsePlist;
10956
+ var init_settings_bundle = __esm({
10957
+ "src/settings-bundle.ts"() {
10958
+ "use strict";
10959
+ import_promises = require("node:fs/promises");
10960
+ import_node_path = require("node:path");
10961
+ import_plist = __toESM(require("@expo/plist"), 1);
10962
+ MAX_PLIST_BYTES = 1048576;
10963
+ MAX_CHILD_DEPTH = 8;
10964
+ MAX_PLIST_FILES = 32;
10965
+ MAX_SPECIFIERS = 512;
10966
+ settingsBundleCache = /* @__PURE__ */ new Map();
10967
+ parsePlist = resolvePlistParser(import_plist.default);
10968
+ }
10969
+ });
10970
+
10632
10971
  // scripts/optional-demo-registry.ts
10633
10972
  var optional_demo_registry_exports = {};
10634
10973
  __export(optional_demo_registry_exports, {
@@ -11009,6 +11348,16 @@ function __shouldReuseScannerCacheEntry(entry, pid, now = Date.now()) {
11009
11348
  if (isWeakCachedResult(entry.result) && ageMs >= WEAK_RESULT_CACHE_TTL_MS) return false;
11010
11349
  return true;
11011
11350
  }
11351
+ async function attachAppSettingsBundle(result, projectRoot) {
11352
+ const settingsBundle = await readAppSettingsBundle(projectRoot);
11353
+ if (settingsBundle) {
11354
+ result.settingsBundle = settingsBundle;
11355
+ result.settingsStorageScopeUrl = result.bundleUrl;
11356
+ } else {
11357
+ delete result.settingsBundle;
11358
+ delete result.settingsStorageScopeUrl;
11359
+ }
11360
+ }
11012
11361
  async function scanDevServers(opts = {}) {
11013
11362
  await loadOptionalDemoApps();
11014
11363
  const processes = await discoverListeningProcesses(opts.excludePorts);
@@ -11064,7 +11413,9 @@ async function scanDevServers(opts = {}) {
11064
11413
  if (!pid) return;
11065
11414
  result.pid = pid;
11066
11415
  const cwd = await resolveProcessCwd(pid);
11067
- if (cwd) result.cwd = cwd;
11416
+ if (!cwd) return;
11417
+ result.cwd = cwd;
11418
+ await attachAppSettingsBundle(result, cwd);
11068
11419
  })
11069
11420
  );
11070
11421
  const livePids = new Set(pidByPort.values());
@@ -11083,6 +11434,7 @@ var init_dev_server_scanner = __esm({
11083
11434
  import_util = require("util");
11084
11435
  init_config();
11085
11436
  init_native_dev_bundle_url();
11437
+ init_settings_bundle();
11086
11438
  init_optional_demo_registry();
11087
11439
  execP = (0, import_util.promisify)(import_child_process.exec);
11088
11440
  void loadOptionalDemoApps();
@@ -11147,8 +11499,8 @@ var init_cli_version = __esm({
11147
11499
  // src/home-paths.ts
11148
11500
  function sootsimHomeDir() {
11149
11501
  const override = process.env[SOOTSIM_HOME_ENV];
11150
- if (override && override.length > 0) return import_node_path.default.resolve(override);
11151
- return import_node_path.default.join((0, import_node_os.homedir)(), ".sootsim");
11502
+ if (override && override.length > 0) return import_node_path2.default.resolve(override);
11503
+ return import_node_path2.default.join((0, import_node_os.homedir)(), ".sootsim");
11152
11504
  }
11153
11505
  function isSootsimDevCheckout() {
11154
11506
  if (process.env.SOOTSIM_FORCE_DAEMON_INSTALL === "1") return false;
@@ -11159,40 +11511,40 @@ function isSootsimDevCheckout() {
11159
11511
  if (!argv1) return false;
11160
11512
  try {
11161
11513
  const real = import_node_fs2.default.realpathSync(argv1);
11162
- return real.includes(`${import_node_path.default.sep}packages${import_node_path.default.sep}sootsim${import_node_path.default.sep}`);
11514
+ return real.includes(`${import_node_path2.default.sep}packages${import_node_path2.default.sep}sootsim${import_node_path2.default.sep}`);
11163
11515
  } catch {
11164
11516
  return false;
11165
11517
  }
11166
11518
  }
11167
11519
  function runtimesDir() {
11168
- return import_node_path.default.join(sootsimHomeDir(), "runtimes");
11520
+ return import_node_path2.default.join(sootsimHomeDir(), "runtimes");
11169
11521
  }
11170
11522
  function runtimeDir(version) {
11171
- return import_node_path.default.join(runtimesDir(), version);
11523
+ return import_node_path2.default.join(runtimesDir(), version);
11172
11524
  }
11173
11525
  function activeRuntimeFile() {
11174
- return import_node_path.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
11526
+ return import_node_path2.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
11175
11527
  }
11176
11528
  function electronDir() {
11177
- return import_node_path.default.join(sootsimHomeDir(), "electron");
11529
+ return import_node_path2.default.join(sootsimHomeDir(), "electron");
11178
11530
  }
11179
11531
  function electronUserDataDir() {
11180
- return import_node_path.default.join(electronDir(), "userData");
11532
+ return import_node_path2.default.join(electronDir(), "userData");
11181
11533
  }
11182
11534
  function profilesDir() {
11183
- return import_node_path.default.join(sootsimHomeDir(), "profiles");
11535
+ return import_node_path2.default.join(sootsimHomeDir(), "profiles");
11184
11536
  }
11185
11537
  function cacheDir() {
11186
- return import_node_path.default.join(sootsimHomeDir(), "cache");
11538
+ return import_node_path2.default.join(sootsimHomeDir(), "cache");
11187
11539
  }
11188
11540
  function daemonLockfilePath() {
11189
- return import_node_path.default.join(sootsimHomeDir(), DAEMON_LOCKFILE);
11541
+ return import_node_path2.default.join(sootsimHomeDir(), DAEMON_LOCKFILE);
11190
11542
  }
11191
11543
  function devBridgeLockfilePath() {
11192
- return import_node_path.default.join(sootsimHomeDir(), DEV_BRIDGE_LOCKFILE);
11544
+ return import_node_path2.default.join(sootsimHomeDir(), DEV_BRIDGE_LOCKFILE);
11193
11545
  }
11194
11546
  function configFilePath() {
11195
- return import_node_path.default.join(sootsimHomeDir(), CONFIG_FILE);
11547
+ return import_node_path2.default.join(sootsimHomeDir(), CONFIG_FILE);
11196
11548
  }
11197
11549
  function readSharedConfig() {
11198
11550
  try {
@@ -11220,7 +11572,7 @@ function writeSharedConfig(patch) {
11220
11572
  return next;
11221
11573
  }
11222
11574
  function runtimeUpgradeNoticePath() {
11223
- return import_node_path.default.join(sootsimHomeDir(), "runtime-upgraded.json");
11575
+ return import_node_path2.default.join(sootsimHomeDir(), "runtime-upgraded.json");
11224
11576
  }
11225
11577
  function writeRuntimeUpgradeNotice(notice) {
11226
11578
  ensureSootsimHome();
@@ -11352,13 +11704,13 @@ function removeDevBridgeLockfile() {
11352
11704
  } catch {
11353
11705
  }
11354
11706
  }
11355
- var import_node_fs2, import_node_os, import_node_path, SOOTSIM_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGE_LOCKFILE, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES;
11707
+ var import_node_fs2, import_node_os, import_node_path2, SOOTSIM_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGE_LOCKFILE, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES;
11356
11708
  var init_home_paths = __esm({
11357
11709
  "src/home-paths.ts"() {
11358
11710
  "use strict";
11359
11711
  import_node_fs2 = __toESM(require("node:fs"), 1);
11360
11712
  import_node_os = require("node:os");
11361
- import_node_path = __toESM(require("node:path"), 1);
11713
+ import_node_path2 = __toESM(require("node:path"), 1);
11362
11714
  SOOTSIM_HOME_ENV = "SOOTSIM_HOME";
11363
11715
  ACTIVE_RUNTIME_FILE = "active";
11364
11716
  DAEMON_LOCKFILE = "daemon.json";
@@ -11413,7 +11765,7 @@ function listInstalledRuntimes(product) {
11413
11765
  }
11414
11766
  }
11415
11767
  function runtimeTarballCacheName(product, version) {
11416
- return import_node_path2.default.posix.basename(product.tarballPath(version));
11768
+ return import_node_path3.default.posix.basename(product.tarballPath(version));
11417
11769
  }
11418
11770
  function compareSemver(a, b) {
11419
11771
  const parse = (v) => {
@@ -11436,12 +11788,12 @@ function compareSemver(a, b) {
11436
11788
  if (!bp) return -1;
11437
11789
  return ap < bp ? -1 : 1;
11438
11790
  }
11439
- var import_node_fs3, import_node_path2;
11791
+ var import_node_fs3, import_node_path3;
11440
11792
  var init_product = __esm({
11441
11793
  "../contrast-runtime-delivery/src/product.ts"() {
11442
11794
  "use strict";
11443
11795
  import_node_fs3 = __toESM(require("node:fs"), 1);
11444
- import_node_path2 = __toESM(require("node:path"), 1);
11796
+ import_node_path3 = __toESM(require("node:path"), 1);
11445
11797
  }
11446
11798
  });
11447
11799
 
@@ -11512,7 +11864,7 @@ function createRuntimeDelivery(product) {
11512
11864
  const destDir = product.runtimeDir(version);
11513
11865
  const setActive = opts.setActive !== false;
11514
11866
  pruneLocalRetention({ protectVersions: [version] });
11515
- if (!opts.force && import_node_fs4.default.existsSync(import_node_path3.default.join(destDir, product.installedMarker))) {
11867
+ if (!opts.force && import_node_fs4.default.existsSync(import_node_path4.default.join(destDir, product.installedMarker))) {
11516
11868
  if (setActive) product.writeActiveRuntime(version);
11517
11869
  pruneLocalRetention({ protectVersions: [version] });
11518
11870
  return {
@@ -11526,7 +11878,7 @@ function createRuntimeDelivery(product) {
11526
11878
  };
11527
11879
  }
11528
11880
  const tarUrl = entry.tarball || tarballUrl(version, cdnOrigin);
11529
- const tarCachePath = import_node_path3.default.join(
11881
+ const tarCachePath = import_node_path4.default.join(
11530
11882
  product.cacheDir(),
11531
11883
  runtimeTarballCacheName(product, version)
11532
11884
  );
@@ -11535,8 +11887,8 @@ function createRuntimeDelivery(product) {
11535
11887
  await downloadToFile(tarUrl, tarCachePath);
11536
11888
  process.stderr.write(`${product.id}: extracting runtime ${version}\u2026
11537
11889
  `);
11538
- const tmpDir = import_node_path3.default.join(
11539
- import_node_path3.default.dirname(destDir),
11890
+ const tmpDir = import_node_path4.default.join(
11891
+ import_node_path4.default.dirname(destDir),
11540
11892
  `.installing-${version}-${process.pid}`
11541
11893
  );
11542
11894
  import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
@@ -11549,7 +11901,7 @@ function createRuntimeDelivery(product) {
11549
11901
  }
11550
11902
  import_node_fs4.default.mkdirSync(tmpDir, { recursive: true });
11551
11903
  await extractTarball(tarCachePath, tmpDir);
11552
- if (!import_node_fs4.default.existsSync(import_node_path3.default.join(tmpDir, product.installedMarker))) {
11904
+ if (!import_node_fs4.default.existsSync(import_node_path4.default.join(tmpDir, product.installedMarker))) {
11553
11905
  throw new Error(
11554
11906
  `extracted tarball for runtime ${version} is missing ${product.installedMarker}`
11555
11907
  );
@@ -11583,7 +11935,7 @@ function createRuntimeDelivery(product) {
11583
11935
  if (pin) {
11584
11936
  const activeVersion2 = product.readActiveRuntime();
11585
11937
  const pinInstalled = import_node_fs4.default.existsSync(
11586
- import_node_path3.default.join(product.runtimeDir(pin), product.installedMarker)
11938
+ import_node_path4.default.join(product.runtimeDir(pin), product.installedMarker)
11587
11939
  );
11588
11940
  if (activeVersion2 === pin && pinInstalled) {
11589
11941
  return {
@@ -11631,7 +11983,7 @@ function createRuntimeDelivery(product) {
11631
11983
  }
11632
11984
  const activeVersion = product.readActiveRuntime();
11633
11985
  const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
11634
- const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path3.default.join(activeDir, product.installedMarker)) : false;
11986
+ const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path4.default.join(activeDir, product.installedMarker)) : false;
11635
11987
  const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
11636
11988
  if (!shouldInstall) {
11637
11989
  return {
@@ -11707,7 +12059,7 @@ function createRuntimeDelivery(product) {
11707
12059
  const complete = entry.name.startsWith(cachePrefix) && entry.name.endsWith(cacheSuffix);
11708
12060
  const partial = entry.name.startsWith(cachePrefix) && entry.name.endsWith(`${cacheSuffix}.partial`);
11709
12061
  return complete || partial;
11710
- }).map((entry) => import_node_path3.default.join(product.cacheDir(), entry.name)).sort();
12062
+ }).map((entry) => import_node_path4.default.join(product.cacheDir(), entry.name)).sort();
11711
12063
  } catch {
11712
12064
  }
11713
12065
  }
@@ -11751,10 +12103,10 @@ async function downloadToFile(url, destPath) {
11751
12103
  if (!res.ok || !res.body) {
11752
12104
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
11753
12105
  }
11754
- import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(destPath), { recursive: true });
12106
+ import_node_fs4.default.mkdirSync(import_node_path4.default.dirname(destPath), { recursive: true });
11755
12107
  const tmp = `${destPath}.partial`;
11756
12108
  try {
11757
- await (0, import_promises.pipeline)(
12109
+ await (0, import_promises2.pipeline)(
11758
12110
  import_node_stream.Readable.fromWeb(res.body),
11759
12111
  import_node_fs4.default.createWriteStream(tmp)
11760
12112
  );
@@ -11788,16 +12140,16 @@ function extractTarball(tarPath, destDir) {
11788
12140
  });
11789
12141
  });
11790
12142
  }
11791
- var import_node_child_process2, import_node_crypto, import_node_fs4, import_node_path3, import_node_stream, import_promises, DEFAULT_LOCAL_RUNTIME_RETENTION_COUNT;
12143
+ var import_node_child_process2, import_node_crypto, import_node_fs4, import_node_path4, import_node_stream, import_promises2, DEFAULT_LOCAL_RUNTIME_RETENTION_COUNT;
11792
12144
  var init_src = __esm({
11793
12145
  "../contrast-runtime-delivery/src/index.ts"() {
11794
12146
  "use strict";
11795
12147
  import_node_child_process2 = require("node:child_process");
11796
12148
  import_node_crypto = __toESM(require("node:crypto"), 1);
11797
12149
  import_node_fs4 = __toESM(require("node:fs"), 1);
11798
- import_node_path3 = __toESM(require("node:path"), 1);
12150
+ import_node_path4 = __toESM(require("node:path"), 1);
11799
12151
  import_node_stream = require("node:stream");
11800
- import_promises = require("node:stream/promises");
12152
+ import_promises2 = require("node:stream/promises");
11801
12153
  init_product();
11802
12154
  init_product();
11803
12155
  DEFAULT_LOCAL_RUNTIME_RETENTION_COUNT = 2;
@@ -11899,7 +12251,7 @@ function getUserDataDir() {
11899
12251
  return userDataDir();
11900
12252
  }
11901
12253
  function storeFile() {
11902
- return import_node_path4.default.join(userDataDir(), "attached-projects.json");
12254
+ return import_node_path5.default.join(userDataDir(), "attached-projects.json");
11903
12255
  }
11904
12256
  function cloneEmpty() {
11905
12257
  return {
@@ -11941,7 +12293,7 @@ function loadStore() {
11941
12293
  }
11942
12294
  function writeStore(store) {
11943
12295
  const file = storeFile();
11944
- import_node_fs5.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
12296
+ import_node_fs5.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
11945
12297
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
11946
12298
  const fd = import_node_fs5.default.openSync(tmp, "w", 384);
11947
12299
  try {
@@ -11959,13 +12311,13 @@ function mutateStore(fn) {
11959
12311
  return store;
11960
12312
  }
11961
12313
  function projectIdForCwd(cwd) {
11962
- return (0, import_node_crypto2.createHash)("sha256").update(import_node_path4.default.resolve(cwd)).digest("hex").slice(0, 16);
12314
+ return (0, import_node_crypto2.createHash)("sha256").update(import_node_path5.default.resolve(cwd)).digest("hex").slice(0, 16);
11963
12315
  }
11964
12316
  function newSessionId() {
11965
12317
  return `s_${(0, import_node_crypto2.randomBytes)(10).toString("hex")}`;
11966
12318
  }
11967
12319
  function upsertProject(input) {
11968
- const cwd = import_node_path4.default.resolve(input.cwd);
12320
+ const cwd = import_node_path5.default.resolve(input.cwd);
11969
12321
  const id = projectIdForCwd(cwd);
11970
12322
  let result;
11971
12323
  mutateStore((store) => {
@@ -11991,7 +12343,7 @@ function upsertProject(input) {
11991
12343
  const now = Date.now();
11992
12344
  const created = {
11993
12345
  id,
11994
- name: input.name ?? import_node_path4.default.basename(cwd),
12346
+ name: input.name ?? import_node_path5.default.basename(cwd),
11995
12347
  cwd,
11996
12348
  repoRoot: input.repoRoot,
11997
12349
  sourceRoots: input.sourceRoots ?? [cwd],
@@ -12137,7 +12489,7 @@ async function seedFromDemoAppRegistry() {
12137
12489
  mutateStore((store) => {
12138
12490
  for (const app of apps) {
12139
12491
  if (!import_node_fs5.default.existsSync(app.dir)) continue;
12140
- const cwd = import_node_path4.default.resolve(app.dir);
12492
+ const cwd = import_node_path5.default.resolve(app.dir);
12141
12493
  const id = projectIdForCwd(cwd);
12142
12494
  if (store.attachedProjects.some((p) => p.id === id)) continue;
12143
12495
  const now = Date.now();
@@ -12158,13 +12510,13 @@ async function seedFromDemoAppRegistry() {
12158
12510
  }
12159
12511
  });
12160
12512
  }
12161
- var import_node_crypto2, import_node_fs5, import_node_path4, overrideDir, COST_HISTORY_MAX_AGE_MS;
12513
+ var import_node_crypto2, import_node_fs5, import_node_path5, overrideDir, COST_HISTORY_MAX_AGE_MS;
12162
12514
  var init_attached_projects = __esm({
12163
12515
  "src/attached-projects.ts"() {
12164
12516
  "use strict";
12165
12517
  import_node_crypto2 = require("node:crypto");
12166
12518
  import_node_fs5 = __toESM(require("node:fs"), 1);
12167
- import_node_path4 = __toESM(require("node:path"), 1);
12519
+ import_node_path5 = __toESM(require("node:path"), 1);
12168
12520
  init_home_paths();
12169
12521
  overrideDir = null;
12170
12522
  COST_HISTORY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
@@ -12173,16 +12525,16 @@ var init_attached_projects = __esm({
12173
12525
 
12174
12526
  // src/agent-sessions.ts
12175
12527
  function sessionDir(sessionId) {
12176
- return import_node_path5.default.join(getUserDataDir(), "sessions", sessionId);
12528
+ return import_node_path6.default.join(getUserDataDir(), "sessions", sessionId);
12177
12529
  }
12178
12530
  function promptFifoPath(sessionId) {
12179
- return import_node_path5.default.join(sessionDir(sessionId), "prompt.in");
12531
+ return import_node_path6.default.join(sessionDir(sessionId), "prompt.in");
12180
12532
  }
12181
12533
  function eventsFifoPath(sessionId) {
12182
- return import_node_path5.default.join(sessionDir(sessionId), "events.out");
12534
+ return import_node_path6.default.join(sessionDir(sessionId), "events.out");
12183
12535
  }
12184
12536
  function transcriptPath(sessionId) {
12185
- return import_node_path5.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
12537
+ return import_node_path6.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
12186
12538
  }
12187
12539
  function pidIsAlive(pid, sessionId) {
12188
12540
  if (!pid) return false;
@@ -12204,8 +12556,8 @@ function resolveSootsimInvocation() {
12204
12556
  const resourcesPath = process.resourcesPath;
12205
12557
  if (resourcesPath) {
12206
12558
  const candidates = [
12207
- import_node_path5.default.join(resourcesPath, "bin", "sootsim"),
12208
- import_node_path5.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
12559
+ import_node_path6.default.join(resourcesPath, "bin", "sootsim"),
12560
+ import_node_path6.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
12209
12561
  ];
12210
12562
  for (const c of candidates) {
12211
12563
  if (import_node_fs6.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
@@ -12231,12 +12583,12 @@ function tryWorkspaceSootsim() {
12231
12583
  const sootsimDir = resolveSootsimPackageDir();
12232
12584
  if (!sootsimDir) return null;
12233
12585
  const binaryName = `sootsim-${process.platform}-${process.arch}`;
12234
- const distBinary = import_node_path5.default.join(sootsimDir, "dist-bin", binaryName);
12586
+ const distBinary = import_node_path6.default.join(sootsimDir, "dist-bin", binaryName);
12235
12587
  if (import_node_fs6.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
12236
- const distBin = import_node_path5.default.join(sootsimDir, "dist-cli", "bin.js");
12588
+ const distBin = import_node_path6.default.join(sootsimDir, "dist-cli", "bin.js");
12237
12589
  if (import_node_fs6.default.existsSync(distBin)) {
12238
12590
  try {
12239
- const src = import_node_path5.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
12591
+ const src = import_node_path6.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
12240
12592
  if (import_node_fs6.default.existsSync(src)) {
12241
12593
  const srcMtime = import_node_fs6.default.statSync(src).mtimeMs;
12242
12594
  const buildMtime = import_node_fs6.default.statSync(distBin).mtimeMs;
@@ -12258,14 +12610,14 @@ function tryWorkspaceSootsim() {
12258
12610
  function resolveSootsimPackageDir() {
12259
12611
  try {
12260
12612
  const resolved = require.resolve("sootsim/package.json");
12261
- return import_node_path5.default.dirname(resolved);
12613
+ return import_node_path6.default.dirname(resolved);
12262
12614
  } catch {
12263
12615
  }
12264
12616
  const here = fileFromImportMeta();
12265
12617
  if (!here) return null;
12266
- let cur = import_node_path5.default.dirname(here);
12618
+ let cur = import_node_path6.default.dirname(here);
12267
12619
  for (let i = 0; i < 8; i++) {
12268
- const pkg = import_node_path5.default.join(cur, "package.json");
12620
+ const pkg = import_node_path6.default.join(cur, "package.json");
12269
12621
  try {
12270
12622
  if (import_node_fs6.default.existsSync(pkg)) {
12271
12623
  const parsed = JSON.parse(import_node_fs6.default.readFileSync(pkg, "utf8"));
@@ -12273,7 +12625,7 @@ function resolveSootsimPackageDir() {
12273
12625
  }
12274
12626
  } catch {
12275
12627
  }
12276
- const parent = import_node_path5.default.dirname(cur);
12628
+ const parent = import_node_path6.default.dirname(cur);
12277
12629
  if (parent === cur) break;
12278
12630
  cur = parent;
12279
12631
  }
@@ -12289,13 +12641,13 @@ function fileFromImportMeta() {
12289
12641
  }
12290
12642
  }
12291
12643
  async function withStartLock(projectId, provider, fn) {
12292
- const lockDir = import_node_path5.default.join(getUserDataDir(), "locks");
12644
+ const lockDir = import_node_path6.default.join(getUserDataDir(), "locks");
12293
12645
  import_node_fs6.default.mkdirSync(lockDir, { recursive: true });
12294
12646
  try {
12295
12647
  import_node_fs6.default.chmodSync(lockDir, 448);
12296
12648
  } catch {
12297
12649
  }
12298
- const lockPath = import_node_path5.default.join(lockDir, `start-${projectId}-${provider}.lock`);
12650
+ const lockPath = import_node_path6.default.join(lockDir, `start-${projectId}-${provider}.lock`);
12299
12651
  const deadline = Date.now() + 4e3;
12300
12652
  let fd = null;
12301
12653
  while (fd === null) {
@@ -12346,7 +12698,7 @@ function isProcessAlive(pid) {
12346
12698
  }
12347
12699
  }
12348
12700
  function mkfifoSync(p) {
12349
- const parent = import_node_path5.default.dirname(p);
12701
+ const parent = import_node_path6.default.dirname(p);
12350
12702
  import_node_fs6.default.mkdirSync(parent, { recursive: true });
12351
12703
  try {
12352
12704
  import_node_fs6.default.chmodSync(parent, 448);
@@ -12354,8 +12706,8 @@ function mkfifoSync(p) {
12354
12706
  }
12355
12707
  if (import_node_fs6.default.existsSync(p)) {
12356
12708
  try {
12357
- const stat = import_node_fs6.default.statSync(p);
12358
- if (stat.isFIFO()) {
12709
+ const stat2 = import_node_fs6.default.statSync(p);
12710
+ if (stat2.isFIFO()) {
12359
12711
  try {
12360
12712
  import_node_fs6.default.chmodSync(p, 384);
12361
12713
  } catch {
@@ -12404,7 +12756,7 @@ async function startSession(opts) {
12404
12756
  const transcript = transcriptPath(session.id);
12405
12757
  mkfifoSync(promptIn);
12406
12758
  mkfifoSync(eventsOut);
12407
- const transcriptDir = import_node_path5.default.dirname(transcript);
12759
+ const transcriptDir = import_node_path6.default.dirname(transcript);
12408
12760
  import_node_fs6.default.mkdirSync(transcriptDir, { recursive: true });
12409
12761
  try {
12410
12762
  import_node_fs6.default.chmodSync(transcriptDir, 448);
@@ -12587,14 +12939,14 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
12587
12939
  import_node_fs6.default.closeSync(fd);
12588
12940
  }
12589
12941
  }
12590
- var import_node_child_process3, import_node_crypto3, import_node_fs6, import_node_path5, import_node_readline, AgentSessionError;
12942
+ var import_node_child_process3, import_node_crypto3, import_node_fs6, import_node_path6, import_node_readline, AgentSessionError;
12591
12943
  var init_agent_sessions = __esm({
12592
12944
  "src/agent-sessions.ts"() {
12593
12945
  "use strict";
12594
12946
  import_node_child_process3 = require("node:child_process");
12595
12947
  import_node_crypto3 = require("node:crypto");
12596
12948
  import_node_fs6 = __toESM(require("node:fs"), 1);
12597
- import_node_path5 = __toESM(require("node:path"), 1);
12949
+ import_node_path6 = __toESM(require("node:path"), 1);
12598
12950
  import_node_readline = __toESM(require("node:readline"), 1);
12599
12951
  init_agent_events();
12600
12952
  init_agent_prompt();
@@ -12706,12 +13058,12 @@ function mapFrameworkToProjectFramework(fw) {
12706
13058
  if (fw === "one" || fw === "vxrn") return "one";
12707
13059
  return "unknown";
12708
13060
  }
12709
- var import_node_fs7, import_node_path6, WS_OPEN, SESSION_STATUS_PERSIST_DELAY_MS, AgentHost;
13061
+ var import_node_fs7, import_node_path7, WS_OPEN, SESSION_STATUS_PERSIST_DELAY_MS, AgentHost;
12710
13062
  var init_agent_host = __esm({
12711
13063
  "src/host/agent-host.ts"() {
12712
13064
  "use strict";
12713
13065
  import_node_fs7 = __toESM(require("node:fs"), 1);
12714
- import_node_path6 = __toESM(require("node:path"), 1);
13066
+ import_node_path7 = __toESM(require("node:path"), 1);
12715
13067
  init_dev_server_scanner();
12716
13068
  init_agent_sessions();
12717
13069
  init_attached_projects();
@@ -12910,7 +13262,7 @@ var init_agent_host = __esm({
12910
13262
  );
12911
13263
  const project = upsertProject({
12912
13264
  cwd: match.cwd,
12913
- name: match.projectName ?? import_node_path6.default.basename(match.cwd),
13265
+ name: match.projectName ?? import_node_path7.default.basename(match.cwd),
12914
13266
  preferredProvider: input.provider ?? existing?.preferredProvider,
12915
13267
  sourceRoots: existing?.sourceRoots ?? [match.cwd],
12916
13268
  knownBundleUrls,
@@ -12930,9 +13282,9 @@ var init_agent_host = __esm({
12930
13282
  const dir = getUserDataDir();
12931
13283
  return {
12932
13284
  userDataDir: dir,
12933
- storeFile: import_node_path6.default.join(dir, "attached-projects.json"),
12934
- sessionsDir: import_node_path6.default.join(dir, "sessions"),
12935
- transcriptsDir: import_node_path6.default.join(dir, "transcripts")
13285
+ storeFile: import_node_path7.default.join(dir, "attached-projects.json"),
13286
+ sessionsDir: import_node_path7.default.join(dir, "sessions"),
13287
+ transcriptsDir: import_node_path7.default.join(dir, "transcripts")
12936
13288
  };
12937
13289
  }
12938
13290
  // --- subscription management ---
@@ -13411,7 +13763,7 @@ async function handleFetchProxyRequest(req, res) {
13411
13763
  const switchToGet = (status === 301 || status === 302) && method === "POST" || status === 303 && method !== "GET" && method !== "HEAD";
13412
13764
  const redirectUrl = new URL(location, targetUrl2);
13413
13765
  proxyRes.resume();
13414
- await (0, import_promises2.finished)(proxyRes);
13766
+ await (0, import_promises3.finished)(proxyRes);
13415
13767
  await proxy(
13416
13768
  redirectUrl,
13417
13769
  switchToGet ? "GET" : method,
@@ -13436,7 +13788,7 @@ async function handleFetchProxyRequest(req, res) {
13436
13788
  );
13437
13789
  }
13438
13790
  res.statusCode = status;
13439
- await (0, import_promises2.pipeline)(proxyRes, res);
13791
+ await (0, import_promises3.pipeline)(proxyRes, res);
13440
13792
  };
13441
13793
  try {
13442
13794
  await proxy(upstreamUrl, originalMethod, body, 0);
@@ -13519,13 +13871,13 @@ function handleAppApiRequest(req, res) {
13519
13871
  req.pipe(proxyReq);
13520
13872
  return true;
13521
13873
  }
13522
- var import_http2, import_https, import_promises2, STRIP_FETCH_PROXY_HEADERS, FETCH_PROXY_CORS_HEADERS, APP_API_HEADER_REWRITES;
13874
+ var import_http2, import_https, import_promises3, STRIP_FETCH_PROXY_HEADERS, FETCH_PROXY_CORS_HEADERS, APP_API_HEADER_REWRITES;
13523
13875
  var init_fetch_proxy_handler = __esm({
13524
13876
  "src/host/fetch-proxy-handler.ts"() {
13525
13877
  "use strict";
13526
13878
  import_http2 = __toESM(require("http"), 1);
13527
13879
  import_https = __toESM(require("https"), 1);
13528
- import_promises2 = require("stream/promises");
13880
+ import_promises3 = require("stream/promises");
13529
13881
  init_backend_origin();
13530
13882
  init_fetch_proxy_overrides();
13531
13883
  STRIP_FETCH_PROXY_HEADERS = /* @__PURE__ */ new Set([
@@ -17732,14 +18084,14 @@ process.stdin.on('end', async () => {
17732
18084
  function getBaseDir() {
17733
18085
  const explicit = process.env[SESSION_FILE_ENV];
17734
18086
  if (explicit?.trim()) {
17735
- return (0, import_node_path7.dirname)((0, import_node_path7.resolve)(explicit));
18087
+ return (0, import_node_path8.dirname)((0, import_node_path8.resolve)(explicit));
17736
18088
  }
17737
18089
  return electronUserDataDir();
17738
18090
  }
17739
18091
  function getSharedDesktopAuthFilePath() {
17740
18092
  const explicit = process.env[SESSION_FILE_ENV];
17741
- if (explicit?.trim()) return (0, import_node_path7.resolve)(explicit);
17742
- return (0, import_node_path7.join)(getBaseDir(), "desktop-auth.json");
18093
+ if (explicit?.trim()) return (0, import_node_path8.resolve)(explicit);
18094
+ return (0, import_node_path8.join)(getBaseDir(), "desktop-auth.json");
17743
18095
  }
17744
18096
  function normalizeUser(input) {
17745
18097
  if (!input || typeof input !== "object") return null;
@@ -17799,12 +18151,12 @@ function readSharedDesktopAuthSession() {
17799
18151
  return null;
17800
18152
  }
17801
18153
  }
17802
- var import_node_fs8, import_node_path7, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
18154
+ var import_node_fs8, import_node_path8, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
17803
18155
  var init_shared_session = __esm({
17804
18156
  "src/auth/shared-session.ts"() {
17805
18157
  "use strict";
17806
18158
  import_node_fs8 = require("node:fs");
17807
- import_node_path7 = require("node:path");
18159
+ import_node_path8 = require("node:path");
17808
18160
  init_home_paths();
17809
18161
  SESSION_VERSION = 1;
17810
18162
  SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";