sootsim 0.1.140 → 0.1.141

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 (153) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-N767ME6M.js → agent-BFN5TIRU.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-ELHIUFZZ.js → agent-wrapper-A4UNOJOD.js} +2 -2
  4. package/dist-cli/chunks/{app-fonts-OZ3OSNAJ.js → app-fonts-KEAMDLYZ.js} +2 -2
  5. package/dist-cli/chunks/{assert-GGFUQBNB.js → assert-BWBAKX5N.js} +2 -2
  6. package/dist-cli/chunks/auto-bootstrap-WJH44ZIE.js +2 -0
  7. package/dist-cli/chunks/beta-VFKZHKER.js +2 -0
  8. package/dist-cli/chunks/{camera-5PYEDLLB.js → camera-P5TTGC72.js} +2 -2
  9. package/dist-cli/chunks/{chunk-PBS47TD5.js → chunk-33EJL7CG.js} +2 -2
  10. package/dist-cli/chunks/{chunk-BLQBPN76.js → chunk-3LN2PP4L.js} +2 -2
  11. package/dist-cli/chunks/{chunk-MRQRJINW.js → chunk-4ISWLDJG.js} +1 -1
  12. package/dist-cli/chunks/{chunk-EMNVJOEL.js → chunk-53DRW635.js} +3 -3
  13. package/dist-cli/chunks/{chunk-7SMEXHWJ.js → chunk-7A7VFR2C.js} +1 -1
  14. package/dist-cli/chunks/{chunk-GL74P6NR.js → chunk-7SO2SJ4H.js} +1 -1
  15. package/dist-cli/chunks/{chunk-RAY2DLSK.js → chunk-A5W3HB44.js} +1 -1
  16. package/dist-cli/chunks/{chunk-SSZBFWV7.js → chunk-AJGTCVQX.js} +1 -1
  17. package/dist-cli/chunks/{chunk-R5F7XGAO.js → chunk-AMSIP5PD.js} +3 -3
  18. package/dist-cli/chunks/{chunk-ZGDJ5TFU.js → chunk-AQVB4G34.js} +2 -2
  19. package/dist-cli/chunks/{chunk-N2XPC4Z7.js → chunk-DM5KNA7Q.js} +2 -2
  20. package/dist-cli/chunks/{chunk-ZN4Z2W7F.js → chunk-EIZ6LJP2.js} +2 -2
  21. package/dist-cli/chunks/{chunk-5VTYMBUK.js → chunk-ETB6DHJM.js} +2 -2
  22. package/dist-cli/chunks/{chunk-WGDXZMKT.js → chunk-HDCTWR2Q.js} +2 -2
  23. package/dist-cli/chunks/chunk-I3JPJMJB.js +5 -0
  24. package/dist-cli/chunks/{chunk-QRRBQE6M.js → chunk-I6SWX7OI.js} +2 -2
  25. package/dist-cli/chunks/{chunk-BGXNYXBC.js → chunk-IILFDOSF.js} +1 -1
  26. package/dist-cli/chunks/{chunk-4FGNOWB6.js → chunk-IITPPGBS.js} +1 -1
  27. package/dist-cli/chunks/{chunk-QXOZB7WD.js → chunk-ITJLXD4X.js} +2 -2
  28. package/dist-cli/chunks/{chunk-BM7QWZRI.js → chunk-JJBNA2JO.js} +2 -2
  29. package/dist-cli/chunks/{chunk-AI65UVSN.js → chunk-JM5XCDBF.js} +2 -2
  30. package/dist-cli/chunks/{chunk-AOICEZCA.js → chunk-JQTHQOPS.js} +2 -2
  31. package/dist-cli/chunks/{chunk-X6AWKKL4.js → chunk-KMQWCYU7.js} +2 -2
  32. package/dist-cli/chunks/{chunk-XGYD25DJ.js → chunk-LHIPDN4B.js} +1 -1
  33. package/dist-cli/chunks/{chunk-6KUVOSFF.js → chunk-LHS4PEAA.js} +2 -2
  34. package/dist-cli/chunks/{chunk-ZVQOEMXS.js → chunk-M7S4VLEL.js} +54 -54
  35. package/dist-cli/chunks/{chunk-REIC7HRW.js → chunk-MENSR2TZ.js} +1 -1
  36. package/dist-cli/chunks/chunk-MHUNWWWS.js +412 -0
  37. package/dist-cli/chunks/chunk-MYKHUFW2.js +1 -0
  38. package/dist-cli/chunks/chunk-NOAONZTZ.js +119 -0
  39. package/dist-cli/chunks/{chunk-C3FURRBF.js → chunk-NQJD2WTM.js} +1 -1
  40. package/dist-cli/chunks/{chunk-QOZ2Q4FH.js → chunk-PVPWCA2K.js} +1 -1
  41. package/dist-cli/chunks/{chunk-GYZNLDBX.js → chunk-RBUJZXNR.js} +5 -5
  42. package/dist-cli/chunks/{chunk-AP2MOP44.js → chunk-RUXWU3UH.js} +1 -1
  43. package/dist-cli/chunks/{chunk-UHTE6FLK.js → chunk-SXHBK5IJ.js} +2 -2
  44. package/dist-cli/chunks/chunk-SYRS7NKN.js +1 -0
  45. package/dist-cli/chunks/chunk-TUZVZ5QS.js +1 -0
  46. package/dist-cli/chunks/{chunk-CQ3LV5VL.js → chunk-URPQTI2I.js} +2 -2
  47. package/dist-cli/chunks/{chunk-GI43DDEI.js → chunk-UYQDGXHQ.js} +1 -1
  48. package/dist-cli/chunks/{chunk-4FBFOWV3.js → chunk-WUQHVDJU.js} +2 -2
  49. package/dist-cli/chunks/{chunk-FYUDIUFX.js → chunk-XD7XHQUO.js} +2 -2
  50. package/dist-cli/chunks/{chunk-77TL74AM.js → chunk-XERRDQLM.js} +1 -1
  51. package/dist-cli/chunks/{chunk-O2SQNUDP.js → chunk-XQRCVSK3.js} +1 -1
  52. package/dist-cli/chunks/{chunk-HPTMLB7V.js → chunk-YOJ6BZCH.js} +1 -1
  53. package/dist-cli/chunks/chunk-ZBN3P5JE.js +2 -0
  54. package/dist-cli/chunks/cli-version-3G6HHMRW.js +2 -0
  55. package/dist-cli/chunks/{compat-U3772TUK.js → compat-3Z67EPSJ.js} +3 -3
  56. package/dist-cli/chunks/{config-6CZCIYKJ.js → config-SH3NTYZ2.js} +2 -2
  57. package/dist-cli/chunks/{control-NVA25O65.js → control-2XVEDKYZ.js} +2 -2
  58. package/dist-cli/chunks/{cpu-profile-WRLTZYO6.js → cpu-profile-FANLHU4S.js} +2 -2
  59. package/dist-cli/chunks/{daemon-QQPGLGS6.js → daemon-QGDVR4JT.js} +2 -2
  60. package/dist-cli/chunks/{debug-RKYLSDZV.js → debug-EIUEPLFN.js} +3 -3
  61. package/dist-cli/chunks/{detox-ZRUQQU22.js → detox-EV3KYFKR.js} +2 -2
  62. package/dist-cli/chunks/{device-HXTOLEWY.js → device-UC5DAVA6.js} +2 -2
  63. package/dist-cli/chunks/{diagnose-QN4E4WA6.js → diagnose-Q2M2AJBD.js} +2 -2
  64. package/dist-cli/chunks/drivers-VJIWLDTC.js +2 -0
  65. package/dist-cli/chunks/{electron-ZHRC4WQ5.js → electron-PXKF52Q6.js} +3 -3
  66. package/dist-cli/chunks/flow-RGMXGVLL.js +2 -0
  67. package/dist-cli/chunks/help-TBZZP4SA.js +2 -0
  68. package/dist-cli/chunks/{hints-HCHKMDUE.js → hints-HS7X2FIO.js} +2 -2
  69. package/dist-cli/chunks/{home-paths-3OHKRAE4.js → home-paths-KPMXMJQ7.js} +2 -2
  70. package/dist-cli/chunks/{inspect-QXUBDKJJ.js → inspect-ZUWEMCIG.js} +3 -3
  71. package/dist-cli/chunks/install-FPYDDDQ4.js +2 -0
  72. package/dist-cli/chunks/{install-desktop-QCX44BGL.js → install-desktop-H6ZTTVXC.js} +3 -3
  73. package/dist-cli/chunks/{keys-VEP2KPUF.js → keys-6OBZZLCJ.js} +2 -2
  74. package/dist-cli/chunks/{launch-K4BPQLTP.js → launch-7JASEDHP.js} +3 -3
  75. package/dist-cli/chunks/{login-UVC5XRKR.js → login-JWMB6JNS.js} +4 -4
  76. package/dist-cli/chunks/{logout-3VW34IBA.js → logout-LWVFUKF5.js} +2 -2
  77. package/dist-cli/chunks/maestro-WX22SLCR.js +94 -0
  78. package/dist-cli/chunks/optional-demo-registry-52MHQCYV.js +2 -0
  79. package/dist-cli/chunks/{preview-TZYJMLEJ.js → preview-SDMLCW3U.js} +2 -2
  80. package/dist-cli/chunks/{profile-HDJRF7YB.js → profile-MQVLCO7R.js} +2 -2
  81. package/dist-cli/chunks/{react-RLJR26M7.js → react-2JFP5W4W.js} +2 -2
  82. package/dist-cli/chunks/{record-2LDDHHUY.js → record-IJJ3SPXP.js} +2 -2
  83. package/dist-cli/chunks/runtime-JJMZ4AF3.js +2 -0
  84. package/dist-cli/chunks/{runtime-delivery-3F6O57E5.js → runtime-delivery-5M2P7LEI.js} +2 -2
  85. package/dist-cli/chunks/{screenshot-QAUSSEPK.js → screenshot-4QAGJCPZ.js} +2 -2
  86. package/dist-cli/chunks/{screenshot-mode-K6HEVK4K.js → screenshot-mode-PSAU7TH4.js} +2 -2
  87. package/dist-cli/chunks/{screenshots-TWMCGUBT.js → screenshots-73VI4UUL.js} +2 -2
  88. package/dist-cli/chunks/{server-ZPIZCBW5.js → server-BXD5WKQS.js} +3 -3
  89. package/dist-cli/chunks/setup-repo-F2P5RZ4R.js +2 -0
  90. package/dist-cli/chunks/{skills-NI3RH7CW.js → skills-IEJOURWM.js} +2 -2
  91. package/dist-cli/chunks/{start-G6CQL6HJ.js → start-CLBAJ4LJ.js} +4 -4
  92. package/dist-cli/chunks/store-7DIOVJNK.js +2 -0
  93. package/dist-cli/chunks/telemetry-3XHPQYOQ.js +2 -0
  94. package/dist-cli/chunks/{test-V47D6EPK.js → test-42YWJ5ZT.js} +3 -3
  95. package/dist-cli/chunks/{three-mode-G7N3LRHM.js → three-mode-5DU4IBF5.js} +2 -2
  96. package/dist-cli/chunks/{timeline-EBUOILTJ.js → timeline-WJYQRW5S.js} +2 -2
  97. package/dist-cli/chunks/{upgrade-OQJLTCQP.js → upgrade-F7ADMCLU.js} +2 -2
  98. package/dist-cli/chunks/upload-TJ2XKWDS.js +2 -0
  99. package/dist-cli/chunks/{version-3YJPPUE5.js → version-SLA5P34B.js} +2 -2
  100. package/dist-cli/chunks/{web-ZKUX5ICX.js → web-OGC6GSKM.js} +2 -2
  101. package/dist-cli/chunks/{what-happened-HOY3TA42.js → what-happened-VYXK3O2C.js} +2 -2
  102. package/dist-cli/chunks/{whoami-GOCSBVTG.js → whoami-QL2LTKOF.js} +2 -2
  103. package/dist-lib/agent-daemon-client.cjs +1 -1
  104. package/dist-lib/agent-events.cjs +1 -1
  105. package/dist-lib/agent-sessions.cjs +1 -1
  106. package/dist-lib/attached-projects.cjs +1 -1
  107. package/dist-lib/auth/shared-session.cjs +1 -1
  108. package/dist-lib/backend-origin.cjs +1 -1
  109. package/dist-lib/beta.cjs +1 -1
  110. package/dist-lib/beta.mjs +1 -1
  111. package/dist-lib/bridge-constants.cjs +1 -1
  112. package/dist-lib/cli-constants.cjs +1 -1
  113. package/dist-lib/config.cjs +5 -2
  114. package/dist-lib/detox/index.cjs +1 -1
  115. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  116. package/dist-lib/home-paths.cjs +1 -1
  117. package/dist-lib/host/bridge-host.cjs +2 -2
  118. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  119. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  120. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  121. package/dist-lib/host/websocket-proxy.cjs +1 -1
  122. package/dist-lib/index.cjs +1 -1
  123. package/dist-lib/metro.cjs +1 -1
  124. package/dist-lib/profiles.cjs +1 -1
  125. package/dist-lib/render-mode.cjs +1 -1
  126. package/dist-lib/scripts/dev-server-scanner.cjs +2 -2
  127. package/dist-lib/sdk.cjs +1 -1
  128. package/dist-lib/sdk.mjs +1 -1
  129. package/dist-lib/skills.cjs +351 -80
  130. package/dist-lib/vite.cjs +1 -1
  131. package/package.json +1 -1
  132. package/src/config.ts +13 -0
  133. package/dist-cli/chunks/auto-bootstrap-L5E6XMCK.js +0 -2
  134. package/dist-cli/chunks/beta-D74SDA2L.js +0 -2
  135. package/dist-cli/chunks/chunk-5EP5RRNS.js +0 -381
  136. package/dist-cli/chunks/chunk-BEA3AO36.js +0 -5
  137. package/dist-cli/chunks/chunk-EH6YDCSN.js +0 -119
  138. package/dist-cli/chunks/chunk-NQG4R5K2.js +0 -1
  139. package/dist-cli/chunks/chunk-Q5Z7P54I.js +0 -2
  140. package/dist-cli/chunks/chunk-S7I6ZCT2.js +0 -1
  141. package/dist-cli/chunks/chunk-WN3WZEE5.js +0 -1
  142. package/dist-cli/chunks/cli-version-EZRTEUXF.js +0 -2
  143. package/dist-cli/chunks/drivers-EVK22AX5.js +0 -2
  144. package/dist-cli/chunks/flow-ICCRVJVX.js +0 -2
  145. package/dist-cli/chunks/help-QMZ35MIQ.js +0 -2
  146. package/dist-cli/chunks/install-JSDZIE2T.js +0 -2
  147. package/dist-cli/chunks/maestro-HTFXXMLR.js +0 -80
  148. package/dist-cli/chunks/optional-demo-registry-5YYEAL46.js +0 -2
  149. package/dist-cli/chunks/runtime-QPYF2WQX.js +0 -2
  150. package/dist-cli/chunks/setup-repo-VHOZJEIV.js +0 -2
  151. package/dist-cli/chunks/store-F6MJUJYW.js +0 -2
  152. package/dist-cli/chunks/telemetry-DM2Y7OQJ.js +0 -2
  153. package/dist-cli/chunks/upload-W3YCA65H.js +0 -2
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.140 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.141 | (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;
@@ -9982,7 +9982,7 @@ function hasOwnKeys(value) {
9982
9982
  }
9983
9983
  function hasSootSimConfig(config) {
9984
9984
  if (!config) return false;
9985
- return hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.env) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
9985
+ return hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
9986
9986
  }
9987
9987
  function applySootSimConfigToUrl(url, config) {
9988
9988
  const parsed = new URL(url);
@@ -15465,36 +15465,234 @@ var init_settling = __esm({
15465
15465
  }
15466
15466
  });
15467
15467
 
15468
- // cli/flow-file.ts
15469
- function interpolateFlowEnv(value, scopedVars) {
15470
- if (typeof value === "string") {
15471
- return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, name) => {
15472
- if (scopedVars?.has(name)) return scopedVars.get(name);
15473
- const resolved = process.env[name];
15474
- if (resolved === void 0) {
15475
- throw new Error(`missing environment variable for flow placeholder: ${name}`);
15476
- }
15477
- return resolved;
15478
- });
15468
+ // cli/maestro-js.ts
15469
+ function executeSyncHttp(url, method, params) {
15470
+ if (params?.multipartForm) {
15471
+ throw new Error("http: multipartForm is not supported by sootsim yet");
15479
15472
  }
15480
- if (Array.isArray(value)) {
15481
- return value.map((entry) => interpolateFlowEnv(entry, scopedVars));
15473
+ const child = (0, import_child_process6.spawnSync)(process.execPath, ["-e", HTTP_CHILD_SRC], {
15474
+ input: JSON.stringify({ url, method, headers: params?.headers, body: params?.body }),
15475
+ encoding: "utf8",
15476
+ timeout: HTTP_TIMEOUT_MS,
15477
+ maxBuffer: 64 * 1024 * 1024
15478
+ });
15479
+ if (child.error) {
15480
+ throw new Error(`http ${method} ${url} failed: ${child.error.message}`);
15482
15481
  }
15483
- if (value && typeof value === "object") {
15484
- return Object.fromEntries(
15485
- Object.entries(value).map(([key, entry]) => [
15486
- key,
15487
- interpolateFlowEnv(entry, scopedVars)
15488
- ])
15482
+ let parsed;
15483
+ try {
15484
+ parsed = JSON.parse(child.stdout || "");
15485
+ } catch {
15486
+ throw new Error(
15487
+ `http ${method} ${url} failed: no response (${(child.stderr || "").trim().slice(0, 200)})`
15489
15488
  );
15490
15489
  }
15491
- return value;
15490
+ const result = parsed;
15491
+ if (result.__error) {
15492
+ throw new Error(`http ${method} ${url} failed: ${result.__error}`);
15493
+ }
15494
+ return result;
15495
+ }
15496
+ function stringifyJs(value) {
15497
+ if (value === void 0) return "undefined";
15498
+ if (value === null) return "null";
15499
+ if (typeof value === "object") {
15500
+ try {
15501
+ return JSON.stringify(value);
15502
+ } catch {
15503
+ return String(value);
15504
+ }
15505
+ }
15506
+ return String(value);
15492
15507
  }
15493
- var import_yaml;
15494
- var init_flow_file = __esm({
15495
- "cli/flow-file.ts"() {
15508
+ function scriptConditionIsTruthy(value) {
15509
+ if (value === void 0 || value === null) return false;
15510
+ if (typeof value === "boolean") return value;
15511
+ const text = String(value);
15512
+ if (text.trim().length === 0) return false;
15513
+ if (text.toLowerCase() === "false") return false;
15514
+ if (text === "undefined" || text === "null") return false;
15515
+ const num = Number(text);
15516
+ if (!Number.isNaN(num) && num === 0) return false;
15517
+ return true;
15518
+ }
15519
+ var import_child_process6, vm, HTTP_TIMEOUT_MS, HTTP_CHILD_SRC, TEMPLATE_RE, ESCAPED_TEMPLATE_RE, BARE_IDENTIFIER_RE, MaestroJsContext;
15520
+ var init_maestro_js = __esm({
15521
+ "cli/maestro-js.ts"() {
15496
15522
  "use strict";
15497
- import_yaml = __toESM(require("yaml"), 1);
15523
+ import_child_process6 = require("child_process");
15524
+ vm = __toESM(require("vm"), 1);
15525
+ HTTP_TIMEOUT_MS = 3e5;
15526
+ HTTP_CHILD_SRC = `
15527
+ let input = '';
15528
+ process.stdin.on('data', (c) => { input += c });
15529
+ process.stdin.on('end', async () => {
15530
+ try {
15531
+ const req = JSON.parse(input);
15532
+ const res = await fetch(req.url, {
15533
+ method: req.method,
15534
+ headers: req.headers,
15535
+ body: req.body === undefined || req.body === null ? undefined : req.body,
15536
+ });
15537
+ const body = await res.text();
15538
+ const headers = {};
15539
+ for (const [k, v] of res.headers.entries()) {
15540
+ headers[k] = headers[k] ? headers[k] + ',' + v : v;
15541
+ }
15542
+ process.stdout.write(JSON.stringify({ ok: res.ok, status: res.status, body, headers }));
15543
+ } catch (err) {
15544
+ process.stdout.write(JSON.stringify({ __error: (err && err.message) || String(err) }));
15545
+ process.exitCode = 1;
15546
+ }
15547
+ });
15548
+ `;
15549
+ TEMPLATE_RE = /(?<!\\)\$\{([^$]*)\}/g;
15550
+ ESCAPED_TEMPLATE_RE = /\\(\$\{[^$]*\})/g;
15551
+ BARE_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
15552
+ MaestroJsContext = class {
15553
+ context;
15554
+ envBinding = /* @__PURE__ */ new Map();
15555
+ envScopeStack = [];
15556
+ // env keys currently materialized as context globals — cleared and re-set
15557
+ // before each evaluation, mirroring upstream syncBindingsToContext.
15558
+ syncedEnvKeys = /* @__PURE__ */ new Set();
15559
+ output = {};
15560
+ maestro;
15561
+ constructor(opts = {}) {
15562
+ this.maestro = { copiedText: null, platform: opts.platform ?? "ios" };
15563
+ const onLog = opts.onLog ?? ((msg) => console.log(`[flow] js: ${msg}`));
15564
+ const sandbox = {
15565
+ output: this.output,
15566
+ maestro: this.maestro,
15567
+ http: {
15568
+ get: (url, params) => executeSyncHttp(url, "GET", params),
15569
+ post: (url, params) => executeSyncHttp(url, "POST", params),
15570
+ put: (url, params) => executeSyncHttp(url, "PUT", params),
15571
+ delete: (url, params) => executeSyncHttp(url, "DELETE", params),
15572
+ request: (url, params) => executeSyncHttp(url, (params?.method ?? "GET").toUpperCase(), params)
15573
+ },
15574
+ console: {
15575
+ log: (...args) => onLog(args.map((a) => typeof a === "string" ? a : stringifyJs(a)).join(" "))
15576
+ }
15577
+ };
15578
+ this.context = vm.createContext(sandbox);
15579
+ vm.runInContext(
15580
+ `
15581
+ globalThis.__maestroScope = new Proxy(globalThis, {
15582
+ has() { return true },
15583
+ get(target, key) { return target[key] },
15584
+ })
15585
+ function json(text) { return JSON.parse(text) }
15586
+ function relativePoint(x, y) {
15587
+ var xPercent = Math.ceil(x * 100) + '%'
15588
+ var yPercent = Math.ceil(y * 100) + '%'
15589
+ return xPercent + ',' + yPercent
15590
+ }
15591
+ `,
15592
+ this.context
15593
+ );
15594
+ for (const [key, value] of Object.entries(process.env)) {
15595
+ if (value !== void 0) this.envBinding.set(key, value);
15596
+ }
15597
+ }
15598
+ putEnv(key, value) {
15599
+ this.envBinding.set(key, value);
15600
+ }
15601
+ setCopiedText(text) {
15602
+ this.maestro.copiedText = text;
15603
+ }
15604
+ enterEnvScope() {
15605
+ this.envScopeStack.push(new Map(this.envBinding));
15606
+ }
15607
+ leaveEnvScope() {
15608
+ const previous = this.envScopeStack.pop();
15609
+ if (previous) {
15610
+ this.envBinding.clear();
15611
+ for (const [k, v] of previous) this.envBinding.set(k, v);
15612
+ }
15613
+ }
15614
+ // evaluate a JS snippet in the shared context. mirrors upstream
15615
+ // evalWithIIFE: the script is embedded in a template literal and run
15616
+ // through eval inside an IIFE so var/let/const stay scoped to this
15617
+ // evaluation while the last expression's value is returned.
15618
+ evaluate(script, opts = {}) {
15619
+ const env = opts.env;
15620
+ if (env && Object.keys(env).length > 0) {
15621
+ this.enterEnvScope();
15622
+ try {
15623
+ for (const [k, v] of Object.entries(env)) this.envBinding.set(k, v);
15624
+ return this.evalRaw(script);
15625
+ } finally {
15626
+ this.leaveEnvScope();
15627
+ }
15628
+ }
15629
+ return this.evalRaw(script);
15630
+ }
15631
+ evalRaw(script) {
15632
+ this.syncEnvToContext();
15633
+ const escaped = script.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
15634
+ return vm.runInContext(
15635
+ `(function(){ with(__maestroScope){ return eval(\`${escaped}\`) } })()`,
15636
+ this.context
15637
+ );
15638
+ }
15639
+ syncEnvToContext() {
15640
+ const globals = vm.runInContext("globalThis", this.context);
15641
+ for (const key of this.syncedEnvKeys) {
15642
+ if (!this.envBinding.has(key)) delete globals[key];
15643
+ }
15644
+ this.syncedEnvKeys = /* @__PURE__ */ new Set();
15645
+ for (const [key, value] of this.envBinding) {
15646
+ try {
15647
+ globals[key] = value;
15648
+ this.syncedEnvKeys.add(key);
15649
+ } catch {
15650
+ }
15651
+ }
15652
+ }
15653
+ // upstream Env.kt String.evaluateScripts: replace every unescaped `${expr}`
15654
+ // with the stringified evaluation result, then unescape `\${...}`.
15655
+ evaluateStringTemplate(value) {
15656
+ const replaced = value.replace(TEMPLATE_RE, (_match, expr) => {
15657
+ if (expr.trim().length === 0) return "";
15658
+ const result = this.evaluate(expr);
15659
+ if (result === void 0 && BARE_IDENTIFIER_RE.test(expr.trim())) {
15660
+ throw new Error(`missing variable for flow placeholder: ${expr.trim()}`);
15661
+ }
15662
+ return stringifyJs(result);
15663
+ });
15664
+ return replaced.replace(ESCAPED_TEMPLATE_RE, (_match, inner) => inner);
15665
+ }
15666
+ // walk a parsed step and evaluate every string template. nested command
15667
+ // lists are skipped — each nested command evaluates its own strings when
15668
+ // it executes (matching upstream per-command evaluateScripts timing, and
15669
+ // required for values that change between iterations, e.g. copyTextFrom
15670
+ // inside repeat).
15671
+ interpolateStep(step) {
15672
+ return this.interpolateValue(step, null);
15673
+ }
15674
+ interpolateValue(value, parentKey) {
15675
+ if (typeof value === "string") {
15676
+ if (parentKey === "evalScript") return value;
15677
+ return this.evaluateStringTemplate(value);
15678
+ }
15679
+ if (Array.isArray(value)) {
15680
+ if (parentKey === "commands" || parentKey === "onFlowStart" || parentKey === "onFlowComplete") {
15681
+ return value;
15682
+ }
15683
+ return value.map((entry) => this.interpolateValue(entry, parentKey));
15684
+ }
15685
+ if (value && typeof value === "object") {
15686
+ return Object.fromEntries(
15687
+ Object.entries(value).map(([key, entry]) => [
15688
+ key,
15689
+ this.interpolateValue(entry, key)
15690
+ ])
15691
+ );
15692
+ }
15693
+ return value;
15694
+ }
15695
+ };
15498
15696
  }
15499
15697
  });
15500
15698
 
@@ -15814,19 +16012,11 @@ var init_recording_access = __esm({
15814
16012
  var bridge_flow_runner_exports = {};
15815
16013
  __export(bridge_flow_runner_exports, {
15816
16014
  SootSimBridgeFlowRunner: () => SootSimBridgeFlowRunner,
15817
- clearFlowScopedVars: () => clearFlowScopedVars,
15818
16015
  normalizeFlowScreenshotSpec: () => normalizeFlowScreenshotSpec,
15819
16016
  parseFlowSteps: () => parseFlowSteps,
15820
16017
  resolveFlowScreenshotPath: () => resolveFlowScreenshotPath,
15821
- resolveFlowScreenshotPathWithMode: () => resolveFlowScreenshotPathWithMode,
15822
- setFlowScopedVar: () => setFlowScopedVar
16018
+ resolveFlowScreenshotPathWithMode: () => resolveFlowScreenshotPathWithMode
15823
16019
  });
15824
- function setFlowScopedVar(name, value) {
15825
- flowScopedVars.set(name, value);
15826
- }
15827
- function clearFlowScopedVars() {
15828
- flowScopedVars.clear();
15829
- }
15830
16020
  function sleep(ms) {
15831
16021
  return new Promise((resolve6) => setTimeout(resolve6, ms));
15832
16022
  }
@@ -15873,34 +16063,39 @@ function parsePoint(value) {
15873
16063
  function parseFlowSteps(content) {
15874
16064
  const parts = content.split(/^---$/m);
15875
16065
  const candidate = parts.length > 1 ? parts[parts.length - 1] : content;
15876
- const parsed = interpolateFlowEnv(import_yaml2.default.parse(candidate), flowScopedVars);
16066
+ const parsed = import_yaml.default.parse(candidate);
15877
16067
  return Array.isArray(parsed) ? parsed : [];
15878
16068
  }
15879
- var fs7, path7, import_settings2, import_yaml2, DEFAULT_TIMEOUT, SCREEN_W, SCREEN_H, CLI_PERF_SESSION_GLOBAL, MAESTRO_COPIED_TEXT_KEY, flowScopedVars, SootSimBridgeFlowRunner;
16069
+ var fs7, path7, import_settings2, import_yaml, DEFAULT_TIMEOUT, SCREEN_W, SCREEN_H, CLI_PERF_SESSION_GLOBAL, SootSimBridgeFlowRunner;
15880
16070
  var init_bridge_flow_runner = __esm({
15881
16071
  "cli/bridge-flow-runner.ts"() {
15882
16072
  "use strict";
15883
16073
  fs7 = __toESM(require("fs"), 1);
15884
16074
  path7 = __toESM(require("path"), 1);
15885
16075
  import_settings2 = require("sootsim-engine/settings");
15886
- import_yaml2 = __toESM(require("yaml"), 1);
16076
+ import_yaml = __toESM(require("yaml"), 1);
15887
16077
  init_frame_compose();
15888
16078
  init_app_state_reset();
15889
16079
  init_settling();
15890
- init_flow_file();
16080
+ init_maestro_js();
15891
16081
  init_recording_access();
15892
16082
  DEFAULT_TIMEOUT = 1e4;
15893
16083
  SCREEN_W = 393;
15894
16084
  SCREEN_H = 852;
15895
16085
  CLI_PERF_SESSION_GLOBAL = "__sootsimCliPerf";
15896
- MAESTRO_COPIED_TEXT_KEY = "maestroCopiedText";
15897
- flowScopedVars = /* @__PURE__ */ new Map();
15898
16086
  SootSimBridgeFlowRunner = class {
15899
16087
  constructor(bridge, opts) {
15900
16088
  this.bridge = bridge;
15901
16089
  this.opts = opts;
15902
16090
  }
15903
16091
  stepDelay = 0;
16092
+ // maestro-compatible JS context for the whole flow run (shared with
16093
+ // runFlow sub-flows): `${...}` templates, runScript, evalScript, output,
16094
+ // maestro.copiedText. one per runner = one per flow file, like upstream.
16095
+ js = new MaestroJsContext({
16096
+ platform: "ios",
16097
+ onLog: (msg) => console.log(`[flow] js: ${msg}`)
16098
+ });
15904
16099
  firstLaunchDone = false;
15905
16100
  profilingEnabled = false;
15906
16101
  recordingEnabled = false;
@@ -16717,6 +16912,9 @@ var init_bridge_flow_runner = __esm({
16717
16912
  }
16718
16913
  async launchApp(opts) {
16719
16914
  await this.refreshSimId();
16915
+ if (opts && typeof opts === "object" && opts.arguments) {
16916
+ console.log("[flow] launchApp.arguments ignored (sootsim has no native process)");
16917
+ }
16720
16918
  const wantsClear = !!(opts && typeof opts === "object" && opts.clearState);
16721
16919
  if (wantsClear) {
16722
16920
  await this.evaluate(`(async () => {
@@ -16900,7 +17098,8 @@ var init_bridge_flow_runner = __esm({
16900
17098
  );
16901
17099
  }
16902
17100
  // maestro copyTextFrom: find an element and capture its text for use in
16903
- // later steps via ${maestroCopiedText}. the matcher shape matches tapOn.
17101
+ // later steps via ${maestro.copiedText} (upstream form) or the legacy
17102
+ // ${maestroCopiedText}. the matcher shape matches tapOn.
16904
17103
  async copyTextFrom(target) {
16905
17104
  const opts = typeof target === "string" ? { id: target } : target;
16906
17105
  const node = await this.findElement(opts);
@@ -16908,36 +17107,52 @@ var init_bridge_flow_runner = __esm({
16908
17107
  throw new Error(`copyTextFrom: element not found: ${JSON.stringify(opts)}`);
16909
17108
  }
16910
17109
  const captured = node.text ?? node.testID ?? "";
16911
- flowScopedVars.set(MAESTRO_COPIED_TEXT_KEY, captured);
17110
+ this.js.setCopiedText(captured);
17111
+ this.js.putEnv("maestroCopiedText", captured);
16912
17112
  console.log(`[flow] copied text: ${JSON.stringify(captured)}`);
16913
17113
  }
16914
- // maestro evalScript: run arbitrary JS in the page via the bridge's eval
16915
- // channel. the return value is logged but not stored use copyTextFrom
16916
- // (or a side-effect on window) for flows that need to round-trip data.
16917
- async evalScript(code) {
16918
- const result = await this.evaluate(`(async () => {
16919
- try {
16920
- return { ok: true, value: await (async () => { ${code} })() }
16921
- } catch (err) {
16922
- return { ok: false, error: err && err.message ? err.message : String(err) }
16923
- }
16924
- })()`);
16925
- const r = result;
16926
- if (!r.ok) throw new Error(`evalScript failed: ${r.error}`);
16927
- if (r.value !== void 0) {
16928
- console.log(`[flow] evalScript ->`, r.value);
17114
+ // maestro evalScript: run JS in the flow's shared HOST-side context (the
17115
+ // same engine that owns `output` and env vars)never in the app page.
17116
+ // the canonical maestro form is `evalScript: ${output.x = 1}`, which is
17117
+ // pure template evaluation. a script with no `${}` at all would be a
17118
+ // silent no-op upstream; we charitably evaluate it as raw JS in the same
17119
+ // context so plain-JS evalScript blocks fail or work loudly.
17120
+ evalScript(code) {
17121
+ const hasTemplate = /(?<!\\)\$\{[^$]*\}/.test(code);
17122
+ const result = hasTemplate ? this.js.evaluateStringTemplate(code) : this.js.evaluate(code);
17123
+ if (result !== void 0 && result !== "") {
17124
+ console.log(`[flow] evalScript ->`, result);
16929
17125
  }
16930
17126
  }
16931
- // maestro openLink: navigate the sim to a URL via the bridge's eval
16932
- // channel. on-device maestro asks the OS to open the link; in sootsim we
16933
- // just drive window.location so the current app sees the deep link.
17127
+ // maestro runScript: execute a JS file in the shared flow context. env
17128
+ // vars are scoped to the script (upstream runInSubScope=true). paths
17129
+ // resolve relative to the flow file, like runFlow.
17130
+ runScript(target) {
17131
+ const spec = typeof target === "string" ? { file: target } : target;
17132
+ if (!spec.file) throw new Error("runScript requires a file");
17133
+ const scriptPath = path7.resolve(this.opts.flowDir, spec.file);
17134
+ const source = fs7.readFileSync(scriptPath, "utf8");
17135
+ this.js.evaluate(source, { env: spec.env });
17136
+ console.log(`[flow] runScript: ${spec.file} done`);
17137
+ }
17138
+ // maestro openLink: on-device maestro asks the OS to open the link, and
17139
+ // iOS routes an app-claimed URL into the running app as a Linking 'url'
17140
+ // event. sootsim mirrors that: dispatch through the engine's Linking
17141
+ // emulation so react-navigation useLinking / addEventListener('url')
17142
+ // handlers fire exactly like on a real device. an app that doesn't
17143
+ // handle the link simply ignores it (same as iOS routing to Safari —
17144
+ // the app under test sees nothing).
16934
17145
  async openLink(target) {
16935
17146
  const link = typeof target === "string" ? target : target.link;
16936
17147
  if (!link) throw new Error("openLink: missing link");
16937
- await this.evaluate(`window.location.href = ${JSON.stringify(link)}`);
17148
+ const result = await this.callTest(
17149
+ "openDeepLink",
17150
+ link
17151
+ );
17152
+ if (!result?.ok) {
17153
+ throw new Error(`openLink failed: ${result?.error || "no test bridge"}`);
17154
+ }
16938
17155
  await sleep(300);
16939
- await this.refreshSimId();
16940
- await this.waitForTree(3e4);
16941
17156
  }
16942
17157
  // evaluate a `when:` predicate. returns true if the step should run.
16943
17158
  async evaluateWhen(when) {
@@ -16952,10 +17167,10 @@ var init_bridge_flow_runner = __esm({
16952
17167
  return !el;
16953
17168
  }
16954
17169
  if (when.platform !== void 0) {
16955
- return when.platform.toLowerCase() === "ios";
17170
+ return when.platform.toLowerCase() === this.js.maestro.platform.toLowerCase();
16956
17171
  }
16957
17172
  if (when.true !== void 0) {
16958
- return when.true.toLowerCase() !== "false";
17173
+ return scriptConditionIsTruthy(when.true);
16959
17174
  }
16960
17175
  return true;
16961
17176
  }
@@ -16966,9 +17181,26 @@ var init_bridge_flow_runner = __esm({
16966
17181
  const value = entry ? entry[1] : void 0;
16967
17182
  return !!(value && typeof value === "object" && "optional" in value && value.optional);
16968
17183
  }
16969
- async runStep(step, stepIndex) {
16970
- const stepName = Object.keys(step).find((k) => k !== "when") || Object.keys(step)[0];
17184
+ async runStep(rawStep, stepIndex) {
17185
+ const stepName = Object.keys(rawStep).find((k) => k !== "when") || Object.keys(rawStep)[0];
16971
17186
  console.log(`[flow] step ${stepIndex + 1}: ${stepName}`);
17187
+ let step;
17188
+ try {
17189
+ step = this.js.interpolateStep(rawStep);
17190
+ } catch (error) {
17191
+ if (this.isOptional(rawStep)) {
17192
+ console.log(
17193
+ `[flow] (optional, skipped: ${error.message.slice(0, 80)})`
17194
+ );
17195
+ return;
17196
+ }
17197
+ this.lastFailedStep = {
17198
+ index: stepIndex,
17199
+ kind: stepName,
17200
+ target: rawStep[stepName]
17201
+ };
17202
+ throw error;
17203
+ }
16972
17204
  if (step.when) {
16973
17205
  const shouldRun = await this.evaluateWhen(step.when);
16974
17206
  if (!shouldRun) {
@@ -16977,7 +17209,9 @@ var init_bridge_flow_runner = __esm({
16977
17209
  }
16978
17210
  }
16979
17211
  try {
16980
- const hasExplicitWait = !!(step.extendedWaitUntil || step.waitFor || step.scrollUntilVisible || step.launchApp || step.runFlow);
17212
+ const hasExplicitWait = !!(step.extendedWaitUntil || step.waitFor || step.scrollUntilVisible || step.launchApp || step.runFlow || // runScript http calls are synchronous with a 5-minute upstream
17213
+ // timeout — the 10s watchdog would kill legitimate setup scripts.
17214
+ step.runScript);
16981
17215
  const STEP_WATCHDOG_MS = 1e4;
16982
17216
  const body = this.runStepInner(step);
16983
17217
  if (hasExplicitWait) {
@@ -17073,7 +17307,11 @@ var init_bridge_flow_runner = __esm({
17073
17307
  } else if (typeof step.eraseText === "number") {
17074
17308
  await this.eraseText(step.eraseText);
17075
17309
  } else if (step.repeat) {
17076
- for (let i = 0; i < step.repeat.times; i++) {
17310
+ const times = Number(step.repeat.times);
17311
+ if (!Number.isFinite(times)) {
17312
+ throw new Error(`repeat.times is not a number: ${step.repeat.times}`);
17313
+ }
17314
+ for (let i = 0; i < times; i++) {
17077
17315
  for (let j = 0; j < step.repeat.commands.length; j++) {
17078
17316
  await this.runStep(step.repeat.commands[j], j);
17079
17317
  }
@@ -17087,26 +17325,59 @@ var init_bridge_flow_runner = __esm({
17087
17325
  } else if (step.copyTextFrom !== void 0) {
17088
17326
  await this.copyTextFrom(step.copyTextFrom);
17089
17327
  } else if (typeof step.evalScript === "string") {
17090
- await this.evalScript(step.evalScript);
17328
+ this.evalScript(step.evalScript);
17329
+ } else if (step.runScript) {
17330
+ const rs = step.runScript;
17331
+ const innerWhen = typeof rs === "string" ? void 0 : rs.when;
17332
+ if (innerWhen && !await this.evaluateWhen(innerWhen)) {
17333
+ console.log(`[flow] runScript skipped (when predicate false)`);
17334
+ return;
17335
+ }
17336
+ this.runScript(rs);
17091
17337
  } else if (step.openLink !== void 0) {
17092
17338
  await this.openLink(step.openLink);
17093
17339
  } else if (step.runFlow) {
17094
17340
  const rf = step.runFlow;
17095
17341
  const file = typeof rf === "string" ? rf : rf.file;
17342
+ const commands = typeof rf === "string" ? void 0 : rf.commands;
17343
+ const env = typeof rf === "string" ? void 0 : rf.env;
17096
17344
  const innerWhen = typeof rf === "string" ? void 0 : rf.when;
17097
17345
  if (innerWhen) {
17098
17346
  const shouldRun = await this.evaluateWhen(innerWhen);
17099
17347
  if (!shouldRun) {
17100
- console.log(`[flow] runFlow skipped (when predicate false): ${file}`);
17348
+ console.log(
17349
+ `[flow] runFlow skipped (when predicate false): ${file ?? "inline commands"}`
17350
+ );
17101
17351
  return;
17102
17352
  }
17103
17353
  }
17104
- const flowPath = path7.resolve(this.opts.flowDir, file);
17105
- const flowContent = fs7.readFileSync(flowPath, "utf8");
17106
- const previousDir = this.opts.flowDir;
17107
- this.opts.flowDir = path7.dirname(flowPath);
17108
- await this.runFlow(parseFlowSteps(flowContent));
17109
- this.opts.flowDir = previousDir;
17354
+ if (!file && !commands) {
17355
+ throw new Error("runFlow requires either file or commands");
17356
+ }
17357
+ this.js.enterEnvScope();
17358
+ try {
17359
+ if (env) {
17360
+ for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
17361
+ }
17362
+ if (file) {
17363
+ const flowPath = path7.resolve(this.opts.flowDir, file);
17364
+ const flowContent = fs7.readFileSync(flowPath, "utf8");
17365
+ const previousDir = this.opts.flowDir;
17366
+ this.opts.flowDir = path7.dirname(flowPath);
17367
+ try {
17368
+ await this.runFlow(parseFlowSteps(flowContent));
17369
+ } finally {
17370
+ ;
17371
+ this.opts.flowDir = previousDir;
17372
+ }
17373
+ } else if (commands) {
17374
+ for (let i = 0; i < commands.length; i++) {
17375
+ await this.runStep(commands[i], i);
17376
+ }
17377
+ }
17378
+ } finally {
17379
+ this.js.leaveEnvScope();
17380
+ }
17110
17381
  } else {
17111
17382
  throw new Error(`unsupported flow step: ${JSON.stringify(step)}`);
17112
17383
  }
@@ -17489,7 +17760,7 @@ var skill5 = {
17489
17760
  async execute(params, context) {
17490
17761
  const fs9 = await import("fs");
17491
17762
  const path9 = await import("path");
17492
- const yaml3 = await import("yaml");
17763
+ const yaml2 = await import("yaml");
17493
17764
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
17494
17765
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
17495
17766
  const { createBridge: createBridge2 } = await Promise.resolve().then(() => (init_ws_bridge(), ws_bridge_exports));
@@ -17500,7 +17771,7 @@ var skill5 = {
17500
17771
  const flowContent = fs9.readFileSync(params.flowPath, "utf8");
17501
17772
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
17502
17773
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
17503
- const steps = yaml3.parse(stepsBody);
17774
+ const steps = yaml2.parse(stepsBody);
17504
17775
  const beforeIds = new Set(host.listSims().map((sim) => sim.id));
17505
17776
  await host.openUrl(context.url);
17506
17777
  let simId = null;
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.140 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.141 | (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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sootsim",
3
- "version": "0.1.140",
3
+ "version": "0.1.141",
4
4
  "description": "sootsim CLI + vite/metro plugins + skills registry. bridge client for driving the proprietary sootsim-engine over WebSocket.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "MIT",
package/src/config.ts CHANGED
@@ -20,6 +20,15 @@ export interface SootSimConfig<
20
20
  turboModules?: Record<string, NativeModuleResolution>
21
21
  nativeModules?: Record<string, NativeModuleResolution>
22
22
  env?: Record<string, string>
23
+ // generic per-sim network rewrites for the guest app's runtime fetches.
24
+ // `remap` keys/values are `host:port` (or bare `host`) — a tenant fetch whose
25
+ // url matches a key has its host:port swapped for the value before the
26
+ // request is issued. exists for third-party e2e suites that hardcode a port
27
+ // (e.g. bluesky's flows type `http://localhost:3000`) which collides with a
28
+ // host service; map it to the real bound port without editing the app.
29
+ network?: {
30
+ remap?: Record<string, string>
31
+ }
23
32
  settings?: Partial<Settings>
24
33
  initialState?: {
25
34
  authenticated?: boolean
@@ -51,6 +60,7 @@ export function hasSootSimConfig<
51
60
  hasOwnKeys(config.turboModules as Record<string, unknown> | undefined) ||
52
61
  hasOwnKeys(config.nativeModules as Record<string, unknown> | undefined) ||
53
62
  hasOwnKeys(config.env as Record<string, unknown> | undefined) ||
63
+ hasOwnKeys(config.network?.remap as Record<string, unknown> | undefined) ||
54
64
  hasOwnKeys(config.settings as Record<string, unknown> | undefined) ||
55
65
  hasOwnKeys(config.initialState as Record<string, unknown> | undefined)
56
66
  )
@@ -74,6 +84,9 @@ export function mergeSootSimConfig<
74
84
  ...(override.nativeModules || {}),
75
85
  },
76
86
  env: { ...(base.env || {}), ...(override.env || {}) },
87
+ network: {
88
+ remap: { ...(base.network?.remap || {}), ...(override.network?.remap || {}) },
89
+ },
77
90
  settings: {
78
91
  ...(base.settings || {}),
79
92
  ...(override.settings || {}),
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.140 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d}from"./chunk-R5F7XGAO.js";import"./chunk-AOICEZCA.js";import"./chunk-RAY2DLSK.js";import"./chunk-QOZ2Q4FH.js";import"./chunk-GL74P6NR.js";import"./chunk-O2SQNUDP.js";export{c as ensureDaemonRunning,a as ensureRuntimeInstalled,d as ensureSootsimReady,b as resolveBootstrapPort};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.140 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c,d,e}from"./chunk-BGXNYXBC.js";import"./chunk-O2SQNUDP.js";export{e as BETA_ASK_HEADLINE,c as BETA_LABEL,d as BETA_TAGLINE,b as BETA_VERSION_TARGET,a as IS_BETA};