rnxsim 0.1.407 → 0.1.409
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.
- package/README.md +11 -10
- package/cli/bin.ts +16 -643
- package/cli/commands/assert.ts +6 -6
- package/cli/commands/box/rnx-command.ts +3 -11
- package/cli/commands/control.ts +3 -9
- package/cli/commands/daemon-mac-app.ts +5 -11
- package/cli/commands/daemon.ts +63 -113
- package/cli/drivers/playwright-provisioning.ts +33 -29
- package/cli/drivers/playwright-sim-host.ts +501 -0
- package/cli/drivers/playwright.ts +35 -522
- package/cli/hints.ts +2 -4
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +28 -39
- package/cli/main.ts +645 -0
- package/cli/outbound-endpoints.ts +8 -0
- package/cli/self-invocation.ts +34 -0
- package/dist-lib/agent-daemon-client.cjs +35 -25
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +35 -25
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +2 -2
- package/dist-lib/capture-contract.mjs +2 -2
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -4
- package/dist-lib/cloud-contract.mjs +1 -3
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +25 -15
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2 -2
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +134 -608
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/agent-daemon-client.ts +2 -2
- package/src/agent-sessions.ts +29 -24
- package/src/capture-contract.ts +3 -0
- package/src/cloud-contract.ts +0 -1
- package/src/vite-plugin.ts +62 -0
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.409 | (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
|
@@ -365,12 +365,12 @@ export async function ensureDaemonRunning(
|
|
|
365
365
|
'DEV_HOST_REFUSED',
|
|
366
366
|
)
|
|
367
367
|
}
|
|
368
|
-
const {
|
|
368
|
+
const { executable, prefixArgs } = resolveSootsimInvocation()
|
|
369
369
|
const args = [...prefixArgs, 'serve', '--quiet']
|
|
370
370
|
if (port !== DEFAULT_SOOTSIM_BRIDGE_PORT) {
|
|
371
371
|
args.push('--port', String(port))
|
|
372
372
|
}
|
|
373
|
-
const child = spawn(
|
|
373
|
+
const child = spawn(executable, args, {
|
|
374
374
|
detached: true,
|
|
375
375
|
stdio: 'ignore',
|
|
376
376
|
env: process.env,
|
package/src/agent-sessions.ts
CHANGED
|
@@ -11,6 +11,8 @@ import { randomUUID } from 'node:crypto'
|
|
|
11
11
|
import fs, { constants as fsConstants } from 'node:fs'
|
|
12
12
|
import path from 'node:path'
|
|
13
13
|
import readline from 'node:readline'
|
|
14
|
+
import { rnxSelfInvocation, type RnxSelfInvocation } from '../cli/self-invocation.ts'
|
|
15
|
+
import { IS_STANDALONE } from '../cli/standalone.ts'
|
|
14
16
|
import { parseAgentEventLine, type AgentEvent } from './agent-events.ts'
|
|
15
17
|
import { encodeAgentPromptEnvelope, type AgentPromptEnvelope } from './agent-prompt.ts'
|
|
16
18
|
import {
|
|
@@ -65,21 +67,27 @@ export function pidIsAlive(pid: number | undefined, sessionId?: string): boolean
|
|
|
65
67
|
|
|
66
68
|
// --- invocation resolution ---
|
|
67
69
|
|
|
68
|
-
/**
|
|
70
|
+
/** locate the rnx CLI so this process can run a subcommand of it. callers
|
|
71
|
+
* range from the CLI itself to electron main and the vite-plugin daemon.
|
|
69
72
|
* priority:
|
|
70
73
|
* 1. RNX_BIN env var (explicit override)
|
|
71
|
-
* 2.
|
|
72
|
-
* 3.
|
|
74
|
+
* 2. this process already IS the CLI — `rnxSelfInvocation` owns that answer
|
|
75
|
+
* 3. electron prod: bundled binary under process.resourcesPath/bin/
|
|
76
|
+
* 4. workspace build artifacts (dist-bin/<binary> or dist-cli/bin.js)
|
|
73
77
|
* — shared between electron dev, the vite-plugin-hosted daemon, and
|
|
74
78
|
* any other node process that isn't launched with the CLI entry
|
|
75
79
|
* script directly (e.g. argv[1] = .../node_modules/.bin/vite).
|
|
76
|
-
*
|
|
77
|
-
* 5. CLI standalone: argv[0] is the compiled binary, no prefix needed
|
|
80
|
+
* 5. CLI dev (argv[1] points at the entry script): re-use argv[0] + argv[1]
|
|
78
81
|
*/
|
|
79
|
-
export function resolveSootsimInvocation():
|
|
82
|
+
export function resolveSootsimInvocation(): RnxSelfInvocation {
|
|
80
83
|
if (process.env.RNX_BIN) {
|
|
81
|
-
return {
|
|
84
|
+
return { executable: process.env.RNX_BIN, prefixArgs: [] }
|
|
82
85
|
}
|
|
86
|
+
// the compiled standalone binary cannot be found through argv: bun reports
|
|
87
|
+
// argv[0] as the literal string "bun" and argv[1] as a path inside its
|
|
88
|
+
// virtual filesystem, so both fall through to spawning a `bun` that a
|
|
89
|
+
// shell-installed user does not have.
|
|
90
|
+
if (IS_STANDALONE) return rnxSelfInvocation()
|
|
83
91
|
// electron prod: packaged binary lives under Resources/bin/.
|
|
84
92
|
if (process.versions.electron) {
|
|
85
93
|
const resourcesPath = (process as NodeJS.Process & { resourcesPath?: string })
|
|
@@ -90,7 +98,7 @@ export function resolveSootsimInvocation(): { cmd: string; prefixArgs: string[]
|
|
|
90
98
|
path.join(resourcesPath, 'bin', `sootsim-${process.platform}-${process.arch}`),
|
|
91
99
|
]
|
|
92
100
|
for (const c of candidates) {
|
|
93
|
-
if (fs.existsSync(c)) return {
|
|
101
|
+
if (fs.existsSync(c)) return { executable: c, prefixArgs: [] }
|
|
94
102
|
}
|
|
95
103
|
}
|
|
96
104
|
}
|
|
@@ -108,23 +116,20 @@ export function resolveSootsimInvocation(): { cmd: string; prefixArgs: string[]
|
|
|
108
116
|
// script — `.js`/`.ts`/`.mjs` etc. launching vite gives us argv[1] =
|
|
109
117
|
// `…/node_modules/.bin/vite` (no extension), which would make us try
|
|
110
118
|
// to run agent-wrapper under the vite shim and silently fail.
|
|
111
|
-
const argv0 = process.argv[0]
|
|
112
119
|
const argv1 = process.argv[1]
|
|
113
120
|
if (argv1 && /\.(ts|tsx|mjs|cjs|js)$/.test(argv1)) {
|
|
114
|
-
return {
|
|
121
|
+
return { executable: process.argv[0], prefixArgs: [argv1] }
|
|
115
122
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
return { cmd: argv0, prefixArgs: [] }
|
|
123
|
+
// anything else — a bin shim such as `…/node_modules/.bin/vite`, or no
|
|
124
|
+
// argv[1] at all — names no rnx entry script, so say so instead of
|
|
125
|
+
// spawning the host runtime with no arguments.
|
|
126
|
+
throw new Error(
|
|
127
|
+
'rnx CLI not found. set RNX_BIN to the path of the rnx binary, ' +
|
|
128
|
+
'or build the workspace CLI via `bun run --cwd packages/sootsim build:cli`.',
|
|
129
|
+
)
|
|
125
130
|
}
|
|
126
131
|
|
|
127
|
-
function tryWorkspaceSootsim():
|
|
132
|
+
function tryWorkspaceSootsim(): RnxSelfInvocation | null {
|
|
128
133
|
try {
|
|
129
134
|
const sootsimDir = resolveSootsimPackageDir()
|
|
130
135
|
if (!sootsimDir) return null
|
|
@@ -132,7 +137,7 @@ function tryWorkspaceSootsim(): { cmd: string; prefixArgs: string[] } | null {
|
|
|
132
137
|
process.platform === 'win32' ? 'windows' : process.platform
|
|
133
138
|
}-${process.arch}${process.platform === 'win32' ? '.exe' : ''}`
|
|
134
139
|
const distBinary = path.join(sootsimDir, 'dist-bin', binaryName)
|
|
135
|
-
if (fs.existsSync(distBinary)) return {
|
|
140
|
+
if (fs.existsSync(distBinary)) return { executable: distBinary, prefixArgs: [] }
|
|
136
141
|
const distBin = path.join(sootsimDir, 'dist-cli', 'bin.js')
|
|
137
142
|
if (fs.existsSync(distBin)) {
|
|
138
143
|
try {
|
|
@@ -148,7 +153,7 @@ function tryWorkspaceSootsim(): { cmd: string; prefixArgs: string[] } | null {
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
} catch {}
|
|
151
|
-
return {
|
|
156
|
+
return { executable: process.execPath, prefixArgs: [distBin] }
|
|
152
157
|
}
|
|
153
158
|
return null
|
|
154
159
|
} catch {
|
|
@@ -368,7 +373,7 @@ export async function startSession(opts: StartSessionOpts): Promise<StartSession
|
|
|
368
373
|
fs.chmodSync(transcriptDir, 0o700)
|
|
369
374
|
} catch {}
|
|
370
375
|
|
|
371
|
-
const {
|
|
376
|
+
const { executable, prefixArgs } = resolveSootsimInvocation()
|
|
372
377
|
const wrapperArgs = [
|
|
373
378
|
...prefixArgs,
|
|
374
379
|
'agent-wrapper',
|
|
@@ -394,7 +399,7 @@ export async function startSession(opts: StartSessionOpts): Promise<StartSession
|
|
|
394
399
|
wrapperArgs.push('--claude-session-uuid', claudeSessionUuid)
|
|
395
400
|
}
|
|
396
401
|
|
|
397
|
-
const child = spawn(
|
|
402
|
+
const child = spawn(executable, wrapperArgs, {
|
|
398
403
|
detached: true,
|
|
399
404
|
stdio: 'ignore',
|
|
400
405
|
env: {
|
package/src/capture-contract.ts
CHANGED
|
@@ -137,6 +137,8 @@ export interface RnxCaptureTree {
|
|
|
137
137
|
viewport: { width: number; height: number }
|
|
138
138
|
rootNodeId: number
|
|
139
139
|
nodes: RnxCaptureNode[]
|
|
140
|
+
/** reconciler commit shared by semantic, layout, and visual evidence */
|
|
141
|
+
commitRevision?: number
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
export interface RnxCaptureVisualEvidence {
|
|
@@ -511,6 +513,7 @@ export function isRnxScreenCapture(value: unknown): value is RnxScreenCapture {
|
|
|
511
513
|
captureInteger(tree.viewport.height) &&
|
|
512
514
|
tree.viewport.height > 0 &&
|
|
513
515
|
captureInteger(tree.rootNodeId) &&
|
|
516
|
+
(tree.commitRevision === undefined || captureInteger(tree.commitRevision)) &&
|
|
514
517
|
Array.isArray(tree.nodes) &&
|
|
515
518
|
tree.nodes.every(captureNode) &&
|
|
516
519
|
(visual === undefined ||
|
package/src/cloud-contract.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { BridgeCommandType } from './bridge-contract'
|
|
2
2
|
|
|
3
3
|
export const RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024
|
|
4
|
-
export const RNX_CLOUD_DESIGN_PARALLEL_JOB_LIMIT = 16
|
|
5
4
|
export const RNX_CLOUD_DESIGN_MAX_STORAGE_ENTRIES = 256
|
|
6
5
|
export const RNX_CLOUD_DESIGN_MAX_STORAGE_BYTES = 1024 * 1024
|
|
7
6
|
|
package/src/vite-plugin.ts
CHANGED
|
@@ -466,9 +466,71 @@ export function engineShellWorkerPlugins(): Plugin[] {
|
|
|
466
466
|
keyboardControllerBindingsRedirect(),
|
|
467
467
|
rnghUpstreamInternalResolvePlugin(),
|
|
468
468
|
workletsBabelTransform(() => true),
|
|
469
|
+
workerBootChunkPlugin(ENGINE_WORKER_BOOT_CLOSURES),
|
|
469
470
|
]
|
|
470
471
|
}
|
|
471
472
|
|
|
473
|
+
// a worker cannot modulepreload, so every static level under its
|
|
474
|
+
// implementation root and every dynamic import on its boot path is a serial
|
|
475
|
+
// round trip before the worker is ready. this plugin bundles each declared
|
|
476
|
+
// worker into one file and fails the build when that file grows past its byte
|
|
477
|
+
// cap, so a worker feature cannot silently add startup bytes.
|
|
478
|
+
//
|
|
479
|
+
// the entries stay export-free and import-free so webkit keeps the one-way
|
|
480
|
+
// dynamic boundary (see shell-worker-entry.ts); with every chunk inlined no
|
|
481
|
+
// other file can import the worker script, so nothing can evaluate it twice.
|
|
482
|
+
// inlined dynamic roots still evaluate at their `import()` (the reanimated
|
|
483
|
+
// passthrough must install before upstream reanimated, the worklet runtime
|
|
484
|
+
// must exist before shell-in-worker): with code splitting off rolldown wraps
|
|
485
|
+
// every dynamic-import target in an init function that runs on first import.
|
|
486
|
+
// shell-worker.ts throws at init if a bundle ever hoists one of them.
|
|
487
|
+
export type WorkerBootClosure = {
|
|
488
|
+
// substring of the worker entry module id this applies to
|
|
489
|
+
entry: string
|
|
490
|
+
// byte cap on the rendered worker file; raise it in the same change that
|
|
491
|
+
// adds worker code, never silently
|
|
492
|
+
maxBytes: number
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const ENGINE_WORKER_BOOT_CLOSURES: WorkerBootClosure[] = [
|
|
496
|
+
{ entry: 'src/render-worker/shell-worker-entry.ts', maxBytes: 3_480_000 },
|
|
497
|
+
{ entry: 'src/render-worker/compositor-worker-entry.ts', maxBytes: 1_255_000 },
|
|
498
|
+
]
|
|
499
|
+
|
|
500
|
+
export function workerBootChunkPlugin(closures: WorkerBootClosure[]): Plugin {
|
|
501
|
+
let closure: WorkerBootClosure | null = null
|
|
502
|
+
return {
|
|
503
|
+
name: 'sootsim-worker-boot-chunk',
|
|
504
|
+
apply: 'build',
|
|
505
|
+
options(inputOptions) {
|
|
506
|
+
const input = inputOptions.input
|
|
507
|
+
closure =
|
|
508
|
+
typeof input === 'string'
|
|
509
|
+
? (closures.find((candidate) => input.includes(candidate.entry)) ?? null)
|
|
510
|
+
: null
|
|
511
|
+
},
|
|
512
|
+
outputOptions(options) {
|
|
513
|
+
if (!closure) return null
|
|
514
|
+
return { ...options, inlineDynamicImports: true }
|
|
515
|
+
},
|
|
516
|
+
generateBundle(_options, bundle) {
|
|
517
|
+
if (!closure) return
|
|
518
|
+
const chunks = Object.values(bundle).filter((output) => output.type === 'chunk')
|
|
519
|
+
if (chunks.length !== 1 || !chunks[0].isEntry) {
|
|
520
|
+
this.error(
|
|
521
|
+
`worker ${closure.entry}: expected one inlined chunk, got ${chunks.map((chunk) => chunk.fileName).join(', ')}`,
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
const bytes = Buffer.byteLength(chunks[0].code)
|
|
525
|
+
if (bytes > closure.maxBytes) {
|
|
526
|
+
this.error(
|
|
527
|
+
`worker ${closure.entry}: ${chunks[0].fileName} is ${bytes} bytes, over the ${closure.maxBytes} byte cap; raise the cap in the same change that grows the worker`,
|
|
528
|
+
)
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
472
534
|
// react-native-keyboard-controller is pure-JS for everything except its
|
|
473
535
|
// native-event seam (`bindings.ts` / `bindings.native.ts`) and RN platform
|
|
474
536
|
// `findNodeHandle` resolution. let upstream's components, hooks, animated
|