peachsim 0.1.2206 → 0.1.2208

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 (109) hide show
  1. package/cli/bridge-diagnostics.ts +4 -4
  2. package/cli/bridge-flow-runner.ts +33 -33
  3. package/cli/browser-evals.ts +2 -2
  4. package/cli/commands/control.ts +1 -1
  5. package/cli/commands/cpu-profile.ts +5 -4
  6. package/cli/commands/debug.ts +3 -3
  7. package/cli/commands/diagnose.ts +2 -2
  8. package/cli/commands/flow.ts +7 -7
  9. package/cli/commands/inspect/core.ts +22 -22
  10. package/cli/commands/inspect/get-node.ts +2 -2
  11. package/cli/commands/inspect/shared.ts +2 -2
  12. package/cli/commands/inspect/wait-event.ts +1 -1
  13. package/cli/commands/inspect.ts +33 -33
  14. package/cli/commands/record-three.ts +17 -17
  15. package/cli/commands/record.ts +44 -40
  16. package/cli/commands/shell-boolean-mode.ts +1 -1
  17. package/cli/commands/slides.ts +5 -3
  18. package/cli/commands/three-mode.ts +3 -3
  19. package/cli/commands/upload.ts +8 -8
  20. package/cli/drivers/types.ts +1 -1
  21. package/cli/runtime-diagnostics.ts +2 -2
  22. package/cli/scene-video.ts +5 -3
  23. package/cli/send-to-box.ts +1 -1
  24. package/cli/ws-bridge.ts +3 -3
  25. package/dist-lib/agent-daemon-client.cjs +1 -1
  26. package/dist-lib/agent-events.cjs +1 -1
  27. package/dist-lib/attached-projects.cjs +1 -1
  28. package/dist-lib/auth/shared-session.cjs +1 -1
  29. package/dist-lib/backend-origin.cjs +1 -1
  30. package/dist-lib/beta.cjs +1 -1
  31. package/dist-lib/beta.mjs +1 -1
  32. package/dist-lib/bridge-constants.cjs +1 -1
  33. package/dist-lib/bridge-contract-input.cjs +1 -1
  34. package/dist-lib/bridge-contract-input.mjs +1 -1
  35. package/dist-lib/bridge-contract.cjs +1 -1
  36. package/dist-lib/bridge-contract.mjs +1 -1
  37. package/dist-lib/bundle-channel.cjs +6 -6
  38. package/dist-lib/capture-contract.cjs +1 -1
  39. package/dist-lib/capture-contract.mjs +1 -1
  40. package/dist-lib/cloud-contract.cjs +1 -1
  41. package/dist-lib/cloud-contract.mjs +1 -1
  42. package/dist-lib/cloud-test-args.cjs +1 -1
  43. package/dist-lib/cloud-test-args.mjs +1 -1
  44. package/dist-lib/cloud.cjs +1 -1
  45. package/dist-lib/cloud.mjs +1 -1
  46. package/dist-lib/config.cjs +1 -1
  47. package/dist-lib/config.mjs +1 -1
  48. package/dist-lib/detox/index.cjs +4 -4
  49. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  50. package/dist-lib/expo-swift-bundle.cjs +4 -4
  51. package/dist-lib/expo-swift-metadata.cjs +1 -1
  52. package/dist-lib/expo-swift-metadata.mjs +1 -1
  53. package/dist-lib/home-paths.cjs +1 -1
  54. package/dist-lib/host/bridge-host.cjs +7 -7
  55. package/dist-lib/host/fetch-proxy-handler.cjs +4 -4
  56. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  57. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  58. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  59. package/dist-lib/host/websocket-proxy.cjs +1 -1
  60. package/dist-lib/index.cjs +10 -10
  61. package/dist-lib/jump-to-source-babel.cjs +1 -1
  62. package/dist-lib/jump-to-source-native.cjs +1 -1
  63. package/dist-lib/kotlin-host.cjs +1 -1
  64. package/dist-lib/menu.cjs +1 -1
  65. package/dist-lib/menu.mjs +1 -1
  66. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  67. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  68. package/dist-lib/metro-production-bundle.cjs +1 -1
  69. package/dist-lib/metro-production-bundle.mjs +1 -1
  70. package/dist-lib/metro.cjs +4 -4
  71. package/dist-lib/native-app-identity-project.cjs +2 -2
  72. package/dist-lib/native-app-identity-project.mjs +2 -2
  73. package/dist-lib/native-app-identity.cjs +1 -1
  74. package/dist-lib/native-app-identity.mjs +1 -1
  75. package/dist-lib/native-firebase-metadata.cjs +1 -1
  76. package/dist-lib/native-firebase-metadata.mjs +1 -1
  77. package/dist-lib/pdfium-raster.cjs +1 -1
  78. package/dist-lib/pdfium-raster.mjs +1 -1
  79. package/dist-lib/plist.cjs +1 -1
  80. package/dist-lib/plist.mjs +1 -1
  81. package/dist-lib/profiles.cjs +1 -1
  82. package/dist-lib/public-brand.cjs +1 -1
  83. package/dist-lib/public-origins-lib-esm.json +24 -24
  84. package/dist-lib/public-origins-lib.json +53 -53
  85. package/dist-lib/react-native-host-modules.cjs +1 -1
  86. package/dist-lib/react-native-host-modules.mjs +1 -1
  87. package/dist-lib/reap-browser.cjs +1 -1
  88. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  89. package/dist-lib/sdk.cjs +23 -23
  90. package/dist-lib/sdk.mjs +23 -23
  91. package/dist-lib/skills.cjs +55 -55
  92. package/dist-lib/swift-compile.cjs +2 -2
  93. package/dist-lib/swift-compile.mjs +2 -2
  94. package/dist-lib/swift-package.cjs +1 -1
  95. package/dist-lib/swift-package.mjs +1 -1
  96. package/dist-lib/swift-submit.cjs +1 -1
  97. package/dist-lib/swift-submit.mjs +1 -1
  98. package/dist-lib/swift-toolchain.cjs +1 -1
  99. package/dist-lib/swift.cjs +1 -1
  100. package/dist-lib/vite-swift.cjs +3 -3
  101. package/dist-lib/vite.cjs +4 -4
  102. package/dist-lib/worklet-executable.cjs +1 -1
  103. package/dist-lib/worklet-executable.mjs +1 -1
  104. package/dist-types/packages/peach-engine/src/engine/image-loader.d.ts +1 -1
  105. package/dist-types/packages/peach-engine/src/engine/node.d.ts +3 -0
  106. package/dist-types/packages/peach-engine/src/settings/store.d.ts +1 -0
  107. package/package.json +1 -1
  108. package/runtime-companion.json +1 -1
  109. package/sdk/ios/System/Library/Frameworks/Foundation.framework/Headers/Foundation.apinotes +0 -8
@@ -150,8 +150,8 @@ export async function printBridgeStateSummary(bridge: WsBridge) {
150
150
  const state = (await bridge.send({
151
151
  type: 'evaluate',
152
152
  code: `(async () => {
153
- const test = window.__sootsimTest
154
- const mainShell = window.SootSim?.bridges?.mainShell
153
+ const test = globalThis.__sootsimTest
154
+ const mainShell = globalThis.SootSim?.bridges?.mainShell
155
155
  let shell = null
156
156
  try {
157
157
  shell = typeof mainShell?.getState === 'function' ? await mainShell.getState() : null
@@ -162,9 +162,9 @@ export async function printBridgeStateSummary(bridge: WsBridge) {
162
162
  } catch {}
163
163
  return {
164
164
  url: window.location.href,
165
- simId: window.__sootsimSimId || null,
165
+ simId: globalThis.__sootsimSimId || null,
166
166
  nodeCount,
167
- mode: window.__sootsimRenderHost ? 'render-worker' : 'main-thread',
167
+ mode: globalThis.__sootsimRenderHost ? 'render-worker' : 'main-thread',
168
168
  shell: shell
169
169
  ? {
170
170
  state: shell.state || null,
@@ -523,7 +523,7 @@ type FocusedTextInputInfo = {
523
523
  }
524
524
  type ShellState = Record<string, unknown>
525
525
 
526
- // shape of window.__sootsimShellPerf.stop() — the shell worker frame profile
526
+ // shape of globalThis.__sootsimShellPerf.stop() — the shell worker frame profile
527
527
  // (the worker that paints app pixels) merged with the render-profile counters.
528
528
  // see sootsim-engine shell-worker.ts stopShellFrameProfile.
529
529
  export interface SootSimFlowProfileResult {
@@ -1291,7 +1291,7 @@ export class SootSimBridgeFlowRunner {
1291
1291
  format?: string
1292
1292
  startedAtMs?: number
1293
1293
  }>(`(() => {
1294
- const rec = window.__sootsimRecorder
1294
+ const rec = globalThis.__sootsimRecorder
1295
1295
  if (!rec) return { ok: false, error: 'recorder unavailable on this page' }
1296
1296
  const format = ${JSON.stringify(this.opts.recordingFormat ?? 'webm')}
1297
1297
  if (rec.state() === 'recording') return { ok: true, format }
@@ -1312,12 +1312,12 @@ export class SootSimBridgeFlowRunner {
1312
1312
  // stops the recorder and leaves no half-started state to skip past.
1313
1313
  try {
1314
1314
  await this.evaluate(`(() => {
1315
- const recorder = window.SootSim?.bridges?.eventRecorder ?? window.__sootsimEventRecorder
1315
+ const recorder = globalThis.SootSim?.bridges?.eventRecorder ?? globalThis.__sootsimEventRecorder
1316
1316
  if (!recorder?.isRecording?.()) return
1317
1317
  return recorder.markVisibleStart(${JSON.stringify(startedAtMs)})
1318
1318
  })()`)
1319
1319
  } catch (error) {
1320
- await this.evaluate(`window.__sootsimRecorder.stop()`).catch(() => {})
1320
+ await this.evaluate(`globalThis.__sootsimRecorder.stop()`).catch(() => {})
1321
1321
  throw error
1322
1322
  }
1323
1323
  this.recordingStartedAtMs = startedAtMs
@@ -1432,7 +1432,7 @@ export class SootSimBridgeFlowRunner {
1432
1432
  mime?: string
1433
1433
  durationMs: number
1434
1434
  profile?: ProfileFile | null
1435
- }>(`window.__sootsimRecorder.stop()`)
1435
+ }>(`globalThis.__sootsimRecorder.stop()`)
1436
1436
  if (!stopped?.ok) {
1437
1437
  this.recordingStartedAtMs = null
1438
1438
  this.lastRecordingProfile = null
@@ -1457,7 +1457,7 @@ export class SootSimBridgeFlowRunner {
1457
1457
  done: boolean
1458
1458
  mime: string
1459
1459
  } | null>(
1460
- `window.__sootsimRecorder.getBlobBase64({ offset: ${offset}, chunk: ${
1460
+ `globalThis.__sootsimRecorder.getBlobBase64({ offset: ${offset}, chunk: ${
1461
1461
  2 * 1024 * 1024
1462
1462
  } })`,
1463
1463
  )
@@ -1517,7 +1517,7 @@ export class SootSimBridgeFlowRunner {
1517
1517
 
1518
1518
  private async captureAccessibilityTree(): Promise<PeachAccessibilityNode[]> {
1519
1519
  const tree = await this.evaluate(`(async () => {
1520
- const test = window.__sootsimTest
1520
+ const test = globalThis.__sootsimTest
1521
1521
  if (!test || typeof test.captureAccessibilityTree !== 'function') throw new Error('engine accessibility snapshot is unavailable')
1522
1522
  return await test.captureAccessibilityTree()
1523
1523
  })()`)
@@ -1593,7 +1593,7 @@ export class SootSimBridgeFlowRunner {
1593
1593
  private async findElementScoped(opts: FlowTargetSelector, preferHittable = false) {
1594
1594
  const screen = await this.screenBounds()
1595
1595
  const candidates = await this.evaluate<any[]>(`(async () => {
1596
- const test = window.__sootsimTest
1596
+ const test = globalThis.__sootsimTest
1597
1597
  if (!test || !test.queryAll) return null
1598
1598
  const selector = ${JSON.stringify(opts)}
1599
1599
  const compile = ${accessibilityTextMatcher.toString()}
@@ -1774,7 +1774,7 @@ export class SootSimBridgeFlowRunner {
1774
1774
  if (candidates.length < 2) return candidates[0] ?? null
1775
1775
  const nodeIds = candidates.map((node) => node.nodeId)
1776
1776
  const index = await this.evaluate<number>(`(async () => {
1777
- const test = window.__sootsimTest
1777
+ const test = globalThis.__sootsimTest
1778
1778
  for (const [index, nodeId] of ${JSON.stringify(nodeIds)}.entries()) {
1779
1779
  if (typeof nodeId !== 'number') continue
1780
1780
  const resolved = await test.resolveTapTarget(nodeId)
@@ -1791,7 +1791,7 @@ export class SootSimBridgeFlowRunner {
1791
1791
 
1792
1792
  private async resolveTapTarget(nodeId: number) {
1793
1793
  return this.evaluate<any>(`(async () => {
1794
- const test = window.__sootsimTest
1794
+ const test = globalThis.__sootsimTest
1795
1795
  if (!test?.resolveTapTarget) return null
1796
1796
  return await test.resolveTapTarget(${nodeId})
1797
1797
  })()`)
@@ -1807,7 +1807,7 @@ export class SootSimBridgeFlowRunner {
1807
1807
  ? { id: opts.id, testID: opts.id, text: null }
1808
1808
  : { id: null, testID: null, text: opts.text ?? null }
1809
1809
  return this.evaluate<any>(`(async () => {
1810
- const test = window.__sootsimTest
1810
+ const test = globalThis.__sootsimTest
1811
1811
  if (!test) return null
1812
1812
  let point = { x: ${x}, y: ${y} }
1813
1813
  const resolved = await test.resolveTapTarget(${nodeId})
@@ -1830,7 +1830,7 @@ export class SootSimBridgeFlowRunner {
1830
1830
 
1831
1831
  private async activatePressAt(x: number, y: number) {
1832
1832
  return this.evaluate<any>(`(async () => {
1833
- const test = window.__sootsimTest
1833
+ const test = globalThis.__sootsimTest
1834
1834
  if (!test?.activatePressAt) return null
1835
1835
  const direct = await test.activatePressAt(${x}, ${y})
1836
1836
  if (direct?.ok) {
@@ -1878,7 +1878,7 @@ export class SootSimBridgeFlowRunner {
1878
1878
  // which no tree, layout, scroll or prop write could move any element.
1879
1879
  private async geometryRevision(): Promise<string | null> {
1880
1880
  const revision = await this.evaluate(
1881
- `(async () => window.__sootsimTest?.getGeometryRevision?.())()`,
1881
+ `(async () => globalThis.__sootsimTest?.getGeometryRevision?.())()`,
1882
1882
  )
1883
1883
  return typeof revision === 'string' ? revision : null
1884
1884
  }
@@ -2345,7 +2345,7 @@ export class SootSimBridgeFlowRunner {
2345
2345
  private async isKeyboardVisible(): Promise<boolean> {
2346
2346
  const visible = await this.evaluate<boolean>(`(() => {
2347
2347
  const keyboard =
2348
- window.__sootsimKeyboard ?? window.SootSim?.bridges?.keyboard ?? null
2348
+ globalThis.__sootsimKeyboard ?? globalThis.SootSim?.bridges?.keyboard ?? null
2349
2349
  return !!keyboard?.isVisible?.()
2350
2350
  })()`)
2351
2351
  return visible === true
@@ -2480,11 +2480,11 @@ export class SootSimBridgeFlowRunner {
2480
2480
  type: 'evaluate',
2481
2481
  simId: this.opts.simId,
2482
2482
  code: `(() => {
2483
- const c = window.__sootsimConsole
2483
+ const c = globalThis.__sootsimConsole
2484
2484
  return {
2485
2485
  errors: c?.getErrors?.() ?? [],
2486
2486
  warnings: c?.getWarnings?.() ?? [],
2487
- requests: (window.__sootsimGetFailedRequests?.() ?? []),
2487
+ requests: (globalThis.__sootsimGetFailedRequests?.() ?? []),
2488
2488
  }
2489
2489
  })()`,
2490
2490
  })) as SootSimFlowConsole
@@ -2542,7 +2542,7 @@ export class SootSimBridgeFlowRunner {
2542
2542
  manifest?: unknown
2543
2543
  }>(`(async () => {
2544
2544
  const out = {
2545
- simId: window.__sootsimBridge?.id ?? window.SootSim?.state?.simId ?? null,
2545
+ simId: globalThis.__sootsimBridge?.id ?? globalThis.SootSim?.state?.simId ?? null,
2546
2546
  url: location.href,
2547
2547
  title: document.title,
2548
2548
  hidden: document.hidden,
@@ -2596,8 +2596,8 @@ export class SootSimBridgeFlowRunner {
2596
2596
  // full layout, style, a11y, transforms. the `--json` describe output
2597
2597
  // shape; inlined here so we don't depend on the cli reentering.
2598
2598
  const describeJson = await safeEval<any>(`(async () => {
2599
- const t = window.__sootsimTest
2600
- const mainShell = window.SootSim?.bridges?.mainShell
2599
+ const t = globalThis.__sootsimTest
2600
+ const mainShell = globalThis.SootSim?.bridges?.mainShell
2601
2601
  if (!t) return { error: 'no test bridge' }
2602
2602
  let shell = null
2603
2603
  try {
@@ -2610,19 +2610,19 @@ export class SootSimBridgeFlowRunner {
2610
2610
 
2611
2611
  // every animation the settle check can name, with its kind, priority and visibility
2612
2612
  const animations = await safeEval<unknown>(
2613
- `(async () => await window.__sootsimTest?.listAnimations?.())()`,
2613
+ `(async () => await globalThis.__sootsimTest?.listAnimations?.())()`,
2614
2614
  )
2615
2615
  if (animations) write('animations.json', JSON.stringify(animations, null, 2))
2616
2616
 
2617
2617
  // 4. accessibility tree (flat text — what voiceover would read)
2618
2618
  const a11y = await safeEval<string>(
2619
- `(async () => await window.__sootsimTest?.dumpAccessibilityTree?.(20))()`,
2619
+ `(async () => await globalThis.__sootsimTest?.dumpAccessibilityTree?.(20))()`,
2620
2620
  )
2621
2621
  if (typeof a11y === 'string') write('a11y.txt', a11y)
2622
2622
 
2623
2623
  // 5. tree dump (nested — useful for layout bugs)
2624
2624
  const tree = await safeEval<string>(
2625
- `(async () => await window.__sootsimTest?.dumpTree?.(15))()`,
2625
+ `(async () => await globalThis.__sootsimTest?.dumpTree?.(15))()`,
2626
2626
  )
2627
2627
  if (typeof tree === 'string') write('tree.txt', tree)
2628
2628
 
@@ -2816,14 +2816,14 @@ export class SootSimBridgeFlowRunner {
2816
2816
  frameIndex?: number
2817
2817
  }>(
2818
2818
  `(async () => {
2819
- const lockstep = window.SootSim?.bridges?.lockstepCapture
2819
+ const lockstep = globalThis.SootSim?.bridges?.lockstepCapture
2820
2820
  if (!lockstep || typeof lockstep.begin !== 'function') {
2821
2821
  return { ok: false, error: 'lockstep capture bridge unavailable' }
2822
2822
  }
2823
- let controller = window.__peachFlowAnimationClockController
2823
+ let controller = globalThis.__peachFlowAnimationClockController
2824
2824
  if (!controller) {
2825
2825
  controller = await lockstep.begin(${JSON.stringify(fps)})
2826
- window.__peachFlowAnimationClockController = controller
2826
+ globalThis.__peachFlowAnimationClockController = controller
2827
2827
  }
2828
2828
  let receipt = controller.initialFrame
2829
2829
  for (const ms of ${JSON.stringify(steps)}) {
@@ -2847,13 +2847,13 @@ export class SootSimBridgeFlowRunner {
2847
2847
  if (!this.animationClockLocked) return
2848
2848
  this.animationClockLocked = false
2849
2849
  await this.evaluate(`(() => {
2850
- const controller = window.__peachFlowAnimationClockController
2851
- window.__peachFlowAnimationClockController = null
2850
+ const controller = globalThis.__peachFlowAnimationClockController
2851
+ globalThis.__peachFlowAnimationClockController = null
2852
2852
  if (controller && typeof controller.end === 'function') {
2853
2853
  controller.end()
2854
2854
  return
2855
2855
  }
2856
- window.SootSim?.bridges?.lockstepCapture?.end?.()
2856
+ globalThis.SootSim?.bridges?.lockstepCapture?.end?.()
2857
2857
  })()`).catch(() => {})
2858
2858
  }
2859
2859
 
@@ -3235,10 +3235,10 @@ export class SootSimBridgeFlowRunner {
3235
3235
 
3236
3236
  async startProfile() {
3237
3237
  const result = await this.evaluate<any>(`(async () => {
3238
- if (!window.__sootsimShellPerf) {
3238
+ if (!globalThis.__sootsimShellPerf) {
3239
3239
  return { error: "shell frame profile unavailable (__sootsimShellPerf missing on the page)" }
3240
3240
  }
3241
- await window.__sootsimShellPerf.start()
3241
+ await globalThis.__sootsimShellPerf.start()
3242
3242
  return { started: true }
3243
3243
  })()`)
3244
3244
  if (result?.error) {
@@ -3249,10 +3249,10 @@ export class SootSimBridgeFlowRunner {
3249
3249
 
3250
3250
  async stopProfile(): Promise<SootSimFlowProfileResult> {
3251
3251
  const result = await this.evaluate<any>(`(async () => {
3252
- if (!window.__sootsimShellPerf) {
3252
+ if (!globalThis.__sootsimShellPerf) {
3253
3253
  return { error: "shell frame profile unavailable (__sootsimShellPerf missing on the page)" }
3254
3254
  }
3255
- return await window.__sootsimShellPerf.stop()
3255
+ return await globalThis.__sootsimShellPerf.stop()
3256
3256
  })()`)
3257
3257
 
3258
3258
  this.profilingEnabled = false
@@ -3454,7 +3454,7 @@ export class SootSimBridgeFlowRunner {
3454
3454
  const dataUrl = `data:${mimeType};base64,${bytes.toString('base64')}`
3455
3455
  const added = await this.evaluate<{ ok: boolean; error?: string }>(
3456
3456
  `(async () => {
3457
- const add = window.__sootsimAddPhotoDataUrl
3457
+ const add = globalThis.__sootsimAddPhotoDataUrl
3458
3458
  if (typeof add !== 'function') {
3459
3459
  return { ok: false, error: 'photo library bridge unavailable' }
3460
3460
  }
@@ -19,7 +19,7 @@ export interface SampleRect {
19
19
  // returns null on miss so the caller can report a clear not-found error.
20
20
  export function buildResolveRectEval(matcher: { id?: string; text?: string }): string {
21
21
  return `(async () => {
22
- const __t = window.__sootsimTest
22
+ const __t = globalThis.__sootsimTest
23
23
  if (!__t) throw new Error('__sootsimTest not available')
24
24
  const __id = ${JSON.stringify(matcher.id || '')}
25
25
  const __text = ${JSON.stringify(matcher.text || '')}
@@ -48,7 +48,7 @@ export function buildResolveRectEval(matcher: { id?: string; text?: string }): s
48
48
  export function buildSampleColorEval(rect: SampleRect): string {
49
49
  return `(async () => {
50
50
  const __rect = ${JSON.stringify(rect)}
51
- const __screenshot = window.__sootsimScreenshot
51
+ const __screenshot = globalThis.__sootsimScreenshot
52
52
  if (typeof __screenshot !== 'function') {
53
53
  throw new Error('screenshot bridge not installed')
54
54
  }
@@ -1307,7 +1307,7 @@ async function waitForTreeStable(
1307
1307
  opts: { stableMs: number; maxMs: number },
1308
1308
  ): Promise<void> {
1309
1309
  const deadline = Date.now() + opts.maxMs
1310
- const probeCode = `(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()`
1310
+ const probeCode = `(async () => (await globalThis.__sootsimTest?.getNodeCount?.()) || 0)()`
1311
1311
  const bridge = createBridge(wsPort, {
1312
1312
  commandTimeoutMs: 2000,
1313
1313
  simId,
@@ -701,13 +701,14 @@ Writes a page profile, worker profiles, and a manifest alongside the output.
701
701
  // with the native host attached, the engine's workers are realm threads in the host, reached
702
702
  // through the page; they record over the same window as the browser targets
703
703
  const hostRealms =
704
- (await evaluatePage(`typeof window.__peachNative?.cpuProfile === 'function'`)) ===
705
- true
704
+ (await evaluatePage(
705
+ `typeof globalThis.__peachNative?.cpuProfile === 'function'`,
706
+ )) === true
706
707
  const hostTargets: AttachedTarget[] = []
707
708
  if (hostRealms) {
708
709
  const startedAtMs = performance.now()
709
710
  const realms = await evaluatePage(
710
- `window.__peachNative.cpuProfile('start', ${sampleInterval * 1000})`,
711
+ `globalThis.__peachNative.cpuProfile('start', ${sampleInterval * 1000})`,
711
712
  )
712
713
  for (const realm of Array.isArray(realms) ? realms : []) {
713
714
  hostTargets.push({
@@ -768,7 +769,7 @@ Writes a page profile, worker profiles, and a manifest alongside the output.
768
769
  }),
769
770
  )
770
771
  if (hostRealms) {
771
- const stopped = await evaluatePage(`window.__peachNative.cpuProfile('stop', 0)`)
772
+ const stopped = await evaluatePage(`globalThis.__peachNative.cpuProfile('stop', 0)`)
772
773
  const stoppedAtMs = performance.now()
773
774
  for (const realm of Array.isArray(stopped) ? stopped : []) {
774
775
  const target = hostTargets.find(
@@ -311,7 +311,7 @@ function readNumberFlag(args: string[], flag: string): number | null {
311
311
  async function runImageAudit(bridge: WsBridge): Promise<ImageAuditReport> {
312
312
  await call(
313
313
  bridge,
314
- "window.__sootsimCompositor.getStats(false, false, undefined, 'enable').then(() => 'enabled')",
314
+ "globalThis.__sootsimCompositor.getStats(false, false, undefined, 'enable').then(() => 'enabled')",
315
315
  )
316
316
  let stats: { imageAudit?: ImageAuditReport | null }
317
317
  try {
@@ -319,7 +319,7 @@ async function runImageAudit(bridge: WsBridge): Promise<ImageAuditReport> {
319
319
  } finally {
320
320
  stats = await call(
321
321
  bridge,
322
- "window.__sootsimCompositor.getStats(false, false, undefined, 'disable').then((s) => ({ imageAudit: s.imageAudit }))",
322
+ "globalThis.__sootsimCompositor.getStats(false, false, undefined, 'disable').then((s) => ({ imageAudit: s.imageAudit }))",
323
323
  )
324
324
  }
325
325
  const report = stats?.imageAudit
@@ -347,7 +347,7 @@ async function runTargetedImageAudit(
347
347
  bridge,
348
348
  `(async () => {
349
349
  const input = ${JSON.stringify(targets)};
350
- const compositor = window.__sootsimCompositor;
350
+ const compositor = globalThis.__sootsimCompositor;
351
351
  let capture;
352
352
  let receipt;
353
353
  let audit;
@@ -229,7 +229,7 @@ async function fetchNetwork(
229
229
  const result = (await bridge.send({
230
230
  type: 'evaluate',
231
231
  code: `(() => {
232
- const obs = window.__sootsimObservability;
232
+ const obs = globalThis.__sootsimObservability;
233
233
  if (!obs) return { ok: false };
234
234
  return { ok: true, entries: obs.network.getSnapshot() };
235
235
  })()`,
@@ -296,7 +296,7 @@ async function fetchConsoleErrors(
296
296
  const result = (await bridge.send({
297
297
  type: 'evaluate',
298
298
  code: `(() => {
299
- const obs = window.__sootsimObservability;
299
+ const obs = globalThis.__sootsimObservability;
300
300
  if (!obs) return { ok: false };
301
301
  return { ok: true, entries: obs.logs.getSnapshot() };
302
302
  })()`,
@@ -811,7 +811,7 @@ flow extension:
811
811
  type: 'evaluate',
812
812
  simId: driver.simId,
813
813
  code: `(() => {
814
- const r = window.SootSim?.bridges?.eventRecorder ?? window.__sootsimEventRecorder
814
+ const r = globalThis.SootSim?.bridges?.eventRecorder ?? globalThis.__sootsimEventRecorder
815
815
  return r?.start?.() ?? false
816
816
  })()`,
817
817
  })
@@ -909,13 +909,13 @@ flow extension:
909
909
  if (preview) {
910
910
  // start the preview event recorder on the tab so agent-driven taps
911
911
  // (via sootsim:agentAction) land in the capture stream for replay.
912
- // some shells expose the recorder via window.SootSim, others via
912
+ // some shells expose the recorder via globalThis.SootSim, others via
913
913
  // the legacy alias only — try both.
914
914
  const started = await bridge.send({
915
915
  type: 'evaluate',
916
916
  simId: driver.simId,
917
917
  code: `(() => {
918
- const r = window.SootSim?.bridges?.eventRecorder ?? window.__sootsimEventRecorder
918
+ const r = globalThis.SootSim?.bridges?.eventRecorder ?? globalThis.__sootsimEventRecorder
919
919
  const startedAtMs = Date.now()
920
920
  return r?.start?.(startedAtMs) ? startedAtMs : null
921
921
  })()`,
@@ -945,7 +945,7 @@ flow extension:
945
945
  type: 'evaluate',
946
946
  simId: driver.simId,
947
947
  code: `(() => {
948
- const r = window.SootSim?.bridges?.eventRecorder ?? window.__sootsimEventRecorder
948
+ const r = globalThis.SootSim?.bridges?.eventRecorder ?? globalThis.__sootsimEventRecorder
949
949
  return r?.stop?.() ?? []
950
950
  })()`,
951
951
  })) as Array<Record<string, any>>
@@ -1000,7 +1000,7 @@ flow extension:
1000
1000
  type: 'evaluate',
1001
1001
  simId: driver.simId,
1002
1002
  code: `(() => {
1003
- const r = window.SootSim?.bridges?.eventRecorder ?? window.__sootsimEventRecorder
1003
+ const r = globalThis.SootSim?.bridges?.eventRecorder ?? globalThis.__sootsimEventRecorder
1004
1004
  return r?.stop?.() ?? []
1005
1005
  })()`,
1006
1006
  })) as Array<Record<string, any>>
@@ -1294,7 +1294,7 @@ async function startPreviewSceneRecording(
1294
1294
  await bridge.send({
1295
1295
  type: 'evaluate',
1296
1296
  simId,
1297
- code: `window.SootSim.bridges.sceneStream.run({ action: 'recordStart' })`,
1297
+ code: `globalThis.SootSim.bridges.sceneStream.run({ action: 'recordStart' })`,
1298
1298
  })
1299
1299
  return true
1300
1300
  } catch (err) {
@@ -1315,7 +1315,7 @@ async function stopPreviewSceneRecording(
1315
1315
  type: 'evaluate',
1316
1316
  simId,
1317
1317
  code: `(async () => {
1318
- const { bytes } = await window.SootSim.bridges.sceneStream.run({ action: 'recordStop' })
1318
+ const { bytes } = await globalThis.SootSim.bridges.sceneStream.run({ action: 'recordStop' })
1319
1319
  let text = ''
1320
1320
  for (let i = 0; i < bytes.length; i += 0x8000)
1321
1321
  text += String.fromCharCode(...bytes.subarray(i, i + 0x8000))
@@ -90,7 +90,7 @@ export function isInspectPickCommand(subcommand: string | null | undefined): boo
90
90
  export async function isInspectModeActive(bridge: InspectBridge): Promise<boolean> {
91
91
  const active = await bridge.send({
92
92
  type: 'evaluate',
93
- code: 'window.__sootsimEngineState?.inspectActive === true',
93
+ code: 'globalThis.__sootsimEngineState?.inspectActive === true',
94
94
  })
95
95
  return active === true
96
96
  }
@@ -587,7 +587,7 @@ export function layoutGetNativeEval(opts: LayoutExtractionOptions = {}): string
587
587
  const includeStyle = opts.styling === true
588
588
  const filter = opts.filter?.trim().toLowerCase() ?? ''
589
589
  return `(async () => {
590
- const t = window.__sootsimTest
590
+ const t = globalThis.__sootsimTest
591
591
  if (!t || typeof t.listInspectable !== 'function') return []
592
592
  const list = await t.listInspectable({})
593
593
  if (!Array.isArray(list)) return []
@@ -751,7 +751,7 @@ export function layoutGetNativeEval(opts: LayoutExtractionOptions = {}): string
751
751
  const textElements = elements.filter((element) => element.text && element.fontSize > 0)
752
752
  if (!includeStyle || textElements.length === 0) return elements
753
753
 
754
- const screenshot = window.SootSim && window.SootSim.bridges && window.SootSim.bridges.screenshot
754
+ const screenshot = globalThis.SootSim && globalThis.SootSim.bridges && globalThis.SootSim.bridges.screenshot
755
755
  if (typeof screenshot !== 'function') {
756
756
  throw new Error('styled native layout requires the peach capture bridge')
757
757
  }
@@ -1714,10 +1714,10 @@ export function consoleEntriesEval(level: 'error' | 'warn', limit: number): stri
1714
1714
  out.push({ timestamp: ts, args: Array.isArray(e.args) ? e.args : [e.args], stack: e.stack || undefined, source: e.source || undefined })
1715
1715
  }
1716
1716
  // page-realm ws-bridge buffer first (richest stacks for page-origin errors)
1717
- try { for (const e of (window.__sootsimConsole?.${getter}(${limit}) || [])) push(e) } catch {}
1717
+ try { for (const e of (globalThis.__sootsimConsole?.${getter}(${limit}) || [])) push(e) } catch {}
1718
1718
  // engine observability store — the always-on render-worker / forwarded path
1719
1719
  try {
1720
- const obs = window.__sootsimObservability
1720
+ const obs = globalThis.__sootsimObservability
1721
1721
  const snap = obs && obs.logs && typeof obs.logs.getSnapshot === 'function' ? obs.logs.getSnapshot() : []
1722
1722
  for (const e of snap) if (e && e.level === ${JSON.stringify(level)}) push(e)
1723
1723
  } catch {}
@@ -1772,12 +1772,12 @@ export const MERGED_CONSOLE_COUNT_EVAL = `(() => {
1772
1772
  else warnings++
1773
1773
  }
1774
1774
  try {
1775
- const c = window.__sootsimConsole
1775
+ const c = globalThis.__sootsimConsole
1776
1776
  for (const e of (c?.getErrors?.(200) || [])) add('error', e?.timestamp ?? e?.ts, e?.args)
1777
1777
  for (const e of (c?.getWarnings?.(200) || [])) add('warn', e?.timestamp ?? e?.ts, e?.args)
1778
1778
  } catch {}
1779
1779
  try {
1780
- const obs = window.__sootsimObservability
1780
+ const obs = globalThis.__sootsimObservability
1781
1781
  const snap = obs && obs.logs && typeof obs.logs.getSnapshot === 'function' ? obs.logs.getSnapshot() : []
1782
1782
  for (const e of snap) if (e) add(e.level, e.ts, e.args)
1783
1783
  } catch {}
@@ -1789,7 +1789,7 @@ export const MERGED_CONSOLE_COUNT_EVAL = `(() => {
1789
1789
  export async function clearConsole(bridge: InspectBridge): Promise<void> {
1790
1790
  await bridge.send({
1791
1791
  type: 'evaluate',
1792
- code: 'window.__sootsimConsole?.clear(); window.__sootsimObservability?.logs?.clear?.(); "cleared"',
1792
+ code: 'globalThis.__sootsimConsole?.clear(); globalThis.__sootsimObservability?.logs?.clear?.(); "cleared"',
1793
1793
  })
1794
1794
  }
1795
1795
 
@@ -1924,7 +1924,7 @@ export async function inspectLogs(bridge: InspectBridge): Promise<LogEntry[]> {
1924
1924
  const res = (await bridge.send({
1925
1925
  type: 'evaluate',
1926
1926
  code: `(() => {
1927
- const obs = window.__sootsimObservability;
1927
+ const obs = globalThis.__sootsimObservability;
1928
1928
  if (!obs) return { ok: false };
1929
1929
  return { ok: true, entries: obs.logs.getSnapshot() };
1930
1930
  })()`,
@@ -1937,7 +1937,7 @@ export async function inspectLogs(bridge: InspectBridge): Promise<LogEntry[]> {
1937
1937
  export async function clearLogs(bridge: InspectBridge): Promise<void> {
1938
1938
  await bridge.send({
1939
1939
  type: 'evaluate',
1940
- code: 'window.__sootsimObservability?.logs.clear(); "cleared"',
1940
+ code: 'globalThis.__sootsimObservability?.logs.clear(); "cleared"',
1941
1941
  })
1942
1942
  }
1943
1943
 
@@ -2085,7 +2085,7 @@ export async function inspectKeyboard(
2085
2085
  const result = (await bridge.send({
2086
2086
  type: 'evaluate',
2087
2087
  code: `(() => {
2088
- const kb = window.__sootsimKeyboard
2088
+ const kb = globalThis.__sootsimKeyboard
2089
2089
  if (!kb || typeof kb.getLayout !== 'function') {
2090
2090
  return { error: 'keyboard bridge getLayout() not available' }
2091
2091
  }
@@ -2165,8 +2165,8 @@ export async function inspectScreens(bridge: InspectBridge): Promise<ScreensRepo
2165
2165
  const payload = (await bridge.send({
2166
2166
  type: 'evaluate',
2167
2167
  code: `(async () => {
2168
- const test = window.__sootsimTest
2169
- const kb = window.__sootsimKeyboard
2168
+ const test = globalThis.__sootsimTest
2169
+ const kb = globalThis.__sootsimKeyboard
2170
2170
  const navSnap =
2171
2171
  test && typeof test.getNavigationSnapshot === 'function'
2172
2172
  ? await test.getNavigationSnapshot()
@@ -2226,7 +2226,7 @@ export async function inspectDebugStatus(
2226
2226
  if (bridge.plane === 'cloud' && !host) {
2227
2227
  return (await inspectCloudDiagnostics(bridge)).channels
2228
2228
  }
2229
- return bridge.send({ type: 'evaluate', code: 'window.__sootsimDebug.status()' })
2229
+ return bridge.send({ type: 'evaluate', code: 'globalThis.__sootsimDebug.status()' })
2230
2230
  }
2231
2231
 
2232
2232
  // `debug flags` — the engine's debug feature flags.
@@ -2240,7 +2240,7 @@ export async function inspectDebugFlags(
2240
2240
  availableChannels.map((channel) => [channel, channels.includes(channel)]),
2241
2241
  )
2242
2242
  }
2243
- return bridge.send({ type: 'evaluate', code: 'window.__sootsimDebug.flags()' })
2243
+ return bridge.send({ type: 'evaluate', code: 'globalThis.__sootsimDebug.flags()' })
2244
2244
  }
2245
2245
 
2246
2246
  export async function inspectDebugChannels(
@@ -2250,7 +2250,7 @@ export async function inspectDebugChannels(
2250
2250
  if (bridge.plane === 'cloud' && !host) {
2251
2251
  return (await inspectCloudDiagnostics(bridge)).availableChannels
2252
2252
  }
2253
- return bridge.send({ type: 'evaluate', code: 'window.__sootsimDebug.channels()' })
2253
+ return bridge.send({ type: 'evaluate', code: 'globalThis.__sootsimDebug.channels()' })
2254
2254
  }
2255
2255
 
2256
2256
  // `debug find sheets|portals` — locate all live sheet / portal nodes.
@@ -2267,7 +2267,7 @@ export async function inspectDebugFind(
2267
2267
  }
2268
2268
  return bridge.send({
2269
2269
  type: 'evaluate',
2270
- code: `window.__sootsimTest.debugFind(${JSON.stringify(target)})`,
2270
+ code: `globalThis.__sootsimTest.debugFind(${JSON.stringify(target)})`,
2271
2271
  })
2272
2272
  }
2273
2273
 
@@ -2286,7 +2286,7 @@ export async function callDebugBridge(
2286
2286
  return bridge.send({
2287
2287
  type: 'evaluate',
2288
2288
  code: `(async () => {
2289
- const result = await window.__sootsimTest.evalInTenant(${JSON.stringify(code)})
2289
+ const result = await globalThis.__sootsimTest.evalInTenant(${JSON.stringify(code)})
2290
2290
  if (!result.ok) throw new Error(result.error)
2291
2291
  return result.value
2292
2292
  })()`,
@@ -2450,17 +2450,17 @@ export async function inspectMemory(bridge: InspectBridge): Promise<MemoryReport
2450
2450
  const result = (await bridge.send({
2451
2451
  type: 'evaluate',
2452
2452
  code: `(async () => {
2453
- const host = window.__sootsimRenderHost
2453
+ const host = globalThis.__sootsimRenderHost
2454
2454
  const stats = host?.queryStats ? await host.queryStats() : null
2455
- const shellRaw = window.__sootsimShellMemory
2456
- ? await window.__sootsimShellMemory()
2455
+ const shellRaw = globalThis.__sootsimShellMemory
2456
+ ? await globalThis.__sootsimShellMemory()
2457
2457
  : null
2458
2458
  const shell = shellRaw && !shellRaw.error ? shellRaw : null
2459
2459
  // the compositor paints home + app:one + app:two, so every app-surface
2460
2460
  // picture and raster image is counted here and nowhere else.
2461
2461
  let compositor = null
2462
2462
  try {
2463
- const cs = await window.__sootsimCompositor?.getStats?.(false, true)
2463
+ const cs = await globalThis.__sootsimCompositor?.getStats?.(false, true)
2464
2464
  compositor = cs?.memory ?? null
2465
2465
  } catch {}
2466
2466
  const normalize = (m) =>
@@ -7,7 +7,7 @@
7
7
 
8
8
  export function buildGetNodeEval(matcher: string): string {
9
9
  return `(async () => {
10
- const t = window.__sootsimTest
10
+ const t = globalThis.__sootsimTest
11
11
  const q = ${JSON.stringify(matcher)}
12
12
  let node = null
13
13
  let via = null
@@ -30,7 +30,7 @@ export function buildGetNodeEval(matcher: string): string {
30
30
  // parent chain — walk up from the node so the JSON dump is
31
31
  // self-describing.
32
32
  const parentChain = []
33
- const root = window.__sootsimRoot
33
+ const root = globalThis.__sootsimRoot
34
34
  if (root && typeof node.nodeId === 'number') {
35
35
  const findPath = (n, targetId, path) => {
36
36
  if (!n) return null
@@ -178,7 +178,7 @@ export async function waitForSimReady(
178
178
  const count = await Promise.race([
179
179
  bridge.send({
180
180
  type: 'evaluate',
181
- code: '(async () => (await window.__sootsimTest?.getNodeCount()) ?? null)()',
181
+ code: '(async () => (await globalThis.__sootsimTest?.getNodeCount()) ?? null)()',
182
182
  }),
183
183
  new Promise<never>((_, reject) => {
184
184
  timer = setTimeout(
@@ -210,7 +210,7 @@ export async function waitForSimReady(
210
210
  const observed = lastError
211
211
  ? `last bridge error: ${lastError}`
212
212
  : lastCount === null
213
- ? 'guest never installed window.__sootsimTest'
213
+ ? 'guest never installed globalThis.__sootsimTest'
214
214
  : `last node count: ${String(lastCount)} (needs > ${minNodeCount})`
215
215
  return {
216
216
  bridge: null,
@@ -162,7 +162,7 @@ export async function runWaitEventSubcommand(opts: WaitEventOptions): Promise<vo
162
162
  // but evaluate is the universally available shape and the cost
163
163
  // of a string-baked function is negligible at 5Hz.
164
164
  code: `(async () => {
165
- const t = window.SootSim?.bridges?.timeline
165
+ const t = globalThis.SootSim?.bridges?.timeline
166
166
  if (!t) return { ok: false, error: 'timeline bridge missing' }
167
167
  return { ok: true, result: await t.recent(${JSON.stringify(query)}) }
168
168
  })()`,