rnxsim 0.1.381 → 0.1.382

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 (138) hide show
  1. package/README.md +19 -6
  2. package/cli/app-fonts.ts +1 -1
  3. package/cli/bin.ts +118 -26
  4. package/cli/bridge-diagnostics.ts +1 -1
  5. package/cli/bridge-flow-runner.ts +9 -9
  6. package/cli/browser-evals.ts +3 -3
  7. package/cli/cli-update.ts +261 -0
  8. package/cli/cloud-client.ts +407 -0
  9. package/cli/cloud-dispatch.ts +165 -0
  10. package/cli/cloud-session.ts +156 -0
  11. package/cli/command-contract.ts +2 -2
  12. package/cli/command-registry.ts +9 -0
  13. package/cli/commands/agent-wrapper.ts +4 -4
  14. package/cli/commands/agent.ts +3 -3
  15. package/cli/commands/box/checkout-plane.ts +16 -8
  16. package/cli/commands/box/rnx-command.ts +2 -2
  17. package/cli/commands/box/search-command.ts +2 -2
  18. package/cli/commands/box.ts +123 -70
  19. package/cli/commands/config.ts +3 -2
  20. package/cli/commands/control.ts +6 -6
  21. package/cli/commands/cpu-profile.ts +2 -2
  22. package/cli/commands/daemon.ts +7 -7
  23. package/cli/commands/debug.ts +2 -2
  24. package/cli/commands/detox.ts +7 -7
  25. package/cli/commands/diagnose.ts +1 -1
  26. package/cli/commands/electron.ts +1 -1
  27. package/cli/commands/film.ts +1 -1
  28. package/cli/commands/flow.ts +4 -4
  29. package/cli/commands/inspect/core.ts +58 -7
  30. package/cli/commands/inspect/env.ts +5 -3
  31. package/cli/commands/inspect/shared.ts +2 -1
  32. package/cli/commands/inspect/wait-event.ts +1 -1
  33. package/cli/commands/inspect/wait-ready.ts +15 -5
  34. package/cli/commands/inspect.ts +31 -9
  35. package/cli/commands/install-desktop.ts +2 -2
  36. package/cli/commands/maestro.ts +3 -3
  37. package/cli/commands/permissions.ts +1 -1
  38. package/cli/commands/platform.ts +91 -0
  39. package/cli/commands/record.ts +3 -3
  40. package/cli/commands/report-issue.ts +1 -1
  41. package/cli/commands/runtime.ts +1 -1
  42. package/cli/commands/screenshot-mode.ts +1 -1
  43. package/cli/commands/screenshot.ts +25 -0
  44. package/cli/commands/serve.ts +1 -1
  45. package/cli/commands/skills.ts +1 -1
  46. package/cli/commands/timeline.ts +1 -1
  47. package/cli/commands/upgrade.ts +8 -34
  48. package/cli/commands/upload.ts +3 -3
  49. package/cli/commands/version.ts +14 -3
  50. package/cli/commands/what-happened.ts +2 -2
  51. package/cli/current-sim.ts +43 -30
  52. package/cli/desktop-companion.ts +1 -1
  53. package/cli/drivers/electron.ts +1 -1
  54. package/cli/drivers/playwright.ts +3 -3
  55. package/cli/drivers/types.ts +4 -4
  56. package/cli/flow-file.ts +3 -3
  57. package/cli/help-core.ts +18 -11
  58. package/cli/hidden-runtime-alias.ts +1 -1
  59. package/cli/hints.ts +2 -2
  60. package/cli/maestro-js.ts +2 -2
  61. package/cli/outbound-endpoints.ts +40 -6
  62. package/cli/parse-args.ts +1 -1
  63. package/cli/registry.ts +1 -1
  64. package/cli/resolve-assets.ts +2 -2
  65. package/cli/secure-file.ts +31 -0
  66. package/cli/shell-init.ts +98 -0
  67. package/cli/ws-bridge.ts +18 -8
  68. package/detox/expectations.ts +1 -1
  69. package/detox/gestures.ts +3 -3
  70. package/detox/index.ts +3 -3
  71. package/dist-lib/agent-daemon-client.cjs +1 -1
  72. package/dist-lib/agent-events.cjs +1 -1
  73. package/dist-lib/agent-identity.cjs +1 -1
  74. package/dist-lib/agent-sessions.cjs +1 -1
  75. package/dist-lib/attached-projects.cjs +1 -1
  76. package/dist-lib/auth/shared-session.cjs +1 -1
  77. package/dist-lib/backend-origin.cjs +1 -1
  78. package/dist-lib/beta.cjs +1 -1
  79. package/dist-lib/beta.mjs +1 -1
  80. package/dist-lib/bridge-constants.cjs +1 -1
  81. package/dist-lib/bridge-contract-input.cjs +15 -8
  82. package/dist-lib/bridge-contract-input.mjs +15 -8
  83. package/dist-lib/bridge-contract.cjs +1 -1
  84. package/dist-lib/bridge-contract.mjs +1 -1
  85. package/dist-lib/capture-contract.cjs +107 -0
  86. package/dist-lib/capture-contract.mjs +80 -0
  87. package/dist-lib/cli-constants.cjs +1 -1
  88. package/dist-lib/cloud-contract.cjs +32 -0
  89. package/dist-lib/cloud-contract.mjs +7 -0
  90. package/dist-lib/config.cjs +1 -1
  91. package/dist-lib/detox/index.cjs +4 -4
  92. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  93. package/dist-lib/home-paths.cjs +9 -1
  94. package/dist-lib/host/bridge-host.cjs +15 -10
  95. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  96. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  97. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  98. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  99. package/dist-lib/host/websocket-proxy.cjs +1 -1
  100. package/dist-lib/index.cjs +248 -73
  101. package/dist-lib/jump-to-source-babel.cjs +1 -1
  102. package/dist-lib/menu.cjs +1 -1
  103. package/dist-lib/menu.mjs +1 -1
  104. package/dist-lib/metro-production-bundle.cjs +1 -1
  105. package/dist-lib/metro-production-bundle.mjs +1 -1
  106. package/dist-lib/metro.cjs +1 -1
  107. package/dist-lib/profiles.cjs +1 -1
  108. package/dist-lib/public-brand.cjs +1 -1
  109. package/dist-lib/react-native-host-modules.cjs +1 -1
  110. package/dist-lib/react-native-host-modules.mjs +1 -1
  111. package/dist-lib/render-mode.cjs +1 -1
  112. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  113. package/dist-lib/sdk.cjs +44 -6
  114. package/dist-lib/sdk.mjs +44 -6
  115. package/dist-lib/skills.cjs +435 -155
  116. package/dist-lib/vite.cjs +1 -1
  117. package/package.json +20 -4
  118. package/scripts/dev-server-scanner.ts +3 -3
  119. package/skills/contrast/SKILL.md +1 -1
  120. package/skills/rnx-perf/SKILL.md +68 -52
  121. package/src/app-url.ts +2 -3
  122. package/src/bridge-contract-input.ts +17 -6
  123. package/src/bridge-contract.ts +25 -4
  124. package/src/capture-contract.ts +423 -0
  125. package/src/cloud-contract.ts +15 -0
  126. package/src/home-paths.ts +9 -3
  127. package/src/host/agent-host.ts +1 -1
  128. package/src/host/bridge-host.ts +13 -11
  129. package/src/host/plane-host.ts +2 -2
  130. package/src/index.ts +21 -0
  131. package/src/native-dev-bundle-url.ts +2 -2
  132. package/src/screenshots/orchestrate.ts +1 -1
  133. package/src/screenshots/org-deck.ts +1 -1
  134. package/src/settings-bundle.ts +1 -1
  135. package/src/sim-client.ts +4 -0
  136. package/src/vite-plugin-one.ts +2 -2
  137. package/src/vite-plugin.ts +1 -1
  138. package/cli/commands/box/cloud-box.ts +0 -294
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract-input.ts
4
4
  var BridgeInputError = class extends Error {
@@ -165,8 +165,10 @@ function parseStateOptions(value) {
165
165
  const input = recordValue(value, "state");
166
166
  const route = optionalBoolean(input, "route", "state");
167
167
  const errors = optionalBoolean(input, "errors", "state");
168
+ const logs = optionalBoolean(input, "logs", "state");
168
169
  const depth = optionalNumber(input, "depth", "state");
169
170
  const errorLimit = optionalNumber(input, "errorLimit", "state");
171
+ const logLimit = optionalNumber(input, "logLimit", "state");
170
172
  const layers = input.layers === void 0 ? void 0 : stringValue(input.layers, "state.layers");
171
173
  if (layers !== void 0 && layers !== "full" && layers !== "tenant" && layers !== "shell") {
172
174
  return validationFailure("state.layers", "must be full, tenant, or shell");
@@ -176,9 +178,11 @@ function parseStateOptions(value) {
176
178
  tree: optionalBoolean(input, "tree", "state") ?? true,
177
179
  ...route === void 0 ? {} : { route },
178
180
  ...errors === void 0 ? {} : { errors },
181
+ ...logs === void 0 ? {} : { logs },
179
182
  ...depth === void 0 ? {} : { depth },
180
183
  ...layers === void 0 ? {} : { layers },
181
- ...errorLimit === void 0 ? {} : { errorLimit }
184
+ ...errorLimit === void 0 ? {} : { errorLimit },
185
+ ...logLimit === void 0 ? {} : { logLimit }
182
186
  };
183
187
  }
184
188
  function parseSemanticSelector(value, path) {
@@ -225,15 +229,18 @@ function parseSemanticQuery(value) {
225
229
  }
226
230
  return validationFailure("query.kind", "must be tree, find, or count");
227
231
  }
228
- function parseSemanticResolveSelector(value) {
229
- const selector = recordValue(value, "selector");
232
+ function semanticResolveSelector(value, path) {
233
+ const selector = recordValue(value, path);
230
234
  if (selector.testID !== void 0) {
231
- return { testID: stringValue(selector.testID, "selector.testID") };
235
+ return { testID: stringValue(selector.testID, `${path}.testID`) };
232
236
  }
233
237
  if (selector.text !== void 0) {
234
- return { text: stringValue(selector.text, "selector.text") };
238
+ return { text: stringValue(selector.text, `${path}.text`) };
235
239
  }
236
- return validationFailure("selector", "must select testID or text");
240
+ return validationFailure(path, "must select testID or text");
241
+ }
242
+ function parseSemanticResolveSelector(value) {
243
+ return semanticResolveSelector(value, "selector");
237
244
  }
238
245
  function parseSemanticWaitOptions(value) {
239
246
  const input = recordValue(value, "waitFor");
@@ -255,7 +262,7 @@ function parseSemanticWaitOptions(value) {
255
262
  return {
256
263
  condition: {
257
264
  type,
258
- testID: stringValue(condition.testID, "waitFor.condition.testID")
265
+ selector: semanticResolveSelector(condition.selector, "waitFor.condition.selector")
259
266
  },
260
267
  ...timeoutMs === void 0 ? {} : { timeoutMs }
261
268
  };
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SEMANTIC_READY_CONTENT_NODE_FLOOR = 100;
@@ -0,0 +1,107 @@
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
+ "use strict";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/capture-contract.ts
23
+ var capture_contract_exports = {};
24
+ __export(capture_contract_exports, {
25
+ RNX_SCREEN_CAPTURE_VERSION: () => RNX_SCREEN_CAPTURE_VERSION,
26
+ isRnxCaptureRegionAtlas: () => isRnxCaptureRegionAtlas,
27
+ isRnxScreenCapture: () => isRnxScreenCapture
28
+ });
29
+ module.exports = __toCommonJS(capture_contract_exports);
30
+ var RNX_SCREEN_CAPTURE_VERSION = 1;
31
+ function captureRecord(value) {
32
+ return value !== null && typeof value === "object" && !Array.isArray(value);
33
+ }
34
+ function captureInteger(value) {
35
+ return typeof value === "number" && Number.isSafeInteger(value);
36
+ }
37
+ function captureNumber(value) {
38
+ return typeof value === "number" && Number.isFinite(value);
39
+ }
40
+ function captureNullableString(value) {
41
+ return value === null || typeof value === "string";
42
+ }
43
+ function captureRect(value) {
44
+ return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y) && captureNumber(value.width) && captureNumber(value.height);
45
+ }
46
+ function captureOptionalString(value) {
47
+ return value === void 0 || typeof value === "string";
48
+ }
49
+ function captureOptionalNullableString(value) {
50
+ return value === void 0 || captureNullableString(value);
51
+ }
52
+ function captureFontRegistration(value) {
53
+ return captureRecord(value) && typeof value.family === "string" && value.family.length > 0 && captureOptionalString(value.url) && captureOptionalString(value.sourceLabel) && captureOptionalNullableString(value.parsedFamily) && captureOptionalNullableString(value.parsedPostScript) && captureOptionalNullableString(value.fullName);
54
+ }
55
+ function capturePoint(value) {
56
+ return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y);
57
+ }
58
+ function captureNode(value) {
59
+ if (!captureRecord(value) || !captureInteger(value.nodeId) || !(value.parentNodeId === null || captureInteger(value.parentNodeId)) || !Array.isArray(value.childNodeIds) || !value.childNodeIds.every(captureInteger) || !captureInteger(value.paintIndex) || typeof value.type !== "string" || !captureNullableString(value.id) || !captureNullableString(value.testID) || !captureNullableString(value.text) || !captureInteger(value.childCount) || !captureRecord(value.accessibility) || !captureRecord(value.interaction) || !captureRecord(value.layout) || !captureRecord(value.style) || !captureRecord(value.source) || !captureRecord(value.props) || !captureRecord(value.inspection)) {
60
+ return false;
61
+ }
62
+ const accessibility = value.accessibility;
63
+ if (typeof accessibility.accessible !== "boolean" || !captureNullableString(accessibility.label) || !captureNullableString(accessibility.role) || !captureNullableString(accessibility.hint) || !(accessibility.liveRegion === null || accessibility.liveRegion === "none" || accessibility.liveRegion === "polite" || accessibility.liveRegion === "assertive") || !(accessibility.state === null || captureRecord(accessibility.state)) || !(accessibility.value === null || captureRecord(accessibility.value))) {
64
+ return false;
65
+ }
66
+ const interaction = value.interaction;
67
+ if (typeof interaction.pressed !== "boolean" || typeof interaction.pressable !== "boolean" || typeof interaction.textInput !== "boolean" || !(interaction.textSelection === null || captureRecord(interaction.textSelection)) || typeof interaction.secureTextEntry !== "boolean" || !captureNullableString(interaction.placeholder) || !capturePoint(interaction.scrollOffset) || !(interaction.zoomScale === null || captureNumber(interaction.zoomScale)) || typeof interaction.nativePinchEnabled !== "boolean" || !(interaction.contentOffsetProp === null || captureRecord(interaction.contentOffsetProp)) || !(interaction.strokeDashoffsetProp === null || captureNumber(interaction.strokeDashoffsetProp))) {
68
+ return false;
69
+ }
70
+ const layout = value.layout;
71
+ if (!captureRect(layout.local) || !(layout.frame === null || captureRect(layout.frame)) || !capturePoint(layout.absolutePosition) || !(layout.visibleFrame === null || captureRect(layout.visibleFrame))) {
72
+ return false;
73
+ }
74
+ const style = value.style;
75
+ return captureRecord(style.resolved) && captureRecord(style.authored) && captureRecord(style.computed) && captureRecord(style.tokenBindings) && (value.textLines === void 0 || Array.isArray(value.textLines));
76
+ }
77
+ function isRnxScreenCapture(value) {
78
+ if (!captureRecord(value) || value.contractVersion !== RNX_SCREEN_CAPTURE_VERSION || !captureInteger(value.capturedAt) || !captureRecord(value.tree) || !(value.fonts === void 0 || Array.isArray(value.fonts) && value.fonts.length <= 200 && value.fonts.every(captureFontRegistration)) || !(value.visual === void 0 || captureRecord(value.visual))) {
79
+ return false;
80
+ }
81
+ const tree = value.tree;
82
+ const visual = value.visual;
83
+ return captureRecord(tree.viewport) && captureInteger(tree.viewport.width) && tree.viewport.width > 0 && captureInteger(tree.viewport.height) && tree.viewport.height > 0 && captureInteger(tree.rootNodeId) && Array.isArray(tree.nodes) && tree.nodes.every(captureNode) && (visual === void 0 || visual.kind === "png" && (visual.producer === "headless-cpu-app-surface" || visual.producer === "browser-compositor-app-surface") && typeof visual.dataUri === "string" && visual.dataUri.startsWith("data:image/png;base64,") && captureInteger(visual.pixelWidth) && visual.pixelWidth > 0 && captureInteger(visual.pixelHeight) && visual.pixelHeight > 0);
84
+ }
85
+ function isRnxCaptureRegionAtlas(value) {
86
+ if (!captureRecord(value) || value.kind !== "png-atlas" || value.producer !== "headless-cpu-app-surface" || typeof value.dataUri !== "string" || !value.dataUri.startsWith("data:image/png;base64,") || !captureNumber(value.width) || value.width <= 0 || !captureNumber(value.height) || value.height <= 0 || !captureInteger(value.pixelWidth) || value.pixelWidth <= 0 || !captureInteger(value.pixelHeight) || value.pixelHeight <= 0 || !Array.isArray(value.regions) || value.regions.length === 0 || value.regions.length > 256) {
87
+ return false;
88
+ }
89
+ const scale = value.pixelWidth / value.width;
90
+ if (!Number.isInteger(scale) || scale < 1 || scale > 4 || Math.abs(value.height * scale - value.pixelHeight) > 1e-6) {
91
+ return false;
92
+ }
93
+ const keys = /* @__PURE__ */ new Set();
94
+ for (const region of value.regions) {
95
+ if (!captureRecord(region) || typeof region.key !== "string" || region.key.length === 0 || keys.has(region.key) || !captureInteger(region.nodeId) || region.nodeId <= 0 || !captureRect(region.frame) || region.frame.width <= 0 || region.frame.height <= 0 || !captureRect(region.source) || region.source.x < 0 || region.source.y < 0 || region.source.width !== region.frame.width || region.source.height !== region.frame.height || region.source.x + region.source.width > value.width || region.source.y + region.source.height > value.height) {
96
+ return false;
97
+ }
98
+ keys.add(region.key);
99
+ }
100
+ return true;
101
+ }
102
+ // Annotate the CommonJS export names for ESM import in node:
103
+ 0 && (module.exports = {
104
+ RNX_SCREEN_CAPTURE_VERSION,
105
+ isRnxCaptureRegionAtlas,
106
+ isRnxScreenCapture
107
+ });
@@ -0,0 +1,80 @@
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+
3
+ // src/capture-contract.ts
4
+ var RNX_SCREEN_CAPTURE_VERSION = 1;
5
+ function captureRecord(value) {
6
+ return value !== null && typeof value === "object" && !Array.isArray(value);
7
+ }
8
+ function captureInteger(value) {
9
+ return typeof value === "number" && Number.isSafeInteger(value);
10
+ }
11
+ function captureNumber(value) {
12
+ return typeof value === "number" && Number.isFinite(value);
13
+ }
14
+ function captureNullableString(value) {
15
+ return value === null || typeof value === "string";
16
+ }
17
+ function captureRect(value) {
18
+ return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y) && captureNumber(value.width) && captureNumber(value.height);
19
+ }
20
+ function captureOptionalString(value) {
21
+ return value === void 0 || typeof value === "string";
22
+ }
23
+ function captureOptionalNullableString(value) {
24
+ return value === void 0 || captureNullableString(value);
25
+ }
26
+ function captureFontRegistration(value) {
27
+ return captureRecord(value) && typeof value.family === "string" && value.family.length > 0 && captureOptionalString(value.url) && captureOptionalString(value.sourceLabel) && captureOptionalNullableString(value.parsedFamily) && captureOptionalNullableString(value.parsedPostScript) && captureOptionalNullableString(value.fullName);
28
+ }
29
+ function capturePoint(value) {
30
+ return captureRecord(value) && captureNumber(value.x) && captureNumber(value.y);
31
+ }
32
+ function captureNode(value) {
33
+ if (!captureRecord(value) || !captureInteger(value.nodeId) || !(value.parentNodeId === null || captureInteger(value.parentNodeId)) || !Array.isArray(value.childNodeIds) || !value.childNodeIds.every(captureInteger) || !captureInteger(value.paintIndex) || typeof value.type !== "string" || !captureNullableString(value.id) || !captureNullableString(value.testID) || !captureNullableString(value.text) || !captureInteger(value.childCount) || !captureRecord(value.accessibility) || !captureRecord(value.interaction) || !captureRecord(value.layout) || !captureRecord(value.style) || !captureRecord(value.source) || !captureRecord(value.props) || !captureRecord(value.inspection)) {
34
+ return false;
35
+ }
36
+ const accessibility = value.accessibility;
37
+ if (typeof accessibility.accessible !== "boolean" || !captureNullableString(accessibility.label) || !captureNullableString(accessibility.role) || !captureNullableString(accessibility.hint) || !(accessibility.liveRegion === null || accessibility.liveRegion === "none" || accessibility.liveRegion === "polite" || accessibility.liveRegion === "assertive") || !(accessibility.state === null || captureRecord(accessibility.state)) || !(accessibility.value === null || captureRecord(accessibility.value))) {
38
+ return false;
39
+ }
40
+ const interaction = value.interaction;
41
+ if (typeof interaction.pressed !== "boolean" || typeof interaction.pressable !== "boolean" || typeof interaction.textInput !== "boolean" || !(interaction.textSelection === null || captureRecord(interaction.textSelection)) || typeof interaction.secureTextEntry !== "boolean" || !captureNullableString(interaction.placeholder) || !capturePoint(interaction.scrollOffset) || !(interaction.zoomScale === null || captureNumber(interaction.zoomScale)) || typeof interaction.nativePinchEnabled !== "boolean" || !(interaction.contentOffsetProp === null || captureRecord(interaction.contentOffsetProp)) || !(interaction.strokeDashoffsetProp === null || captureNumber(interaction.strokeDashoffsetProp))) {
42
+ return false;
43
+ }
44
+ const layout = value.layout;
45
+ if (!captureRect(layout.local) || !(layout.frame === null || captureRect(layout.frame)) || !capturePoint(layout.absolutePosition) || !(layout.visibleFrame === null || captureRect(layout.visibleFrame))) {
46
+ return false;
47
+ }
48
+ const style = value.style;
49
+ return captureRecord(style.resolved) && captureRecord(style.authored) && captureRecord(style.computed) && captureRecord(style.tokenBindings) && (value.textLines === void 0 || Array.isArray(value.textLines));
50
+ }
51
+ function isRnxScreenCapture(value) {
52
+ if (!captureRecord(value) || value.contractVersion !== RNX_SCREEN_CAPTURE_VERSION || !captureInteger(value.capturedAt) || !captureRecord(value.tree) || !(value.fonts === void 0 || Array.isArray(value.fonts) && value.fonts.length <= 200 && value.fonts.every(captureFontRegistration)) || !(value.visual === void 0 || captureRecord(value.visual))) {
53
+ return false;
54
+ }
55
+ const tree = value.tree;
56
+ const visual = value.visual;
57
+ return captureRecord(tree.viewport) && captureInteger(tree.viewport.width) && tree.viewport.width > 0 && captureInteger(tree.viewport.height) && tree.viewport.height > 0 && captureInteger(tree.rootNodeId) && Array.isArray(tree.nodes) && tree.nodes.every(captureNode) && (visual === void 0 || visual.kind === "png" && (visual.producer === "headless-cpu-app-surface" || visual.producer === "browser-compositor-app-surface") && typeof visual.dataUri === "string" && visual.dataUri.startsWith("data:image/png;base64,") && captureInteger(visual.pixelWidth) && visual.pixelWidth > 0 && captureInteger(visual.pixelHeight) && visual.pixelHeight > 0);
58
+ }
59
+ function isRnxCaptureRegionAtlas(value) {
60
+ if (!captureRecord(value) || value.kind !== "png-atlas" || value.producer !== "headless-cpu-app-surface" || typeof value.dataUri !== "string" || !value.dataUri.startsWith("data:image/png;base64,") || !captureNumber(value.width) || value.width <= 0 || !captureNumber(value.height) || value.height <= 0 || !captureInteger(value.pixelWidth) || value.pixelWidth <= 0 || !captureInteger(value.pixelHeight) || value.pixelHeight <= 0 || !Array.isArray(value.regions) || value.regions.length === 0 || value.regions.length > 256) {
61
+ return false;
62
+ }
63
+ const scale = value.pixelWidth / value.width;
64
+ if (!Number.isInteger(scale) || scale < 1 || scale > 4 || Math.abs(value.height * scale - value.pixelHeight) > 1e-6) {
65
+ return false;
66
+ }
67
+ const keys = /* @__PURE__ */ new Set();
68
+ for (const region of value.regions) {
69
+ if (!captureRecord(region) || typeof region.key !== "string" || region.key.length === 0 || keys.has(region.key) || !captureInteger(region.nodeId) || region.nodeId <= 0 || !captureRect(region.frame) || region.frame.width <= 0 || region.frame.height <= 0 || !captureRect(region.source) || region.source.x < 0 || region.source.y < 0 || region.source.width !== region.frame.width || region.source.height !== region.frame.height || region.source.x + region.source.width > value.width || region.source.y + region.source.height > value.height) {
70
+ return false;
71
+ }
72
+ keys.add(region.key);
73
+ }
74
+ return true;
75
+ }
76
+ export {
77
+ RNX_SCREEN_CAPTURE_VERSION,
78
+ isRnxCaptureRegionAtlas,
79
+ isRnxScreenCapture
80
+ };
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;
@@ -0,0 +1,32 @@
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
+ "use strict";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/cloud-contract.ts
23
+ var cloud_contract_exports = {};
24
+ __export(cloud_contract_exports, {
25
+ RNX_CLOUD_MAX_ARTIFACT_BYTES: () => RNX_CLOUD_MAX_ARTIFACT_BYTES
26
+ });
27
+ module.exports = __toCommonJS(cloud_contract_exports);
28
+ var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ RNX_CLOUD_MAX_ARTIFACT_BYTES
32
+ });
@@ -0,0 +1,7 @@
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+
3
+ // src/cloud-contract.ts
4
+ var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
5
+ export {
6
+ RNX_CLOUD_MAX_ARTIFACT_BYTES
7
+ };
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;
@@ -2536,8 +2536,8 @@ var device = {
2536
2536
  return screenshotPath;
2537
2537
  },
2538
2538
  // record the SootSim canvas via the engine's headless recorder
2539
- // (window.__sootsimRecorder — @sootsim/plugin-recording). this is the
2540
- // SAME code path `sootsim record video` drives, NOT the rail-button
2539
+ // (window.__sootsimRecorder — @rnx/plugin-recording). this is the
2540
+ // SAME code path `rnx record video` drives, NOT the rail-button
2541
2541
  // path (SootSim.bridges.startRecording wires the dialog state machine
2542
2542
  // and never stashes the resulting blob into __sootsimRecorder.lastBlob,
2543
2543
  // which is what getBlobBase64 streams from).
@@ -2567,7 +2567,7 @@ var device = {
2567
2567
  }
2568
2568
  },
2569
2569
  // stop the headless recorder, stream the resulting blob in chunks (same
2570
- // protocol as `sootsim record`), and write the webm to outPath.
2570
+ // protocol as `rnx record`), and write the webm to outPath.
2571
2571
  async stopAndSaveBridgeRecording(outPath) {
2572
2572
  const page = getPage();
2573
2573
  const stopResult = await page.evaluate(async () => {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;
@@ -33,6 +33,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  var home_paths_exports = {};
34
34
  __export(home_paths_exports, {
35
35
  ACTIVE_RUNTIME_FILE: () => ACTIVE_RUNTIME_FILE,
36
+ CLI_UPDATE_FILE: () => CLI_UPDATE_FILE,
36
37
  CONFIG_FILE: () => CONFIG_FILE,
37
38
  DAEMON_HEARTBEAT_STALE_MS: () => DAEMON_HEARTBEAT_STALE_MS,
38
39
  DAEMON_LOCKFILE: () => DAEMON_LOCKFILE,
@@ -43,6 +44,7 @@ __export(home_paths_exports, {
43
44
  cacheDir: () => cacheDir,
44
45
  cameraFixturesDir: () => cameraFixturesDir,
45
46
  claimDaemonLockfile: () => claimDaemonLockfile,
47
+ cliUpdateFilePath: () => cliUpdateFilePath,
46
48
  configFilePath: () => configFilePath,
47
49
  consumeRuntimeUpgradeNotice: () => consumeRuntimeUpgradeNotice,
48
50
  daemonAppBundlePath: () => daemonAppBundlePath,
@@ -94,6 +96,7 @@ var ACTIVE_RUNTIME_FILE = "active";
94
96
  var DAEMON_LOCKFILE = "daemon.json";
95
97
  var DEV_BRIDGES_DIR = "dev-bridges";
96
98
  var CONFIG_FILE = "config.json";
99
+ var CLI_UPDATE_FILE = "cli-update.json";
97
100
  var DAEMON_HEARTBEAT_STALE_MS = 3e4;
98
101
  function rnxHomeDir() {
99
102
  const override = process.env[RNX_HOME_ENV];
@@ -172,6 +175,9 @@ function devBridgeLockfilePath(bridgePort) {
172
175
  function configFilePath() {
173
176
  return import_node_path.default.join(rnxHomeDir(), CONFIG_FILE);
174
177
  }
178
+ function cliUpdateFilePath() {
179
+ return import_node_path.default.join(rnxHomeDir(), CLI_UPDATE_FILE);
180
+ }
175
181
  function readSharedConfig() {
176
182
  try {
177
183
  const raw = import_node_fs.default.readFileSync(configFilePath(), "utf8");
@@ -561,6 +567,7 @@ function removeDevBridgeLockfile(owner) {
561
567
  // Annotate the CommonJS export names for ESM import in node:
562
568
  0 && (module.exports = {
563
569
  ACTIVE_RUNTIME_FILE,
570
+ CLI_UPDATE_FILE,
564
571
  CONFIG_FILE,
565
572
  DAEMON_HEARTBEAT_STALE_MS,
566
573
  DAEMON_LOCKFILE,
@@ -571,6 +578,7 @@ function removeDevBridgeLockfile(owner) {
571
578
  cacheDir,
572
579
  cameraFixturesDir,
573
580
  claimDaemonLockfile,
581
+ cliUpdateFilePath,
574
582
  configFilePath,
575
583
  consumeRuntimeUpgradeNotice,
576
584
  daemonAppBundlePath,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;
@@ -3787,7 +3787,7 @@ async function openUrl(url, options = {}) {
3787
3787
  var import_node_fs11 = __toESM(require("node:fs"), 1);
3788
3788
  var import_node_path11 = __toESM(require("node:path"), 1);
3789
3789
 
3790
- // ../contrast-harness/src/planeProtocol.ts
3790
+ // ../rnx-box/src/planeProtocol.ts
3791
3791
  var PLANE_FLAG_READ_ONLY = 1;
3792
3792
  var PLANE_FLAG_BINARY = 2;
3793
3793
  function encodeBase64(bytes) {
@@ -3893,9 +3893,11 @@ var CheckoutFilePlane = class {
3893
3893
  // long a wedged git is waited on, never whether it is waited on, so proving
3894
3894
  // the kill does not have to cost the production deadline.
3895
3895
  listTimeoutMs;
3896
+ trackedOnly;
3896
3897
  constructor(root, options = {}) {
3897
3898
  this.root = import_node_path10.default.resolve(root);
3898
3899
  this.listTimeoutMs = options.listTimeoutMs ?? LIST_FILES_TIMEOUT_MS;
3900
+ this.trackedOnly = options.trackedOnly ?? false;
3899
3901
  }
3900
3902
  index() {
3901
3903
  return this.entries;
@@ -3903,7 +3905,8 @@ var CheckoutFilePlane = class {
3903
3905
  async refresh() {
3904
3906
  let stdout;
3905
3907
  try {
3906
- stdout = (0, import_node_child_process4.execFileSync)("git", ["ls-files", "-co", "--exclude-standard", "-z"], {
3908
+ const args = this.trackedOnly ? ["ls-files", "-z"] : ["ls-files", "-co", "--exclude-standard", "-z"];
3909
+ stdout = (0, import_node_child_process4.execFileSync)("git", args, {
3907
3910
  cwd: this.root,
3908
3911
  encoding: "utf8",
3909
3912
  maxBuffer: 64 * 1024 * 1024,
@@ -3923,7 +3926,7 @@ var CheckoutFilePlane = class {
3923
3926
  }
3924
3927
  if (stdout.length === 0) {
3925
3928
  throw new CheckoutRequiresGitError(
3926
- `git listed no files in ${this.root}. either git tracks nothing there and nothing untracked is visible to it, or this machine could not read the child process's output.`
3929
+ `git listed no ${this.trackedOnly ? "tracked " : ""}files in ${this.root}. either the checkout contains no eligible files, or this machine could not read the child process's output.`
3927
3930
  );
3928
3931
  }
3929
3932
  const next = /* @__PURE__ */ new Map();
@@ -4613,8 +4616,8 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
4613
4616
  static USER_BOOT_LEASE_TTL_MS = 6e4;
4614
4617
  static SIM_RECONNECT_TTL_MS = 3e4;
4615
4618
  // abandoned-tab GC. the ws heartbeat only reaps sims whose socket went
4616
- // dead — but a background tab from a prior `sootsim open` / QA / test run
4617
- // keeps its socket alive (the page still pongs) forever, so `sootsim list`
4619
+ // dead — but a background tab from a prior `rnx open` / QA / test run
4620
+ // keeps its socket alive (the page still pongs) forever, so `rnx list`
4618
4621
  // accretes dozens of zombie sims that all time out on every command (QA
4619
4622
  // F21-3, carried F19-2). reap a sim only when it is provably nobody's:
4620
4623
  // not primary, not user-focused, no CLI attached, no active lease, and no
@@ -4622,7 +4625,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
4622
4625
  // terminal 4001 code, so the client closes the abandoned window instead
4623
4626
  // of reconnecting the zombie straight back in.
4624
4627
  static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
4625
- // automation sims (spawned by the playwright driver: `sootsim open --driver
4628
+ // automation sims (spawned by the playwright driver: `rnx open --driver
4626
4629
  // playwright`, the factory/screenshot capture path — `meta.sootsimHostDriver
4627
4630
  // === 'playwright'`) are unattended one-shot browsers, never a human's tab. a
4628
4631
  // capture run opens one per slide/app/retry and the 30-min human/dev TTL lets
@@ -4652,7 +4655,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
4652
4655
  // dropped, sim crashed) leave their server-side WebSocket sitting "open"
4653
4656
  // forever. ping every WS_HEARTBEAT_INTERVAL_MS; if the previous round's
4654
4657
  // ping was never answered, terminate(). that fires 'close' which runs the
4655
- // sim-cleanup path and stops `sootsim list` from showing 8 zombie
4658
+ // sim-cleanup path and stops `rnx list` from showing 8 zombie
4656
4659
  // sims that all time out on every command.
4657
4660
  wsHeartbeatTimer = null;
4658
4661
  wsIsAlive = /* @__PURE__ */ new WeakMap();
@@ -5856,7 +5859,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5856
5859
  this.sweepRestorableSims(now);
5857
5860
  this.reapIdleSims(now);
5858
5861
  }
5859
- // GC abandoned sims so `sootsim list` stays usable across long dev / QA /
5862
+ // GC abandoned sims so `rnx list` stays usable across long dev / QA /
5860
5863
  // test sessions (F21-3). conservative on purpose: a sim is only reaped
5861
5864
  // when every "someone cares about this" signal is absent.
5862
5865
  //
@@ -5872,7 +5875,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5872
5875
  // using is the primary and/or holds a fresh user-active lease; one that is
5873
5876
  // none of those and idle past the TTL is abandoned regardless of a stale
5874
5877
  // focus flag.
5875
- // automation sims are spawned by the playwright driver (`sootsim open
5878
+ // automation sims are spawned by the playwright driver (`rnx open
5876
5879
  // --driver playwright`, the factory/screenshot capture path), which tags them
5877
5880
  // with `meta.sootsimHostDriver === 'playwright'` via the host's addInitScript.
5878
5881
  // they are unattended one-shot browsers, never a human's tab, so they get a
@@ -6375,6 +6378,8 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
6375
6378
  return "evaluated page state";
6376
6379
  case "screenshot":
6377
6380
  return "captured screenshot";
6381
+ case "capture":
6382
+ return "captured app screen";
6378
6383
  case "tap":
6379
6384
  return "sent tap event";
6380
6385
  case "keyboard":
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/host/fetch-proxy-overrides.ts
4
4
  var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.381 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.382 | (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;