rnxsim 0.1.369 → 0.1.370
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/cli/auth.ts +2 -1
- package/cli/bin.ts +283 -273
- package/cli/commands/app-fonts.ts +3 -2
- package/cli/commands/assert.ts +8 -7
- package/cli/commands/auth.ts +2 -1
- package/cli/commands/box/checkout-plane.ts +45 -16
- package/cli/commands/config.ts +2 -1
- package/cli/commands/control.ts +37 -33
- package/cli/commands/daemon.ts +22 -21
- package/cli/commands/debug.ts +17 -15
- package/cli/commands/detox.ts +5 -4
- package/cli/commands/device.ts +6 -5
- package/cli/commands/electron.ts +6 -5
- package/cli/commands/flow.ts +12 -11
- package/cli/commands/inspect/find.ts +2 -1
- package/cli/commands/inspect/keyboard.ts +2 -1
- package/cli/commands/inspect/sleep.ts +2 -1
- package/cli/commands/inspect/wait-event.ts +4 -3
- package/cli/commands/inspect/wait-idle.ts +2 -1
- package/cli/commands/inspect/wait-ready.ts +3 -2
- package/cli/commands/inspect/wait-selector.ts +4 -3
- package/cli/commands/inspect/wait.ts +2 -1
- package/cli/commands/inspect.ts +82 -80
- package/cli/commands/install-desktop.ts +5 -4
- package/cli/commands/login.ts +3 -2
- package/cli/commands/mode.ts +2 -1
- package/cli/commands/record.ts +38 -37
- package/cli/commands/runtime.ts +9 -8
- package/cli/commands/screenshot-layers.ts +4 -3
- package/cli/commands/screenshot-mode.ts +2 -1
- package/cli/commands/screenshot.ts +8 -7
- package/cli/commands/screenshots-capture.ts +2 -1
- package/cli/commands/serve.ts +5 -4
- package/cli/commands/shell-boolean-mode.ts +2 -1
- package/cli/commands/skills.ts +11 -10
- package/cli/commands/telemetry.ts +2 -1
- package/cli/commands/three-mode.ts +2 -1
- package/cli/commands/timeline.ts +4 -3
- package/cli/commands/upload.ts +14 -13
- package/cli/commands/what-happened.ts +2 -1
- package/cli/recording-access.ts +6 -5
- package/cli/run-rnx.ts +140 -0
- package/dist-cli/bin.js +6 -6
- package/dist-cli/chunks/{agent-OUUFWDLF.js → agent-3R4424LW.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-7BE7DR4R.js → agent-wrapper-4PPWZWSY.js} +2 -2
- package/dist-cli/chunks/app-fonts-KYXB6CXQ.js +4 -0
- package/dist-cli/chunks/{assert-I3CMRNS7.js → assert-7EZOWGYQ.js} +11 -11
- package/dist-cli/chunks/auth-L7M36H6C.js +12 -0
- package/dist-cli/chunks/{beta-BHSKY4K4.js → beta-FKAF6YWJ.js} +2 -2
- package/dist-cli/chunks/{box-3CVWXVTT.js → box-5Y5VBMHV.js} +342 -342
- package/dist-cli/chunks/{camera-MNK73TYV.js → camera-XHF2RPFG.js} +2 -2
- package/dist-cli/chunks/{chunk-NPVEBXU3.js → chunk-2FOGXVOK.js} +2 -2
- package/dist-cli/chunks/{chunk-UDXQCEJU.js → chunk-3BG6UCQY.js} +2 -2
- package/dist-cli/chunks/{chunk-V7I4CTAX.js → chunk-3SOPYG7S.js} +2 -2
- package/dist-cli/chunks/{chunk-QE5MC4V3.js → chunk-3UXXYJVD.js} +1 -1
- package/dist-cli/chunks/{chunk-EKAEEWC2.js → chunk-5BR33NAZ.js} +1 -1
- package/dist-cli/chunks/{chunk-FGGESBWD.js → chunk-5RKRVS5A.js} +2 -2
- package/dist-cli/chunks/{chunk-MXWME7ET.js → chunk-64JAEJ6N.js} +1 -1
- package/dist-cli/chunks/{chunk-AKJYEX54.js → chunk-6A6L3VJR.js} +2 -2
- package/dist-cli/chunks/chunk-6GPS7U4X.js +74 -0
- package/dist-cli/chunks/{chunk-OROUEG22.js → chunk-6S5LJV2O.js} +2 -2
- package/dist-cli/chunks/{chunk-ZW6JXEVX.js → chunk-6W4HIWC7.js} +2 -2
- package/dist-cli/chunks/{chunk-6BMM6OCW.js → chunk-72S5FCBY.js} +2 -2
- package/dist-cli/chunks/{chunk-TBK5UXW2.js → chunk-7C7TJYZ3.js} +2 -2
- package/dist-cli/chunks/{chunk-D6MGELKZ.js → chunk-AALKIAUZ.js} +1 -1
- package/dist-cli/chunks/{chunk-WUR4FXWT.js → chunk-ARMXC3C3.js} +25 -25
- package/dist-cli/chunks/chunk-AVJBT5LF.js +4 -0
- package/dist-cli/chunks/chunk-BMIJZNKD.js +28 -0
- package/dist-cli/chunks/{chunk-N5KDDGV6.js → chunk-C7BA5CCM.js} +2 -2
- package/dist-cli/chunks/{chunk-F4OTMARL.js → chunk-CMVRTZ5G.js} +2 -2
- package/dist-cli/chunks/chunk-D24EOJ4C.js +24 -0
- package/dist-cli/chunks/{chunk-A56GQVNF.js → chunk-D2GZASRV.js} +1 -1
- package/dist-cli/chunks/{chunk-IYPMULI7.js → chunk-DHYTRCIP.js} +2 -2
- package/dist-cli/chunks/{chunk-X3PEDNLV.js → chunk-DMHSD6YJ.js} +2 -2
- package/dist-cli/chunks/{chunk-YPBDPVLR.js → chunk-DUXHYPBP.js} +2 -2
- package/dist-cli/chunks/{chunk-4SCVGBOX.js → chunk-DXV37CJN.js} +1 -1
- package/dist-cli/chunks/{chunk-H2GB2PLY.js → chunk-EOIBLKZO.js} +2 -2
- package/dist-cli/chunks/{chunk-UQJY6O72.js → chunk-EQ3OE2AV.js} +1 -1
- package/dist-cli/chunks/{chunk-3454VMHD.js → chunk-EWSWOWXK.js} +2 -2
- package/dist-cli/chunks/{chunk-FHRG772G.js → chunk-FA75F34Z.js} +1 -1
- package/dist-cli/chunks/{chunk-LU3AHE6T.js → chunk-FK4JSTZ3.js} +2 -2
- package/dist-cli/chunks/{chunk-AJJCYLBC.js → chunk-GJRLPJQL.js} +2 -2
- package/dist-cli/chunks/{chunk-WGE2P25F.js → chunk-GRO74J2X.js} +1 -1
- package/dist-cli/chunks/chunk-H5X5FJ63.js +99 -0
- package/dist-cli/chunks/chunk-HEKHLQ3B.js +497 -0
- package/dist-cli/chunks/chunk-HQQTS2CB.js +30 -0
- package/dist-cli/chunks/{chunk-DKSZZABN.js → chunk-I52NT6VG.js} +1 -1
- package/dist-cli/chunks/{chunk-A72MIIJI.js → chunk-IDLFVRPN.js} +1 -1
- package/dist-cli/chunks/{chunk-6F3WOWFC.js → chunk-JZLDHPB7.js} +2 -2
- package/dist-cli/chunks/{chunk-ZNNE5MAV.js → chunk-LIMWG54N.js} +1 -1
- package/dist-cli/chunks/{chunk-TTUZ5MCK.js → chunk-LUOHRBJG.js} +1 -1
- package/dist-cli/chunks/{chunk-B5NW4TT3.js → chunk-LXPHL6FO.js} +2 -2
- package/dist-cli/chunks/{chunk-TAC4CEIX.js → chunk-MDCY532E.js} +2 -2
- package/dist-cli/chunks/{chunk-45X3D6CI.js → chunk-NJMU5BN6.js} +1 -1
- package/dist-cli/chunks/{chunk-2APXX4RN.js → chunk-NR2V2ONN.js} +2 -2
- package/dist-cli/chunks/{chunk-JH5KE2OI.js → chunk-NTC46LSA.js} +2 -2
- package/dist-cli/chunks/{chunk-RV76U3EI.js → chunk-O6QLKSAM.js} +10 -10
- package/dist-cli/chunks/{chunk-ZEF57HQO.js → chunk-OJZHECGH.js} +1 -1
- package/dist-cli/chunks/chunk-OTFTMGAL.js +7 -0
- package/dist-cli/chunks/{chunk-RYGQ6LZN.js → chunk-PAUEZO6F.js} +2 -2
- package/dist-cli/chunks/{chunk-CCI3DZKE.js → chunk-PIZXOXBL.js} +2 -2
- package/dist-cli/chunks/{chunk-JLOOLA47.js → chunk-PNOENVMJ.js} +1 -1
- package/dist-cli/chunks/{chunk-YLNSLMQM.js → chunk-Q4MRJ6PO.js} +2 -2
- package/dist-cli/chunks/{chunk-5QFJFASW.js → chunk-RRX52O37.js} +1 -1
- package/dist-cli/chunks/{chunk-FBMNYSSW.js → chunk-U63T6LIQ.js} +1 -1
- package/dist-cli/chunks/{chunk-2PVVIPQS.js → chunk-UFVAAWGZ.js} +1 -1
- package/dist-cli/chunks/{chunk-CZ2HCNRK.js → chunk-VVQCZ42C.js} +1 -1
- package/dist-cli/chunks/{chunk-USHV3QFZ.js → chunk-WFQHT4QD.js} +2 -2
- package/dist-cli/chunks/{chunk-DCPDMF27.js → chunk-WPV4H5S4.js} +2 -2
- package/dist-cli/chunks/{chunk-SSBZA5VZ.js → chunk-X6WQ4YWE.js} +1 -1
- package/dist-cli/chunks/{chunk-VGJLCFSC.js → chunk-YIZGNT7A.js} +1 -1
- package/dist-cli/chunks/{chunk-JXARZBWS.js → chunk-Z2VBSNFI.js} +1 -1
- package/dist-cli/chunks/{chunk-4G4VCT2M.js → chunk-Z3DENGXW.js} +2 -2
- package/dist-cli/chunks/{cleanup-H4XFRMZV.js → cleanup-MXMMJ7JW.js} +2 -2
- package/dist-cli/chunks/cli-version-MLS55UTY.js +4 -0
- package/dist-cli/chunks/{compat-NKGYERLN.js → compat-E6KE5KDI.js} +2 -2
- package/dist-cli/chunks/config-QSLLVZDS.js +13 -0
- package/dist-cli/chunks/{connect-WWWAVVCF.js → connect-QE4VU6GB.js} +2 -2
- package/dist-cli/chunks/control-XD5F6K5T.js +4 -0
- package/dist-cli/chunks/daemon-UN5SE2JO.js +4 -0
- package/dist-cli/chunks/{debug-RO6GLDIM.js → debug-5FG3MBJS.js} +20 -20
- package/dist-cli/chunks/desktop-5EZX7NX5.js +31 -0
- package/dist-cli/chunks/detox-WJGQP5TM.js +52 -0
- package/dist-cli/chunks/device-D7LKCAMS.js +18 -0
- package/dist-cli/chunks/{diagnose-HDRTUPDO.js → diagnose-A3W6ZTGA.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-QP2NYN43.js → disk-cleanup-BDRHX5ZG.js} +2 -2
- package/dist-cli/chunks/{do-chain-6LP6SV5J.js → do-chain-RUJNRPPF.js} +2 -2
- package/dist-cli/chunks/drivers-3NJ5RL6X.js +4 -0
- package/dist-cli/chunks/{env-4XD5D2G6.js → env-U67SQVTV.js} +2 -2
- package/dist-cli/chunks/{film-I5SIXLS5.js → film-XC6UAQ3V.js} +3 -3
- package/dist-cli/chunks/flow-FHZZD3P6.js +4 -0
- package/dist-cli/chunks/help-BYYDUSXF.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-LJV2S4M2.js → hidden-runtime-alias-7S2TNZXG.js} +2 -2
- package/dist-cli/chunks/{home-paths-RFI2QRC3.js → home-paths-LMO5LB4F.js} +2 -2
- package/dist-cli/chunks/inspect-RQCTWDCC.js +4 -0
- package/dist-cli/chunks/install-desktop-GOWXCQUE.js +4 -0
- package/dist-cli/chunks/login-JIU42S4C.js +26 -0
- package/dist-cli/chunks/{logout-DKXZZ6HU.js → logout-JTAWQXZO.js} +2 -2
- package/dist-cli/chunks/{maestro-WKGVVWRA.js → maestro-TYBQYOGB.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-KCK6RK2C.js → maestro-generate-YLAGWVKE.js} +3 -3
- package/dist-cli/chunks/mode-DV24ZRZ6.js +26 -0
- package/dist-cli/chunks/{optional-demo-registry-EUSKBIPP.js → optional-demo-registry-JZH66VIM.js} +2 -2
- package/dist-cli/chunks/{perf-IMZMA5MT.js → perf-LXXJ4EAX.js} +2 -2
- package/dist-cli/chunks/{permissions-SLWXTLH6.js → permissions-KAOVZUPW.js} +2 -2
- package/dist-cli/chunks/{platform-HQ735LAE.js → platform-KW35446W.js} +3 -3
- package/dist-cli/chunks/privacy-MIFE72CG.js +4 -0
- package/dist-cli/chunks/record-EK3ETFHZ.js +72 -0
- package/dist-cli/chunks/report-issue-NW5PCAZF.js +29 -0
- package/dist-cli/chunks/reset-RZ4O5AFJ.js +4 -0
- package/dist-cli/chunks/resolve-target-7R5BNYMM.js +4 -0
- package/dist-cli/chunks/runtime-MZHLSRS6.js +4 -0
- package/dist-cli/chunks/{screenshot-command-HAJB5FHK.js → screenshot-command-TQSPTFT2.js} +11 -11
- package/dist-cli/chunks/screenshot-layers-IZP3L3AQ.js +20 -0
- package/dist-cli/chunks/screenshots-capture-K7LJOVAE.js +42 -0
- package/dist-cli/chunks/{serve-TM46TKFW.js → serve-MMX4WXXG.js} +18 -18
- package/dist-cli/chunks/setup-YFP3KEQZ.js +4 -0
- package/dist-cli/chunks/{sim-client-LQUZSO45.js → sim-client-KLAYIFOC.js} +2 -2
- package/dist-cli/chunks/skills-N4D3POIS.js +50 -0
- package/dist-cli/chunks/{state-RUVM4Z4S.js → state-ES6TFQZF.js} +2 -2
- package/dist-cli/chunks/{storage-GQ33UTYN.js → storage-52DR5V2C.js} +2 -2
- package/dist-cli/chunks/store-HOL45WCI.js +4 -0
- package/dist-cli/chunks/telemetry-BV6OTYPF.js +4 -0
- package/dist-cli/chunks/timeline-NRVNB5JR.js +24 -0
- package/dist-cli/chunks/{upgrade-AZDZLUIT.js → upgrade-LNED5YQ2.js} +2 -2
- package/dist-cli/chunks/upload-RXKHFIBU.js +4 -0
- package/dist-cli/chunks/{version-N3ALB75G.js → version-VEF2DYGG.js} +2 -2
- package/dist-cli/chunks/{web-XPHFZATA.js → web-CGDE6S73.js} +2 -2
- package/dist-cli/chunks/welcome-FT2AMUWW.js +5 -0
- package/dist-cli/chunks/what-happened-FSIDWL32.js +25 -0
- package/dist-cli/chunks/{ws-bridge-RUXOYOU6.js → ws-bridge-QXFQLRE7.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- 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/cli-constants.cjs +1 -1
- 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 +1 -1
- 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 +1 -1
- 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-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 +2 -1
- package/dist-lib/react-native-host-modules.mjs +2 -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 +79 -47
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/react-native-host-modules.ts +1 -0
- package/dist-cli/chunks/app-fonts-66V7TL26.js +0 -4
- package/dist-cli/chunks/auth-3FMWUVJH.js +0 -12
- package/dist-cli/chunks/chunk-3NLB5LCN.js +0 -28
- package/dist-cli/chunks/chunk-5RWUFIZW.js +0 -24
- package/dist-cli/chunks/chunk-COXCR6UU.js +0 -7
- package/dist-cli/chunks/chunk-ROISJKH3.js +0 -99
- package/dist-cli/chunks/chunk-SUHAD6N2.js +0 -30
- package/dist-cli/chunks/chunk-TIB3CTRX.js +0 -497
- package/dist-cli/chunks/chunk-YFZLDFZK.js +0 -74
- package/dist-cli/chunks/cli-version-MJWLDXBW.js +0 -4
- package/dist-cli/chunks/config-WK7467KI.js +0 -13
- package/dist-cli/chunks/control-ESI7IZNN.js +0 -4
- package/dist-cli/chunks/daemon-UCLO27YP.js +0 -4
- package/dist-cli/chunks/desktop-FF34Z5X4.js +0 -31
- package/dist-cli/chunks/detox-Q3CWY5UX.js +0 -52
- package/dist-cli/chunks/device-WN4ZWLES.js +0 -18
- package/dist-cli/chunks/drivers-OR2JPAXD.js +0 -4
- package/dist-cli/chunks/flow-4GWW5DYT.js +0 -4
- package/dist-cli/chunks/help-MIIWOT3C.js +0 -4
- package/dist-cli/chunks/inspect-3ZGNJENJ.js +0 -4
- package/dist-cli/chunks/install-desktop-BYOJVTLS.js +0 -4
- package/dist-cli/chunks/login-GNIFSAFE.js +0 -26
- package/dist-cli/chunks/mode-YVMX7OJY.js +0 -26
- package/dist-cli/chunks/privacy-EDC7PF7G.js +0 -4
- package/dist-cli/chunks/record-N4KTTVDI.js +0 -72
- package/dist-cli/chunks/report-issue-PP752HAD.js +0 -29
- package/dist-cli/chunks/reset-DRMKGVP4.js +0 -4
- package/dist-cli/chunks/resolve-target-7WWI32R3.js +0 -4
- package/dist-cli/chunks/runtime-EKJV2ZVI.js +0 -4
- package/dist-cli/chunks/screenshot-layers-GOCJVM2G.js +0 -20
- package/dist-cli/chunks/screenshots-capture-YYJLYA3V.js +0 -42
- package/dist-cli/chunks/setup-FVPVIYE4.js +0 -4
- package/dist-cli/chunks/skills-V5TE57FN.js +0 -50
- package/dist-cli/chunks/store-IKNBDDKM.js +0 -4
- package/dist-cli/chunks/telemetry-2ZVU6WLK.js +0 -4
- package/dist-cli/chunks/timeline-LP7DMJYT.js +0 -24
- package/dist-cli/chunks/upload-DFQK2Q7X.js +0 -4
- package/dist-cli/chunks/welcome-2NFYLWLJ.js +0 -5
- package/dist-cli/chunks/what-happened-EJ5PHKT7.js +0 -25
package/cli/commands/assert.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// 2 misuse — bad flags, unknown verb (treated as bad by bisect)
|
|
15
15
|
|
|
16
16
|
import { spawn } from 'child_process'
|
|
17
|
+
import { rnxExit } from '../run-rnx'
|
|
17
18
|
|
|
18
19
|
// READ_VERBS lists every command whose stdout we know is valid JSON under
|
|
19
20
|
// --json. keeping this explicit means `sootsim assert tap 100 200` fails
|
|
@@ -403,13 +404,13 @@ function runJq(expr: string, payload: unknown): Promise<string> {
|
|
|
403
404
|
export async function runAssert(rawArgs: string[]): Promise<void> {
|
|
404
405
|
if (rawArgs[0] === '--help' || rawArgs[0] === '-h' || rawArgs.length === 0) {
|
|
405
406
|
printHelp()
|
|
406
|
-
|
|
407
|
+
rnxExit(rawArgs.length === 0 ? 2 : 0)
|
|
407
408
|
}
|
|
408
409
|
|
|
409
410
|
const parsed = parseAssertArgs(rawArgs)
|
|
410
411
|
if ('error' in parsed) {
|
|
411
412
|
process.stderr.write(` assert: ${parsed.error}\n`)
|
|
412
|
-
|
|
413
|
+
rnxExit(2)
|
|
413
414
|
}
|
|
414
415
|
|
|
415
416
|
const { verbArgs, predicates, withinMs, negate, quiet, allowTimeout } = parsed
|
|
@@ -420,7 +421,7 @@ export async function runAssert(rawArgs: string[]): Promise<void> {
|
|
|
420
421
|
` assert: unknown or non-read verb: ${verbArgs.join(' ')}\n` +
|
|
421
422
|
` supported: ${Array.from(READ_VERBS).sort().join(', ')}\n`,
|
|
422
423
|
)
|
|
423
|
-
|
|
424
|
+
rnxExit(2)
|
|
424
425
|
}
|
|
425
426
|
|
|
426
427
|
// default assertion when none given is --exists. matches the common
|
|
@@ -452,7 +453,7 @@ export async function runAssert(rawArgs: string[]): Promise<void> {
|
|
|
452
453
|
const label = exitCode === 1 ? 'fail' : 'skip'
|
|
453
454
|
process.stderr.write(` assert: ${label} — ${lastVerbSkipReason}\n`)
|
|
454
455
|
}
|
|
455
|
-
|
|
456
|
+
rnxExit(exitCode)
|
|
456
457
|
}
|
|
457
458
|
|
|
458
459
|
let allPass = true
|
|
@@ -468,7 +469,7 @@ export async function runAssert(rawArgs: string[]): Promise<void> {
|
|
|
468
469
|
}
|
|
469
470
|
} catch (err: any) {
|
|
470
471
|
if (!quiet) process.stderr.write(` assert: skip — ${err.message}\n`)
|
|
471
|
-
|
|
472
|
+
rnxExit(125)
|
|
472
473
|
}
|
|
473
474
|
|
|
474
475
|
const pass = negate ? !allPass : allPass
|
|
@@ -478,7 +479,7 @@ export async function runAssert(rawArgs: string[]): Promise<void> {
|
|
|
478
479
|
` assert: pass${attempts > 1 ? ` (attempt ${attempts})` : ''} — ${reasons.join('; ')}\n`,
|
|
479
480
|
)
|
|
480
481
|
}
|
|
481
|
-
|
|
482
|
+
rnxExit(0)
|
|
482
483
|
}
|
|
483
484
|
|
|
484
485
|
lastFailReason = reasons.join('; ')
|
|
@@ -491,7 +492,7 @@ export async function runAssert(rawArgs: string[]): Promise<void> {
|
|
|
491
492
|
` assert: fail${attempts > 1 ? ` after ${attempts} attempt(s)` : ''} — ${lastFailReason}\n`,
|
|
492
493
|
)
|
|
493
494
|
}
|
|
494
|
-
|
|
495
|
+
rnxExit(1)
|
|
495
496
|
}
|
|
496
497
|
}
|
|
497
498
|
|
package/cli/commands/auth.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { refreshSharedDesktopAuthSession } from '../../src/auth/shared-session'
|
|
2
2
|
import { resolveCliAuth } from '../auth'
|
|
3
|
+
import { rnxExit } from '../run-rnx'
|
|
3
4
|
|
|
4
5
|
function printHelp(): void {
|
|
5
6
|
console.log(`
|
|
@@ -55,5 +56,5 @@ export async function runAuth(args: string[]): Promise<void> {
|
|
|
55
56
|
|
|
56
57
|
console.error(` unknown auth command: ${sub}`)
|
|
57
58
|
printHelp()
|
|
58
|
-
|
|
59
|
+
rnxExit(1)
|
|
59
60
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// ProjectFilePlane over a real local checkout — the
|
|
2
|
-
// seam Contrast's browser
|
|
3
|
-
//
|
|
4
|
-
// represent faithfully rather than round-tripping it through a string.
|
|
1
|
+
// ProjectFilePlane over a real local checkout — the second host behind the
|
|
2
|
+
// seam Contrast's browser already implements. writes land on the user's actual
|
|
3
|
+
// disk, so nothing here converts content: the plane reads and writes bytes.
|
|
5
4
|
//
|
|
6
5
|
// the file set comes from `git ls-files -co --exclude-standard`, which is the
|
|
7
6
|
// project's own definition of what belongs to it. a hardcoded skip list was
|
|
@@ -20,14 +19,14 @@ const execFileAsync = promisify(execFile)
|
|
|
20
19
|
|
|
21
20
|
export class CheckoutRequiresGitError extends Error {}
|
|
22
21
|
|
|
23
|
-
// a NUL byte is the usual "this is not text" test.
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// time is not an option: just-bash's `cat` discards every readFile
|
|
29
|
-
// reports "No such file or directory" whatever the error says, so
|
|
30
|
-
// has to
|
|
22
|
+
// a NUL byte is the usual "this is not text" test. it is published as metadata
|
|
23
|
+
// rather than acted on here: moving a binary file is byte-exact and perfectly
|
|
24
|
+
// fine, and so is deleting one, but a shell command that produced TEXT cannot
|
|
25
|
+
// be allowed to overwrite it, because that text is a lossy decode of the
|
|
26
|
+
// file's own bytes. HarnessProjectFs owns that refusal. detecting it at write
|
|
27
|
+
// time instead is not an option: just-bash's `cat` discards every readFile
|
|
28
|
+
// error and reports "No such file or directory" whatever the error says, so
|
|
29
|
+
// the fact has to be in the index where the filesystem layer can read it.
|
|
31
30
|
const BINARY_SNIFF_BYTES = 8192
|
|
32
31
|
|
|
33
32
|
function looksBinary(filePath: string, size: number): boolean {
|
|
@@ -45,9 +44,24 @@ function looksBinary(filePath: string, size: number): boolean {
|
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
// the box re-indexes before every command, so the sniff above runs against the
|
|
48
|
+
// whole project every time a user presses return. on a 14,889-file checkout
|
|
49
|
+
// that is 277-644 ms of a 430-840 ms refresh, and nearly all of it re-reads
|
|
50
|
+
// files that did not change. a file whose size and mtime both match the last
|
|
51
|
+
// look has the same first 8 KB, so remember the answer against those two.
|
|
52
|
+
// `statSync` already returns mtimeMs, and it carries sub-millisecond
|
|
53
|
+
// resolution here, so the window in which a same-size rewrite could hide is
|
|
54
|
+
// narrower than a millisecond rather than git's one-second racy-clean case.
|
|
55
|
+
interface SniffedFile {
|
|
56
|
+
size: number
|
|
57
|
+
mtimeMs: number
|
|
58
|
+
binary: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
export class CheckoutFilePlane implements ProjectFilePlane {
|
|
49
62
|
readonly root: string
|
|
50
63
|
private entries = new Map<string, ProjectFileMeta>()
|
|
64
|
+
private sniffed = new Map<string, SniffedFile>()
|
|
51
65
|
|
|
52
66
|
constructor(root: string) {
|
|
53
67
|
this.root = path.resolve(root)
|
|
@@ -77,6 +91,9 @@ export class CheckoutFilePlane implements ProjectFilePlane {
|
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
const next = new Map<string, ProjectFileMeta>()
|
|
94
|
+
// rebuilt alongside the index rather than pruned, so a deleted file's
|
|
95
|
+
// record cannot outlive it in a box that stays open all day
|
|
96
|
+
const nextSniffed = new Map<string, SniffedFile>()
|
|
80
97
|
for (const relative of stdout.split('\0')) {
|
|
81
98
|
if (!relative) continue
|
|
82
99
|
let stat: fs.Stats
|
|
@@ -87,12 +104,22 @@ export class CheckoutFilePlane implements ProjectFilePlane {
|
|
|
87
104
|
continue
|
|
88
105
|
}
|
|
89
106
|
if (!stat.isFile()) continue
|
|
107
|
+
const seen = this.sniffed.get(relative)
|
|
108
|
+
const binary =
|
|
109
|
+
seen && seen.size === stat.size && seen.mtimeMs === stat.mtimeMs
|
|
110
|
+
? seen.binary
|
|
111
|
+
: looksBinary(path.join(this.root, relative), stat.size)
|
|
112
|
+
nextSniffed.set(relative, { size: stat.size, mtimeMs: stat.mtimeMs, binary })
|
|
90
113
|
next.set(relative, {
|
|
91
114
|
size: stat.size,
|
|
92
|
-
|
|
115
|
+
// a checkout carries no write policy of its own; if the user can write
|
|
116
|
+
// the file, so can the shell
|
|
117
|
+
readOnly: false,
|
|
118
|
+
binary,
|
|
93
119
|
})
|
|
94
120
|
}
|
|
95
121
|
this.entries = next
|
|
122
|
+
this.sniffed = nextSniffed
|
|
96
123
|
}
|
|
97
124
|
|
|
98
125
|
private absolute(planePath: string): string {
|
|
@@ -113,13 +140,15 @@ export class CheckoutFilePlane implements ProjectFilePlane {
|
|
|
113
140
|
return fs.promises.readFile(this.absolute(planePath))
|
|
114
141
|
}
|
|
115
142
|
|
|
116
|
-
async write(planePath: string, content:
|
|
143
|
+
async write(planePath: string, content: Uint8Array): Promise<void> {
|
|
117
144
|
const absolute = this.absolute(planePath)
|
|
118
145
|
await fs.promises.mkdir(path.dirname(absolute), { recursive: true })
|
|
119
|
-
await fs.promises.writeFile(absolute, content
|
|
146
|
+
await fs.promises.writeFile(absolute, content)
|
|
120
147
|
this.entries.set(planePath, {
|
|
121
|
-
size:
|
|
148
|
+
size: content.byteLength,
|
|
122
149
|
readOnly: false,
|
|
150
|
+
// the bytes are in hand, so the same NUL test costs nothing here
|
|
151
|
+
binary: content.subarray(0, BINARY_SNIFF_BYTES).includes(0),
|
|
123
152
|
})
|
|
124
153
|
}
|
|
125
154
|
|
package/cli/commands/config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { rnxExit } from '../run-rnx'
|
|
1
2
|
import { runTelemetry } from './telemetry'
|
|
2
3
|
|
|
3
4
|
function printHelp(): void {
|
|
@@ -28,5 +29,5 @@ export async function runConfig(args: string[]): Promise<void> {
|
|
|
28
29
|
|
|
29
30
|
console.error(` unknown config command: ${sub ?? '(missing)'}`)
|
|
30
31
|
printHelp()
|
|
31
|
-
|
|
32
|
+
rnxExit(1)
|
|
32
33
|
}
|
package/cli/commands/control.ts
CHANGED
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
} from '../current-sim'
|
|
56
56
|
import { getDriver } from '../drivers/registry'
|
|
57
57
|
import { openUrl as openUrlInBrowser } from '../open-url'
|
|
58
|
+
import { rethrowIfExit, rnxExit } from '../run-rnx'
|
|
58
59
|
import {
|
|
59
60
|
BridgeSimLockedError,
|
|
60
61
|
bridgePortForShellBaseUrl,
|
|
@@ -477,18 +478,18 @@ function parseOpenRuntimeConfig(args: string[]): SootSimConfig | undefined {
|
|
|
477
478
|
const raw = args[i + 1]
|
|
478
479
|
if (!raw) {
|
|
479
480
|
console.error(' rnx open: --replace expects <module>=<file>')
|
|
480
|
-
|
|
481
|
+
rnxExit(1)
|
|
481
482
|
}
|
|
482
483
|
const eqIndex = raw.indexOf('=')
|
|
483
484
|
if (eqIndex <= 0 || eqIndex === raw.length - 1) {
|
|
484
485
|
console.error(' rnx open: --replace expects <module>=<file>')
|
|
485
|
-
|
|
486
|
+
rnxExit(1)
|
|
486
487
|
}
|
|
487
488
|
const moduleName = raw.slice(0, eqIndex).trim()
|
|
488
489
|
const filePath = normalizeReplacementPath(raw.slice(eqIndex + 1).trim())
|
|
489
490
|
if (!fs.existsSync(filePath)) {
|
|
490
491
|
console.error(` rnx open: replacement file not found: ${filePath}`)
|
|
491
|
-
|
|
492
|
+
rnxExit(1)
|
|
492
493
|
}
|
|
493
494
|
modules[moduleName] = { file: filePath }
|
|
494
495
|
i++
|
|
@@ -502,7 +503,7 @@ function parseOpenRuntimeConfig(args: string[]): SootSimConfig | undefined {
|
|
|
502
503
|
const eqIndex = raw ? raw.indexOf('=') : -1
|
|
503
504
|
if (!raw || eqIndex <= 0 || eqIndex === raw.length - 1) {
|
|
504
505
|
console.error(' rnx open: --remap expects <host:port>=<host:port>')
|
|
505
|
-
|
|
506
|
+
rnxExit(1)
|
|
506
507
|
}
|
|
507
508
|
remap[raw.slice(0, eqIndex).trim()] = raw.slice(eqIndex + 1).trim()
|
|
508
509
|
i++
|
|
@@ -1338,7 +1339,7 @@ export async function runLinkCommand(args: string[], opts: ControlCommandOptions
|
|
|
1338
1339
|
if (parsed.positional.length !== 1) {
|
|
1339
1340
|
console.error(' rnx open: expected exactly one <url-or-route>')
|
|
1340
1341
|
console.error(' examples: rnx open /settings | rnx open myapp://settings')
|
|
1341
|
-
|
|
1342
|
+
rnxExit(1)
|
|
1342
1343
|
}
|
|
1343
1344
|
|
|
1344
1345
|
const bridge = createBridgeFromParsed(parsed)
|
|
@@ -1353,7 +1354,7 @@ export async function runLinkCommand(args: string[], opts: ControlCommandOptions
|
|
|
1353
1354
|
warningsCommand: `rnx get warnings 5${simHint}`,
|
|
1354
1355
|
requestsCommand: `rnx get requests 5${simHint}`,
|
|
1355
1356
|
})
|
|
1356
|
-
|
|
1357
|
+
rnxExit(1)
|
|
1357
1358
|
} finally {
|
|
1358
1359
|
bridge.close()
|
|
1359
1360
|
}
|
|
@@ -1397,11 +1398,11 @@ export async function runOpenCommand(
|
|
|
1397
1398
|
console.error(
|
|
1398
1399
|
` rnx open: --cdp-port must be a positive port number, got "${cdpPortArg}"`,
|
|
1399
1400
|
)
|
|
1400
|
-
|
|
1401
|
+
rnxExit(1)
|
|
1401
1402
|
}
|
|
1402
1403
|
if (requestedProfileId && ephemeralProfile) {
|
|
1403
1404
|
console.error(' rnx open: --profile cannot be combined with --ephemeral')
|
|
1404
|
-
|
|
1405
|
+
rnxExit(1)
|
|
1405
1406
|
}
|
|
1406
1407
|
const profileId = requestedProfileId ? ensureProfile(requestedProfileId).id : undefined
|
|
1407
1408
|
const openInNewSim = args.includes('--new') || !!profileId || ephemeralProfile
|
|
@@ -1410,7 +1411,7 @@ export async function runOpenCommand(
|
|
|
1410
1411
|
console.error(
|
|
1411
1412
|
' rnx open: --new, --profile, and --ephemeral cannot be combined with --sim',
|
|
1412
1413
|
)
|
|
1413
|
-
|
|
1414
|
+
rnxExit(1)
|
|
1414
1415
|
}
|
|
1415
1416
|
const target = parsed.positional[0] || ''
|
|
1416
1417
|
|
|
@@ -1419,7 +1420,7 @@ export async function runOpenCommand(
|
|
|
1419
1420
|
console.error(
|
|
1420
1421
|
' rnx open: deep links target the current app; remove --new, --profile, or --ephemeral',
|
|
1421
1422
|
)
|
|
1422
|
-
|
|
1423
|
+
rnxExit(1)
|
|
1423
1424
|
}
|
|
1424
1425
|
await runLinkCommand(args, opts)
|
|
1425
1426
|
return
|
|
@@ -1447,7 +1448,7 @@ export async function runOpenCommand(
|
|
|
1447
1448
|
` could not launch a browser: ${err instanceof Error ? err.message : String(err)}`,
|
|
1448
1449
|
)
|
|
1449
1450
|
console.error(` open it yourself: ${target}`)
|
|
1450
|
-
|
|
1451
|
+
rnxExit(1)
|
|
1451
1452
|
}
|
|
1452
1453
|
console.log(
|
|
1453
1454
|
isLocal
|
|
@@ -1492,7 +1493,7 @@ export async function runOpenCommand(
|
|
|
1492
1493
|
const requestedDriverId = args.find((_, i) => args[i - 1] === '--driver') || ''
|
|
1493
1494
|
if (requestedDriverId && !isDriverId(requestedDriverId)) {
|
|
1494
1495
|
console.error(` unknown driver "${requestedDriverId}" — run \`rnx list --drivers\``)
|
|
1495
|
-
|
|
1496
|
+
rnxExit(1)
|
|
1496
1497
|
}
|
|
1497
1498
|
const driverId: DriverId = isDriverId(requestedDriverId)
|
|
1498
1499
|
? requestedDriverId
|
|
@@ -1506,7 +1507,7 @@ export async function runOpenCommand(
|
|
|
1506
1507
|
const driverHeadless = resolveDriverHeadless(args, driverId)
|
|
1507
1508
|
if (cdpPort && driverId !== 'playwright') {
|
|
1508
1509
|
console.error(' rnx open: --cdp-port is only honored by the playwright driver')
|
|
1509
|
-
|
|
1510
|
+
rnxExit(1)
|
|
1510
1511
|
}
|
|
1511
1512
|
|
|
1512
1513
|
// metro HMR mode. interactive opens default to hot=true so edits hot-apply
|
|
@@ -1520,7 +1521,7 @@ export async function runOpenCommand(
|
|
|
1520
1521
|
const noHmrFlag = args.includes('--no-hmr')
|
|
1521
1522
|
if (hotFlag && noHmrFlag) {
|
|
1522
1523
|
console.error(' rnx open: --hot and --no-hmr cannot be combined')
|
|
1523
|
-
|
|
1524
|
+
rnxExit(1)
|
|
1524
1525
|
}
|
|
1525
1526
|
const hotMode = hotFlag ? true : noHmrFlag ? false : driverId !== 'playwright'
|
|
1526
1527
|
|
|
@@ -1532,7 +1533,7 @@ export async function runOpenCommand(
|
|
|
1532
1533
|
if (deviceArg && !(deviceArg in devices)) {
|
|
1533
1534
|
console.error(` rnx open: unknown device "${deviceArg}"`)
|
|
1534
1535
|
console.error(` known devices: ${listSelectableDeviceModels().join(', ')}`)
|
|
1535
|
-
|
|
1536
|
+
rnxExit(1)
|
|
1536
1537
|
}
|
|
1537
1538
|
const deviceSpec = deviceArg ? devices[deviceArg as DeviceModel] : undefined
|
|
1538
1539
|
|
|
@@ -1544,7 +1545,7 @@ export async function runOpenCommand(
|
|
|
1544
1545
|
const viewportMatch = viewportArg ? /^(\d+)x(\d+)$/.exec(viewportArg) : null
|
|
1545
1546
|
if (viewportArg && !viewportMatch) {
|
|
1546
1547
|
console.error(` rnx open: --viewport must be <width>x<height>, got "${viewportArg}"`)
|
|
1547
|
-
|
|
1548
|
+
rnxExit(1)
|
|
1548
1549
|
}
|
|
1549
1550
|
const explicitViewport = viewportMatch
|
|
1550
1551
|
? { width: Number(viewportMatch[1]), height: Number(viewportMatch[2]) }
|
|
@@ -1662,7 +1663,7 @@ export async function runOpenCommand(
|
|
|
1662
1663
|
warningsCommand: `rnx get warnings 5${simHint}`,
|
|
1663
1664
|
requestsCommand: `rnx get requests 5${simHint}`,
|
|
1664
1665
|
})
|
|
1665
|
-
|
|
1666
|
+
rnxExit(1)
|
|
1666
1667
|
}
|
|
1667
1668
|
|
|
1668
1669
|
if (!fallBackToNewSim && targetSim) {
|
|
@@ -1674,7 +1675,7 @@ export async function runOpenCommand(
|
|
|
1674
1675
|
)
|
|
1675
1676
|
if (!ready) {
|
|
1676
1677
|
console.error(' timed out waiting for current sim to load target')
|
|
1677
|
-
|
|
1678
|
+
rnxExit(1)
|
|
1678
1679
|
}
|
|
1679
1680
|
ready.bridge.close()
|
|
1680
1681
|
saveCurrentSimId(targetSim.id)
|
|
@@ -1706,7 +1707,7 @@ export async function runOpenCommand(
|
|
|
1706
1707
|
console.error(
|
|
1707
1708
|
' could not resolve a stable owning process; refusing unsupervised sim host',
|
|
1708
1709
|
)
|
|
1709
|
-
|
|
1710
|
+
rnxExit(1)
|
|
1710
1711
|
}
|
|
1711
1712
|
const simMatchesToken = (sim: BridgeSimInfo) =>
|
|
1712
1713
|
sim.url?.includes(`inspectOpen=${token}`) ?? false
|
|
@@ -1714,7 +1715,7 @@ export async function runOpenCommand(
|
|
|
1714
1715
|
const driver = getDriver(driverId)
|
|
1715
1716
|
if (!driver) {
|
|
1716
1717
|
console.error(` unknown driver "${driverId}" — run \`rnx list --drivers\``)
|
|
1717
|
-
|
|
1718
|
+
rnxExit(1)
|
|
1718
1719
|
}
|
|
1719
1720
|
const connectWait = resolveDriverConnectWaitOptions()
|
|
1720
1721
|
const result = await driver.launch({
|
|
@@ -1738,7 +1739,7 @@ export async function runOpenCommand(
|
|
|
1738
1739
|
})
|
|
1739
1740
|
if (!result.launched) {
|
|
1740
1741
|
console.error(` ${driver.name} driver: ${result.message}`)
|
|
1741
|
-
|
|
1742
|
+
rnxExit(1)
|
|
1742
1743
|
}
|
|
1743
1744
|
const outcome = await waitForSimMatchOrHostExit(
|
|
1744
1745
|
parsed.wsPort,
|
|
@@ -1750,7 +1751,7 @@ export async function runOpenCommand(
|
|
|
1750
1751
|
if (outcome.kind === 'host-exit') {
|
|
1751
1752
|
printDriverDiagnosticLogTail(result)
|
|
1752
1753
|
console.error(` ${driver.name} host crashed — sim is no longer attached`)
|
|
1753
|
-
|
|
1754
|
+
rnxExit(1)
|
|
1754
1755
|
}
|
|
1755
1756
|
if (outcome.kind === 'timeout') {
|
|
1756
1757
|
if (result.pid) {
|
|
@@ -1763,7 +1764,7 @@ export async function runOpenCommand(
|
|
|
1763
1764
|
console.error(
|
|
1764
1765
|
` timed out after ${connectWait.timeoutMs}ms waiting for opened sim to connect`,
|
|
1765
1766
|
)
|
|
1766
|
-
|
|
1767
|
+
rnxExit(1)
|
|
1767
1768
|
}
|
|
1768
1769
|
const match = outcome.sim
|
|
1769
1770
|
saveCurrentSimId(match.id)
|
|
@@ -1801,7 +1802,7 @@ async function runUseLikeCommand(args: string[], opts: ControlCommandOptions = {
|
|
|
1801
1802
|
` refused: ${target.id} is locked by the active user (${secs}s) — that's a live human tab`,
|
|
1802
1803
|
)
|
|
1803
1804
|
console.error(` run \`rnx open --new\` for a fresh investigation sim`)
|
|
1804
|
-
|
|
1805
|
+
rnxExit(1)
|
|
1805
1806
|
}
|
|
1806
1807
|
if (!force) {
|
|
1807
1808
|
// another CLI agent leases it. don't hijack its target silently;
|
|
@@ -1813,20 +1814,21 @@ async function runUseLikeCommand(args: string[], opts: ControlCommandOptions = {
|
|
|
1813
1814
|
console.error(
|
|
1814
1815
|
` \`sootsim use ${target.id} --force\` to take it, or \`rnx open --new\` for a fresh sim`,
|
|
1815
1816
|
)
|
|
1816
|
-
|
|
1817
|
+
rnxExit(1)
|
|
1817
1818
|
}
|
|
1818
1819
|
}
|
|
1819
1820
|
await bridge.focusSim(target.id)
|
|
1820
1821
|
saveCurrentSimId(target.id)
|
|
1821
1822
|
console.log(` using: ${target.id}`)
|
|
1822
1823
|
} catch (err) {
|
|
1824
|
+
rethrowIfExit(err)
|
|
1823
1825
|
console.error(` use failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
1824
1826
|
await printBridgeFailureDiagnostics(bridge, {
|
|
1825
1827
|
errorsCommand: `rnx get errors 5${simHint}`,
|
|
1826
1828
|
warningsCommand: `rnx get warnings 5${simHint}`,
|
|
1827
1829
|
requestsCommand: `rnx get requests 5${simHint}`,
|
|
1828
1830
|
})
|
|
1829
|
-
|
|
1831
|
+
rnxExit(1)
|
|
1830
1832
|
}
|
|
1831
1833
|
} finally {
|
|
1832
1834
|
bridge.close()
|
|
@@ -1871,10 +1873,10 @@ export async function runClaimCommand(args: string[], opts: ControlCommandOption
|
|
|
1871
1873
|
const secs = Math.max(0, Math.round(err.lock.expiresInMs / 1000))
|
|
1872
1874
|
console.error(` claim failed: locked by ${err.lock.by} for ${secs}s more`)
|
|
1873
1875
|
console.error(` use --force to take it, or \`rnx open --new\` for a fresh sim`)
|
|
1874
|
-
|
|
1876
|
+
rnxExit(1)
|
|
1875
1877
|
}
|
|
1876
1878
|
console.error(` claim failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
1877
|
-
|
|
1879
|
+
rnxExit(1)
|
|
1878
1880
|
}
|
|
1879
1881
|
} finally {
|
|
1880
1882
|
bridge.close()
|
|
@@ -2016,7 +2018,7 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
|
|
|
2016
2018
|
console.error(
|
|
2017
2019
|
` close failed: keep sim ${plan.missingExplicitKeepId} is not connected; not closing other sims`,
|
|
2018
2020
|
)
|
|
2019
|
-
|
|
2021
|
+
rnxExit(1)
|
|
2020
2022
|
}
|
|
2021
2023
|
if (plan.targets.length === 0) {
|
|
2022
2024
|
console.log(
|
|
@@ -2047,11 +2049,12 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
|
|
|
2047
2049
|
console.log(summary)
|
|
2048
2050
|
if (result.remaining.length > 0) {
|
|
2049
2051
|
console.error(` close failed: still connected: ${result.remaining.join(', ')}`)
|
|
2050
|
-
|
|
2052
|
+
rnxExit(1)
|
|
2051
2053
|
}
|
|
2052
2054
|
} catch (err) {
|
|
2055
|
+
rethrowIfExit(err)
|
|
2053
2056
|
console.error(` close failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
2054
|
-
|
|
2057
|
+
rnxExit(1)
|
|
2055
2058
|
} finally {
|
|
2056
2059
|
bridge.close()
|
|
2057
2060
|
}
|
|
@@ -2074,7 +2077,7 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
|
|
|
2074
2077
|
if (!closed) {
|
|
2075
2078
|
await terminatePlaywrightHostsForSims(sims, [target.id])
|
|
2076
2079
|
console.error(` close failed: ${target.id} is still connected`)
|
|
2077
|
-
|
|
2080
|
+
rnxExit(1)
|
|
2078
2081
|
}
|
|
2079
2082
|
await terminatePlaywrightHostsForSims(sims, [target.id])
|
|
2080
2083
|
if (readCurrentSimId() === target.id) {
|
|
@@ -2083,13 +2086,14 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
|
|
|
2083
2086
|
}
|
|
2084
2087
|
console.log(` closed: ${target.id}`)
|
|
2085
2088
|
} catch (err) {
|
|
2089
|
+
rethrowIfExit(err)
|
|
2086
2090
|
console.error(` close failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
2087
2091
|
await printBridgeFailureDiagnostics(bridge, {
|
|
2088
2092
|
errorsCommand: `rnx get errors 5${simHint}`,
|
|
2089
2093
|
warningsCommand: `rnx get warnings 5${simHint}`,
|
|
2090
2094
|
requestsCommand: `rnx get requests 5${simHint}`,
|
|
2091
2095
|
})
|
|
2092
|
-
|
|
2096
|
+
rnxExit(1)
|
|
2093
2097
|
}
|
|
2094
2098
|
} finally {
|
|
2095
2099
|
bridge.close()
|
package/cli/commands/daemon.ts
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
} from '../../src/home-paths'
|
|
38
38
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
39
39
|
import { printCommandHelp } from '../help'
|
|
40
|
+
import { rnxExit } from '../run-rnx'
|
|
40
41
|
import { ensureDaemonApp } from './daemon-mac-app'
|
|
41
42
|
|
|
42
43
|
// minimum seconds between launchd / systemd respawns. without this, a daemon
|
|
@@ -82,7 +83,7 @@ export async function runDaemon(args: string[], opts: DaemonOptions = {}) {
|
|
|
82
83
|
default:
|
|
83
84
|
console.error(` unknown daemon subcommand: ${sub}`)
|
|
84
85
|
printHelp()
|
|
85
|
-
|
|
86
|
+
rnxExit(1)
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -468,7 +469,7 @@ export async function daemonInstall({ port, force }: { port: number; force: bool
|
|
|
468
469
|
|
|
469
470
|
console.error(` background daemon is not supported on ${process.platform}`)
|
|
470
471
|
console.error(` run 'rnx serve' in a persistent shell instead`)
|
|
471
|
-
|
|
472
|
+
rnxExit(1)
|
|
472
473
|
}
|
|
473
474
|
|
|
474
475
|
// removed-path log (idempotent helpers track what they actually touched so the
|
|
@@ -649,7 +650,7 @@ async function daemonStatus() {
|
|
|
649
650
|
return
|
|
650
651
|
}
|
|
651
652
|
console.error(` unsupported platform: ${process.platform}`)
|
|
652
|
-
|
|
653
|
+
rnxExit(1)
|
|
653
654
|
}
|
|
654
655
|
|
|
655
656
|
async function daemonRestart() {
|
|
@@ -657,7 +658,7 @@ async function daemonRestart() {
|
|
|
657
658
|
const path = macPlistPath()
|
|
658
659
|
if (!existsSync(path)) {
|
|
659
660
|
console.error(' daemon not registered. run `rnx daemon install`')
|
|
660
|
-
|
|
661
|
+
rnxExit(1)
|
|
661
662
|
}
|
|
662
663
|
const res = spawnSync(
|
|
663
664
|
'launchctl',
|
|
@@ -666,7 +667,7 @@ async function daemonRestart() {
|
|
|
666
667
|
)
|
|
667
668
|
if (res.status !== 0) {
|
|
668
669
|
console.error(` kickstart failed: ${res.stderr?.trim()}`)
|
|
669
|
-
|
|
670
|
+
rnxExit(1)
|
|
670
671
|
}
|
|
671
672
|
console.log(' restarted')
|
|
672
673
|
return
|
|
@@ -675,7 +676,7 @@ async function daemonRestart() {
|
|
|
675
676
|
const path = linuxUnitPath()
|
|
676
677
|
if (!existsSync(path)) {
|
|
677
678
|
console.error(' daemon not registered. run `rnx daemon install`')
|
|
678
|
-
|
|
679
|
+
rnxExit(1)
|
|
679
680
|
}
|
|
680
681
|
const res = spawnSync('systemctl', ['--user', 'restart', SERVICE_NAME_LINUX], {
|
|
681
682
|
stdio: 'pipe',
|
|
@@ -683,13 +684,13 @@ async function daemonRestart() {
|
|
|
683
684
|
})
|
|
684
685
|
if (res.status !== 0) {
|
|
685
686
|
console.error(` restart failed: ${res.stderr?.trim()}`)
|
|
686
|
-
|
|
687
|
+
rnxExit(1)
|
|
687
688
|
}
|
|
688
689
|
console.log(' restarted')
|
|
689
690
|
return
|
|
690
691
|
}
|
|
691
692
|
console.error(` unsupported platform: ${process.platform}`)
|
|
692
|
-
|
|
693
|
+
rnxExit(1)
|
|
693
694
|
}
|
|
694
695
|
|
|
695
696
|
async function daemonStart() {
|
|
@@ -697,7 +698,7 @@ async function daemonStart() {
|
|
|
697
698
|
const path = macPlistPath()
|
|
698
699
|
if (!existsSync(path)) {
|
|
699
700
|
console.error(' daemon not registered. run `rnx daemon install`')
|
|
700
|
-
|
|
701
|
+
rnxExit(1)
|
|
701
702
|
}
|
|
702
703
|
const res = spawnSync(
|
|
703
704
|
'launchctl',
|
|
@@ -706,7 +707,7 @@ async function daemonStart() {
|
|
|
706
707
|
)
|
|
707
708
|
if (res.status !== 0) {
|
|
708
709
|
console.error(` start failed: ${res.stderr?.trim()}`)
|
|
709
|
-
|
|
710
|
+
rnxExit(1)
|
|
710
711
|
}
|
|
711
712
|
console.log(' started')
|
|
712
713
|
return
|
|
@@ -715,7 +716,7 @@ async function daemonStart() {
|
|
|
715
716
|
const path = linuxUnitPath()
|
|
716
717
|
if (!existsSync(path)) {
|
|
717
718
|
console.error(' daemon not registered. run `rnx daemon install`')
|
|
718
|
-
|
|
719
|
+
rnxExit(1)
|
|
719
720
|
}
|
|
720
721
|
const res = spawnSync('systemctl', ['--user', 'start', SERVICE_NAME_LINUX], {
|
|
721
722
|
stdio: 'pipe',
|
|
@@ -723,13 +724,13 @@ async function daemonStart() {
|
|
|
723
724
|
})
|
|
724
725
|
if (res.status !== 0) {
|
|
725
726
|
console.error(` start failed: ${res.stderr?.trim()}`)
|
|
726
|
-
|
|
727
|
+
rnxExit(1)
|
|
727
728
|
}
|
|
728
729
|
console.log(' started')
|
|
729
730
|
return
|
|
730
731
|
}
|
|
731
732
|
console.error(` unsupported platform: ${process.platform}`)
|
|
732
|
-
|
|
733
|
+
rnxExit(1)
|
|
733
734
|
}
|
|
734
735
|
|
|
735
736
|
async function daemonStop() {
|
|
@@ -737,7 +738,7 @@ async function daemonStop() {
|
|
|
737
738
|
const path = macPlistPath()
|
|
738
739
|
if (!existsSync(path)) {
|
|
739
740
|
console.error(' daemon not registered — nothing to stop')
|
|
740
|
-
|
|
741
|
+
rnxExit(1)
|
|
741
742
|
}
|
|
742
743
|
const res = spawnSync(
|
|
743
744
|
'launchctl',
|
|
@@ -746,7 +747,7 @@ async function daemonStop() {
|
|
|
746
747
|
)
|
|
747
748
|
if (res.status !== 0) {
|
|
748
749
|
console.error(` stop failed: ${res.stderr?.trim()}`)
|
|
749
|
-
|
|
750
|
+
rnxExit(1)
|
|
750
751
|
}
|
|
751
752
|
console.log(' stopped')
|
|
752
753
|
return
|
|
@@ -755,7 +756,7 @@ async function daemonStop() {
|
|
|
755
756
|
const path = linuxUnitPath()
|
|
756
757
|
if (!existsSync(path)) {
|
|
757
758
|
console.error(' daemon not registered — nothing to stop')
|
|
758
|
-
|
|
759
|
+
rnxExit(1)
|
|
759
760
|
}
|
|
760
761
|
const res = spawnSync('systemctl', ['--user', 'stop', SERVICE_NAME_LINUX], {
|
|
761
762
|
stdio: 'pipe',
|
|
@@ -763,13 +764,13 @@ async function daemonStop() {
|
|
|
763
764
|
})
|
|
764
765
|
if (res.status !== 0) {
|
|
765
766
|
console.error(` stop failed: ${res.stderr?.trim()}`)
|
|
766
|
-
|
|
767
|
+
rnxExit(1)
|
|
767
768
|
}
|
|
768
769
|
console.log(' stopped')
|
|
769
770
|
return
|
|
770
771
|
}
|
|
771
772
|
console.error(` unsupported platform: ${process.platform}`)
|
|
772
|
-
|
|
773
|
+
rnxExit(1)
|
|
773
774
|
}
|
|
774
775
|
|
|
775
776
|
// tail the daemon's logs. macOS reads the launchd-redirected files directly
|
|
@@ -789,7 +790,7 @@ async function daemonLogs(rest: string[]) {
|
|
|
789
790
|
const present = [out, err].filter((p) => existsSync(p))
|
|
790
791
|
if (present.length === 0) {
|
|
791
792
|
console.error(` no daemon logs yet at ${LOG_DIR}. run \`rnx daemon install\``)
|
|
792
|
-
|
|
793
|
+
rnxExit(1)
|
|
793
794
|
}
|
|
794
795
|
const args = follow
|
|
795
796
|
? ['-n', String(lines), '-F', ...present]
|
|
@@ -829,11 +830,11 @@ async function daemonLogs(rest: string[]) {
|
|
|
829
830
|
` could not read --user journal for ${unit} (this user isn't in the systemd-journal group yet).\n` +
|
|
830
831
|
` run: sudo journalctl _SYSTEMD_USER_UNIT=${unit} -n ${lines} --no-pager`,
|
|
831
832
|
)
|
|
832
|
-
|
|
833
|
+
rnxExit(1)
|
|
833
834
|
}
|
|
834
835
|
|
|
835
836
|
console.error(` unsupported platform: ${process.platform}`)
|
|
836
|
-
|
|
837
|
+
rnxExit(1)
|
|
837
838
|
}
|
|
838
839
|
|
|
839
840
|
function readPlistBinary(path: string): string | null {
|