peachsim 0.1.636 → 0.1.638

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 (79) hide show
  1. package/README.md +8 -5
  2. package/cli/bridge-flow-runner.ts +442 -14
  3. package/cli/commands/inspect/core.ts +93 -24
  4. package/cli/commands/maestro.ts +2 -2
  5. package/cli/commands/serve.ts +13 -1
  6. package/cli/drivers/playwright-provisioning.ts +8 -16
  7. package/cli/drivers/playwright-sim-host.ts +3 -0
  8. package/cli/drivers/playwright.ts +1 -0
  9. package/cli/internal-child.ts +51 -8
  10. package/dist-lib/agent-daemon-client.cjs +1 -1
  11. package/dist-lib/agent-events.cjs +1 -1
  12. package/dist-lib/agent-identity.cjs +1 -1
  13. package/dist-lib/agent-sessions.cjs +1 -1
  14. package/dist-lib/attached-projects.cjs +1 -1
  15. package/dist-lib/auth/shared-session.cjs +1 -1
  16. package/dist-lib/backend-origin.cjs +1 -1
  17. package/dist-lib/beta.cjs +1 -1
  18. package/dist-lib/beta.mjs +1 -1
  19. package/dist-lib/bridge-constants.cjs +1 -1
  20. package/dist-lib/bridge-contract-input.cjs +3 -2
  21. package/dist-lib/bridge-contract-input.mjs +3 -2
  22. package/dist-lib/bridge-contract.cjs +1 -1
  23. package/dist-lib/bridge-contract.mjs +1 -1
  24. package/dist-lib/capture-contract.cjs +1 -1
  25. package/dist-lib/capture-contract.mjs +1 -1
  26. package/dist-lib/cli-constants.cjs +1 -1
  27. package/dist-lib/cloud-contract.cjs +1 -1
  28. package/dist-lib/cloud-contract.mjs +1 -1
  29. package/dist-lib/cloud-test-args.cjs +1 -1
  30. package/dist-lib/cloud-test-args.mjs +1 -1
  31. package/dist-lib/cloud.cjs +1 -1
  32. package/dist-lib/cloud.mjs +1 -1
  33. package/dist-lib/config.cjs +1 -1
  34. package/dist-lib/detox/index.cjs +1 -1
  35. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  36. package/dist-lib/home-paths.cjs +1 -1
  37. package/dist-lib/host/bridge-host.cjs +4 -2
  38. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  39. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  40. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  41. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  42. package/dist-lib/host/websocket-proxy.cjs +1 -1
  43. package/dist-lib/index.cjs +76 -20
  44. package/dist-lib/jump-to-source-babel.cjs +1 -1
  45. package/dist-lib/jump-to-source-native.cjs +1 -1
  46. package/dist-lib/kotlin-host.cjs +1 -1
  47. package/dist-lib/menu.cjs +1 -1
  48. package/dist-lib/menu.mjs +1 -1
  49. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  50. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  51. package/dist-lib/metro-production-bundle.cjs +1 -1
  52. package/dist-lib/metro-production-bundle.mjs +1 -1
  53. package/dist-lib/metro.cjs +1 -1
  54. package/dist-lib/native-app-identity.cjs +1 -1
  55. package/dist-lib/native-app-identity.mjs +1 -1
  56. package/dist-lib/profiles.cjs +1 -1
  57. package/dist-lib/public-brand.cjs +1 -1
  58. package/dist-lib/react-native-host-modules.cjs +1 -1
  59. package/dist-lib/react-native-host-modules.mjs +1 -1
  60. package/dist-lib/render-mode.cjs +1 -1
  61. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  62. package/dist-lib/sdk.cjs +78 -20
  63. package/dist-lib/sdk.mjs +77 -20
  64. package/dist-lib/skills.cjs +394 -62
  65. package/dist-lib/swift-compile.cjs +89 -7
  66. package/dist-lib/swift-compile.mjs +89 -7
  67. package/dist-lib/swift-package.cjs +1 -1
  68. package/dist-lib/swift-package.mjs +1 -1
  69. package/dist-lib/swift-submit.cjs +1 -1
  70. package/dist-lib/swift-submit.mjs +1 -1
  71. package/dist-lib/swift.cjs +122 -34
  72. package/dist-lib/vite-swift.cjs +89 -7
  73. package/dist-lib/vite.cjs +1 -1
  74. package/package.json +1 -1
  75. package/src/bridge-contract-input.ts +3 -2
  76. package/src/bridge-contract.ts +8 -0
  77. package/src/host/bridge-host.ts +5 -5
  78. package/src/native-seam-manifest.ts +4 -6
  79. package/src/swift-compile.ts +105 -9
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (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;
@@ -321,7 +321,7 @@ var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"'
321
321
  var MULTI_MANIFEST_VERSION = 5;
322
322
  function swiftArtifactHash(input, release, moduleRoot) {
323
323
  const hash = (0, import_node_crypto2.createHash)("sha256");
324
- hash.update(`swift-compile/v2
324
+ hash.update(`swift-compile/v3
325
325
  ${release}
326
326
  `);
327
327
  if (input.oneModule) hash.update("one-module\n");
@@ -421,13 +421,95 @@ function syncSwiftTree(base, files) {
421
421
  (0, import_node_fs2.writeFileSync)(full, contents, "utf8");
422
422
  }
423
423
  }
424
- var CONDITION_LINE = /^([ \t]*#(?:if|elseif)\b)(.*)$/gm;
424
+ var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
425
425
  var OS_IOS = /\bos\(\s*iOS\s*\)/g;
426
426
  function swiftSourceAsIOS(source) {
427
- return source.replace(
428
- CONDITION_LINE,
429
- (_, directive, condition) => directive + condition.replace(OS_IOS, (match) => "true".padEnd(match.length))
430
- );
427
+ const code = swiftCodeLineStarts(source);
428
+ let offset = 0;
429
+ return source.split("\n").map((line) => {
430
+ const start = offset;
431
+ offset += line.length + 1;
432
+ if (!code.has(start) || !DIRECTIVE.test(line)) return line;
433
+ return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
434
+ }).join("\n");
435
+ }
436
+ function swiftCodeLineStarts(source) {
437
+ const starts = /* @__PURE__ */ new Set();
438
+ const stack = [{ kind: "code", parens: 0 }];
439
+ const hashesAt = (at) => {
440
+ let end = at;
441
+ while (source[end] === "#") end++;
442
+ return end - at;
443
+ };
444
+ const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
445
+ let i = 0;
446
+ while (i < source.length) {
447
+ const top = stack[stack.length - 1];
448
+ if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
449
+ starts.add(i);
450
+ const char = source[i];
451
+ if (top.kind === "block") {
452
+ if (source.startsWith("/*", i)) {
453
+ top.depth++;
454
+ i += 2;
455
+ } else if (source.startsWith("*/", i)) {
456
+ if (--top.depth === 0) stack.pop();
457
+ i += 2;
458
+ } else i++;
459
+ continue;
460
+ }
461
+ if (top.kind === "string") {
462
+ if (char === "\\" && closes(i + 1, top.hashes)) {
463
+ const after = i + 1 + top.hashes;
464
+ if (source[after] === "(") {
465
+ stack.push({ kind: "code", parens: 0 });
466
+ i = after + 1;
467
+ } else i = after + 1;
468
+ continue;
469
+ }
470
+ const quote = top.multiline ? '"""' : '"';
471
+ if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
472
+ stack.pop();
473
+ i += quote.length + top.hashes;
474
+ } else i++;
475
+ continue;
476
+ }
477
+ if (top.kind === "regex") {
478
+ if (char === "/" && closes(i + 1, top.hashes)) {
479
+ stack.pop();
480
+ i += 1 + top.hashes;
481
+ } else i++;
482
+ continue;
483
+ }
484
+ if (source.startsWith("//", i)) {
485
+ const end = source.indexOf("\n", i);
486
+ i = end === -1 ? source.length : end;
487
+ } else if (source.startsWith("/*", i)) {
488
+ stack.push({ kind: "block", depth: 1 });
489
+ i += 2;
490
+ } else if (char === '"' || char === "#") {
491
+ const hashes = hashesAt(i);
492
+ const at = i + hashes;
493
+ if (source.startsWith('"""', at)) {
494
+ stack.push({ kind: "string", hashes, multiline: true });
495
+ i = at + 3;
496
+ } else if (source[at] === '"') {
497
+ stack.push({ kind: "string", hashes, multiline: false });
498
+ i = at + 1;
499
+ } else if (hashes > 0 && source[at] === "/") {
500
+ stack.push({ kind: "regex", hashes });
501
+ i = at + 1;
502
+ } else i = Math.max(at, i + 1);
503
+ } else if (char === "(") {
504
+ top.parens++;
505
+ i++;
506
+ } else if (char === ")") {
507
+ if (top.parens === 0 && stack.length > 1) stack.pop();
508
+ else top.parens--;
509
+ i++;
510
+ } else i++;
511
+ }
512
+ return starts;
431
513
  }
432
514
  var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
433
515
  function writeSwiftProject(layout, input, moduleRoot) {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/swift-compile.ts
4
4
  import { execFile as execFile2 } from "node:child_process";
@@ -286,7 +286,7 @@ var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"'
286
286
  var MULTI_MANIFEST_VERSION = 5;
287
287
  function swiftArtifactHash(input, release, moduleRoot) {
288
288
  const hash = createHash2("sha256");
289
- hash.update(`swift-compile/v2
289
+ hash.update(`swift-compile/v3
290
290
  ${release}
291
291
  `);
292
292
  if (input.oneModule) hash.update("one-module\n");
@@ -386,13 +386,95 @@ function syncSwiftTree(base, files) {
386
386
  writeFileSync(full, contents, "utf8");
387
387
  }
388
388
  }
389
- var CONDITION_LINE = /^([ \t]*#(?:if|elseif)\b)(.*)$/gm;
389
+ var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
390
390
  var OS_IOS = /\bos\(\s*iOS\s*\)/g;
391
391
  function swiftSourceAsIOS(source) {
392
- return source.replace(
393
- CONDITION_LINE,
394
- (_, directive, condition) => directive + condition.replace(OS_IOS, (match) => "true".padEnd(match.length))
395
- );
392
+ const code = swiftCodeLineStarts(source);
393
+ let offset = 0;
394
+ return source.split("\n").map((line) => {
395
+ const start = offset;
396
+ offset += line.length + 1;
397
+ if (!code.has(start) || !DIRECTIVE.test(line)) return line;
398
+ return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
399
+ }).join("\n");
400
+ }
401
+ function swiftCodeLineStarts(source) {
402
+ const starts = /* @__PURE__ */ new Set();
403
+ const stack = [{ kind: "code", parens: 0 }];
404
+ const hashesAt = (at) => {
405
+ let end = at;
406
+ while (source[end] === "#") end++;
407
+ return end - at;
408
+ };
409
+ const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
410
+ let i = 0;
411
+ while (i < source.length) {
412
+ const top = stack[stack.length - 1];
413
+ if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
414
+ starts.add(i);
415
+ const char = source[i];
416
+ if (top.kind === "block") {
417
+ if (source.startsWith("/*", i)) {
418
+ top.depth++;
419
+ i += 2;
420
+ } else if (source.startsWith("*/", i)) {
421
+ if (--top.depth === 0) stack.pop();
422
+ i += 2;
423
+ } else i++;
424
+ continue;
425
+ }
426
+ if (top.kind === "string") {
427
+ if (char === "\\" && closes(i + 1, top.hashes)) {
428
+ const after = i + 1 + top.hashes;
429
+ if (source[after] === "(") {
430
+ stack.push({ kind: "code", parens: 0 });
431
+ i = after + 1;
432
+ } else i = after + 1;
433
+ continue;
434
+ }
435
+ const quote = top.multiline ? '"""' : '"';
436
+ if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
437
+ stack.pop();
438
+ i += quote.length + top.hashes;
439
+ } else i++;
440
+ continue;
441
+ }
442
+ if (top.kind === "regex") {
443
+ if (char === "/" && closes(i + 1, top.hashes)) {
444
+ stack.pop();
445
+ i += 1 + top.hashes;
446
+ } else i++;
447
+ continue;
448
+ }
449
+ if (source.startsWith("//", i)) {
450
+ const end = source.indexOf("\n", i);
451
+ i = end === -1 ? source.length : end;
452
+ } else if (source.startsWith("/*", i)) {
453
+ stack.push({ kind: "block", depth: 1 });
454
+ i += 2;
455
+ } else if (char === '"' || char === "#") {
456
+ const hashes = hashesAt(i);
457
+ const at = i + hashes;
458
+ if (source.startsWith('"""', at)) {
459
+ stack.push({ kind: "string", hashes, multiline: true });
460
+ i = at + 3;
461
+ } else if (source[at] === '"') {
462
+ stack.push({ kind: "string", hashes, multiline: false });
463
+ i = at + 1;
464
+ } else if (hashes > 0 && source[at] === "/") {
465
+ stack.push({ kind: "regex", hashes });
466
+ i = at + 1;
467
+ } else i = Math.max(at, i + 1);
468
+ } else if (char === "(") {
469
+ top.parens++;
470
+ i++;
471
+ } else if (char === ")") {
472
+ if (top.parens === 0 && stack.length > 1) stack.pop();
473
+ else top.parens--;
474
+ i++;
475
+ } else i++;
476
+ }
477
+ return starts;
396
478
  }
397
479
  var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
398
480
  function writeSwiftProject(layout, input, moduleRoot) {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/swift-package.ts
4
4
  function isSwiftManifestFile(file) {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/swift-submit.ts
4
4
  var SWIFT_COMPILE_PATH = "/api/swift-compile";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (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;
@@ -7756,6 +7756,82 @@ function markPreviewShareProxyUrl(proxyUrl, previewShareId) {
7756
7756
  return `${proxyUrl}${proxyUrl.includes("?") ? "&" : "?"}shareId=${encodeURIComponent(shareId)}`;
7757
7757
  }
7758
7758
 
7759
+ // ../peach-engine/src/engine/text-content.ts
7760
+ function collectTextContent(node) {
7761
+ let text = "";
7762
+ for (const child of node.children) {
7763
+ if (!("children" in child)) {
7764
+ text += child.text;
7765
+ } else if (child.type === "text" || child.children.length > 0) {
7766
+ text += collectTextContent(child);
7767
+ }
7768
+ }
7769
+ if (node.textContent) text += node.textContent;
7770
+ return text;
7771
+ }
7772
+ function getYogaMeasureTextContent(node) {
7773
+ if (node.type === "text") {
7774
+ const content = collectTextContent(node);
7775
+ if (content) return content;
7776
+ const parent = node.parent;
7777
+ if (!parent || !(parent.props._isTextInput || parent.props.onChangeText)) return "";
7778
+ const placeholder = parent.props.placeholder;
7779
+ return typeof placeholder === "string" && placeholder.length > 0 ? placeholder : "I";
7780
+ }
7781
+ return node.textContent && node.children.length === 0 ? node.textContent : "";
7782
+ }
7783
+
7784
+ // ../peach-engine/src/engine/native-resources.ts
7785
+ var NativeTextDataPending = class extends Error {
7786
+ constructor(ready) {
7787
+ super("Native text data is loading");
7788
+ this.ready = ready;
7789
+ }
7790
+ code = "PEACH_TEXT_DATA_PENDING";
7791
+ };
7792
+ var contexts = /* @__PURE__ */ new WeakMap();
7793
+ function contextFor(canvasKit) {
7794
+ const context = contexts.get(canvasKit);
7795
+ if (!context) throw new Error("Native context has no resource suppliers");
7796
+ return context;
7797
+ }
7798
+ function ensureTextData(canvasKit) {
7799
+ const context = contextFor(canvasKit);
7800
+ context.textLoading ??= Promise.resolve().then(context.suppliers.textData).then((buffer) => {
7801
+ const bytes = new Uint8Array(buffer);
7802
+ const pointer = canvasKit._malloc(bytes.byteLength);
7803
+ if (!pointer) throw new Error("Native text data allocation failed");
7804
+ try {
7805
+ canvasKit.HEAPU8.set(bytes, pointer);
7806
+ const status = canvasKit._peach_text_data_register(pointer, bytes.byteLength);
7807
+ if (status !== 0 || !canvasKit._peach_text_data_ready())
7808
+ throw new Error(`Native text data registration failed: ${status}`);
7809
+ } finally {
7810
+ canvasKit._free(pointer);
7811
+ }
7812
+ }).catch((error) => {
7813
+ context.textError = error instanceof Error ? error : new Error(String(error));
7814
+ throw context.textError;
7815
+ });
7816
+ return context.textLoading;
7817
+ }
7818
+ function checkTextStatus(status) {
7819
+ if (status === 0) return false;
7820
+ if (status === 2) return true;
7821
+ throw new Error(`Native text preflight failed: ${status}`);
7822
+ }
7823
+ function pendingTextDataForText(canvasKit, text) {
7824
+ if (canvasKit._peach_text_data_ready()) return null;
7825
+ if (!checkTextStatus(canvasKit._peachTextStatus(text))) return null;
7826
+ const context = contextFor(canvasKit);
7827
+ if (context.textError) throw context.textError;
7828
+ return ensureTextData(canvasKit);
7829
+ }
7830
+ function readTextDataForText(canvasKit, text) {
7831
+ const pending = pendingTextDataForText(canvasKit, text);
7832
+ if (pending) throw pending;
7833
+ }
7834
+
7759
7835
  // ../peach-engine/src/engine/animated-style-schema.ts
7760
7836
  var ANIMATED_STYLE_PROPS = /* @__PURE__ */ new Set([
7761
7837
  // color props
@@ -12128,6 +12204,41 @@ var SootSimNode = class _SootSimNode {
12128
12204
  if (typeof fn !== "function") return false;
12129
12205
  return fn() === true;
12130
12206
  }
12207
+ _flushLayoutForMeasure(resume, onFail) {
12208
+ try {
12209
+ return this._flushPendingLayout();
12210
+ } catch (error) {
12211
+ if (!(error instanceof NativeTextDataPending)) throw error;
12212
+ let root = this;
12213
+ while (root.parent) root = root.parent;
12214
+ const flush = globalThis.__sootsimFlushLayoutSync;
12215
+ const auxFlush = globalThis.__sootsimFlushAuxLayoutSync;
12216
+ const stillAttached = () => {
12217
+ if (globalThis.__sootsimFlushLayoutSync !== flush || globalThis.__sootsimFlushAuxLayoutSync !== auxFlush)
12218
+ return false;
12219
+ let node = this;
12220
+ while (node.parent) {
12221
+ if (!node.parent.children.includes(node)) return false;
12222
+ node = node.parent;
12223
+ }
12224
+ return node === root;
12225
+ };
12226
+ void error.ready.then(
12227
+ () => {
12228
+ if (stillAttached()) resume();
12229
+ },
12230
+ (failure) => {
12231
+ if (!stillAttached()) return;
12232
+ if (onFail) onFail();
12233
+ else
12234
+ queueMicrotask(() => {
12235
+ throw failure;
12236
+ });
12237
+ }
12238
+ );
12239
+ return null;
12240
+ }
12241
+ }
12131
12242
  // helper — true if `this.layout` has been computed at least once (any
12132
12243
  // dimension is non-zero or there's a non-default x/y). a degenerate
12133
12244
  // {0,0,0,0} layout means yoga hasn't produced a result for this node
@@ -12138,7 +12249,8 @@ var SootSimNode = class _SootSimNode {
12138
12249
  }
12139
12250
  // RN .measure() stub for tamagui components
12140
12251
  measure(callback) {
12141
- const flushed = this._flushPendingLayout();
12252
+ const flushed = this._flushLayoutForMeasure(() => this.measure(callback));
12253
+ if (flushed === null) return;
12142
12254
  const hadComputedLayout = this._hasComputedLayout();
12143
12255
  if (!flushed && !hadComputedLayout) {
12144
12256
  recordTimelineEvent("layout", {
@@ -12175,7 +12287,8 @@ var SootSimNode = class _SootSimNode {
12175
12287
  callback(this.layout.x, this.layout.y, rect.width, rect.height, rect.x, rect.y);
12176
12288
  }
12177
12289
  measureInWindow(callback) {
12178
- const flushed = this._flushPendingLayout();
12290
+ const flushed = this._flushLayoutForMeasure(() => this.measureInWindow(callback));
12291
+ if (flushed === null) return;
12179
12292
  const hadComputedLayout = this._hasComputedLayout();
12180
12293
  if (!flushed && !hadComputedLayout) {
12181
12294
  recordTimelineEvent("layout", {
@@ -12212,7 +12325,11 @@ var SootSimNode = class _SootSimNode {
12212
12325
  onFail?.();
12213
12326
  return;
12214
12327
  }
12215
- const flushed = this._flushPendingLayout();
12328
+ const flushed = this._flushLayoutForMeasure(
12329
+ () => this.measureLayout(relativeToNativeNode, onSuccess, onFail),
12330
+ onFail
12331
+ );
12332
+ if (flushed === null) return;
12216
12333
  if (!flushed && !this._hasComputedLayout()) {
12217
12334
  onFail?.();
12218
12335
  return;
@@ -14873,7 +14990,6 @@ var GRAPHEME_SEGMENTER = (() => {
14873
14990
  var letter = new RegExp("^\\p{L}$", "u");
14874
14991
 
14875
14992
  // ../peach-engine/src/engine/yoga-layout.ts
14876
- var EMPTY_TEXT_INPUT_MEASURE_FALLBACK = "I";
14877
14993
  var _nodeMeasureCache = /* @__PURE__ */ new WeakMap();
14878
14994
  var _nodeConcatenatedText = /* @__PURE__ */ new WeakMap();
14879
14995
  var INCREMENTAL_YOGA_VERIFY_EPSILON = 1 / 1024;
@@ -14895,35 +15011,6 @@ function invalidateYogaTextMeasure(node) {
14895
15011
  }
14896
15012
  if (hadMeasureFunc) s.native.exports._peach_layout_mark_dirty(slot);
14897
15013
  }
14898
- function getTextInputMeasureFallback(node) {
14899
- const parent = node.parent;
14900
- if (!parent || !(parent.props?._isTextInput || parent.props?.onChangeText)) {
14901
- return "";
14902
- }
14903
- const placeholder = parent.props?.placeholder;
14904
- return typeof placeholder === "string" && placeholder.length > 0 ? placeholder : EMPTY_TEXT_INPUT_MEASURE_FALLBACK;
14905
- }
14906
- function getYogaMeasureTextContent(node) {
14907
- if (node.type === "text") {
14908
- const textContent = collectTextContent(node);
14909
- return textContent || getTextInputMeasureFallback(node);
14910
- }
14911
- return node.textContent && node.children.length === 0 ? node.textContent : "";
14912
- }
14913
- function collectTextContent(node) {
14914
- let text = "";
14915
- for (const child of node.children) {
14916
- if (child instanceof SootSimTextNode) {
14917
- text += child.text;
14918
- } else if (child instanceof SootSimNode) {
14919
- if (child.type === "text" || child.children.length > 0) {
14920
- text += collectTextContent(child);
14921
- }
14922
- }
14923
- }
14924
- if (node.textContent) text += node.textContent;
14925
- return text;
14926
- }
14927
15014
 
14928
15015
  // ../peach-engine/src/engine/text-host-mutations.ts
14929
15016
  function getHostTextContent(props) {
@@ -20287,6 +20374,7 @@ function measureSynchronousTextLayout(text, style, maxWidth) {
20287
20374
  if (!activeMeasureText || !context) {
20288
20375
  throw new Error("[sootsim] synchronous text measurement is unavailable");
20289
20376
  }
20377
+ readTextDataForText(context.canvasKit, text);
20290
20378
  const measured = activeMeasureText(text, style, maxWidth, context);
20291
20379
  return {
20292
20380
  width: measured.measuredWidth,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (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;
@@ -817,7 +817,7 @@ var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"'
817
817
  var MULTI_MANIFEST_VERSION = 5;
818
818
  function swiftArtifactHash(input, release, moduleRoot) {
819
819
  const hash = (0, import_node_crypto2.createHash)("sha256");
820
- hash.update(`swift-compile/v2
820
+ hash.update(`swift-compile/v3
821
821
  ${release}
822
822
  `);
823
823
  if (input.oneModule) hash.update("one-module\n");
@@ -917,13 +917,95 @@ function syncSwiftTree(base, files) {
917
917
  (0, import_node_fs3.writeFileSync)(full, contents, "utf8");
918
918
  }
919
919
  }
920
- var CONDITION_LINE = /^([ \t]*#(?:if|elseif)\b)(.*)$/gm;
920
+ var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
921
921
  var OS_IOS = /\bos\(\s*iOS\s*\)/g;
922
922
  function swiftSourceAsIOS(source) {
923
- return source.replace(
924
- CONDITION_LINE,
925
- (_, directive, condition) => directive + condition.replace(OS_IOS, (match) => "true".padEnd(match.length))
926
- );
923
+ const code = swiftCodeLineStarts(source);
924
+ let offset = 0;
925
+ return source.split("\n").map((line) => {
926
+ const start = offset;
927
+ offset += line.length + 1;
928
+ if (!code.has(start) || !DIRECTIVE.test(line)) return line;
929
+ return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
930
+ }).join("\n");
931
+ }
932
+ function swiftCodeLineStarts(source) {
933
+ const starts = /* @__PURE__ */ new Set();
934
+ const stack = [{ kind: "code", parens: 0 }];
935
+ const hashesAt = (at) => {
936
+ let end = at;
937
+ while (source[end] === "#") end++;
938
+ return end - at;
939
+ };
940
+ const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
941
+ let i = 0;
942
+ while (i < source.length) {
943
+ const top = stack[stack.length - 1];
944
+ if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
945
+ starts.add(i);
946
+ const char = source[i];
947
+ if (top.kind === "block") {
948
+ if (source.startsWith("/*", i)) {
949
+ top.depth++;
950
+ i += 2;
951
+ } else if (source.startsWith("*/", i)) {
952
+ if (--top.depth === 0) stack.pop();
953
+ i += 2;
954
+ } else i++;
955
+ continue;
956
+ }
957
+ if (top.kind === "string") {
958
+ if (char === "\\" && closes(i + 1, top.hashes)) {
959
+ const after = i + 1 + top.hashes;
960
+ if (source[after] === "(") {
961
+ stack.push({ kind: "code", parens: 0 });
962
+ i = after + 1;
963
+ } else i = after + 1;
964
+ continue;
965
+ }
966
+ const quote = top.multiline ? '"""' : '"';
967
+ if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
968
+ stack.pop();
969
+ i += quote.length + top.hashes;
970
+ } else i++;
971
+ continue;
972
+ }
973
+ if (top.kind === "regex") {
974
+ if (char === "/" && closes(i + 1, top.hashes)) {
975
+ stack.pop();
976
+ i += 1 + top.hashes;
977
+ } else i++;
978
+ continue;
979
+ }
980
+ if (source.startsWith("//", i)) {
981
+ const end = source.indexOf("\n", i);
982
+ i = end === -1 ? source.length : end;
983
+ } else if (source.startsWith("/*", i)) {
984
+ stack.push({ kind: "block", depth: 1 });
985
+ i += 2;
986
+ } else if (char === '"' || char === "#") {
987
+ const hashes = hashesAt(i);
988
+ const at = i + hashes;
989
+ if (source.startsWith('"""', at)) {
990
+ stack.push({ kind: "string", hashes, multiline: true });
991
+ i = at + 3;
992
+ } else if (source[at] === '"') {
993
+ stack.push({ kind: "string", hashes, multiline: false });
994
+ i = at + 1;
995
+ } else if (hashes > 0 && source[at] === "/") {
996
+ stack.push({ kind: "regex", hashes });
997
+ i = at + 1;
998
+ } else i = Math.max(at, i + 1);
999
+ } else if (char === "(") {
1000
+ top.parens++;
1001
+ i++;
1002
+ } else if (char === ")") {
1003
+ if (top.parens === 0 && stack.length > 1) stack.pop();
1004
+ else top.parens--;
1005
+ i++;
1006
+ } else i++;
1007
+ }
1008
+ return starts;
927
1009
  }
928
1010
  var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
929
1011
  function writeSwiftProject(layout, input, moduleRoot) {
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.636 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.638 | (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": "peachsim",
3
- "version": "0.1.636",
3
+ "version": "0.1.638",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for peach.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -1,4 +1,5 @@
1
1
  import { SIM_LONG_PRESS_MAX_MS } from './bridge-contract'
2
+ import { isRecord } from './is-record'
2
3
  // untrusted JSON -> bridge-contract argument. one owner for that conversion, so
3
4
  // every transport in front of a sim (the Peach Cloud sim service's HTTP and
4
5
  // WebSocket routes) validates its request bodies here rather than growing a
@@ -13,7 +14,6 @@ import type {
13
14
  } from './bridge-contract'
14
15
  import type { SimPerformStep, SimScreenshotOptions } from './sim-client'
15
16
  import type { SootSimReplayTarget } from '@peach/globals'
16
- import { isRecord } from './is-record'
17
17
 
18
18
  /** the caller sent a value this bridge argument cannot be read from. */
19
19
  export class BridgeInputError extends Error {
@@ -371,6 +371,7 @@ export function parseSemanticQuery(value: unknown): SimSemanticQuery {
371
371
  const query = recordValue(value, 'query')
372
372
  const kind = stringValue(query.kind, 'query.kind')
373
373
  if (kind === 'count') return { kind }
374
+ if (kind === 'accessibility') return { kind }
374
375
  if (kind === 'tree') {
375
376
  const depth = optionalNumber(query, 'depth', 'query')
376
377
  return { kind, ...(depth === undefined ? {} : { depth }) }
@@ -378,7 +379,7 @@ export function parseSemanticQuery(value: unknown): SimSemanticQuery {
378
379
  if (kind === 'find') {
379
380
  return { kind, selector: parseSemanticSelector(query.selector, 'query.selector') }
380
381
  }
381
- return validationFailure('query.kind', 'must be tree, find, or count')
382
+ return validationFailure('query.kind', 'must be tree, find, count, or accessibility')
382
383
  }
383
384
 
384
385
  function semanticResolveSelector(
@@ -9,6 +9,7 @@
9
9
  // this is the direction that ships.
10
10
 
11
11
  import type {
12
+ PeachAccessibilityNode,
12
13
  SootSimAgentActionDetail,
13
14
  SootSimCaptureFilter,
14
15
  SootSimExternalAppLifecycleOptions,
@@ -489,10 +490,17 @@ export type SimSemanticQuery =
489
490
  | { kind: 'tree'; depth?: number }
490
491
  | { kind: 'find'; selector: SimSemanticSelector }
491
492
  | { kind: 'count' }
493
+ // the XCTest accessibility projection. it is not a SimSemanticNode tree, so
494
+ // the snapshot rides in `accessibility` and `nodes` stays empty.
495
+ | { kind: 'accessibility' }
492
496
 
493
497
  export interface SimSemanticQueryResult {
494
498
  nodes: SimSemanticNode[]
495
499
  total: number
500
+ // present only for { kind: 'accessibility' }: the engine's recursive
501
+ // accessibility snapshot (PeachAccessibilityNode), the same tree the
502
+ // Maestro structural selectors resolve against.
503
+ accessibility?: PeachAccessibilityNode[]
496
504
  }
497
505
 
498
506
  export type SimSemanticResolveSelector = { testID: string } | { text: string }