rnxsim 0.1.344 → 0.1.345
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 +59 -31
- package/cli/app-fonts.ts +8 -28
- package/cli/app-project.ts +12 -184
- package/cli/app-splash.ts +3 -17
- package/cli/bin.ts +15 -28
- package/cli/commands/control.ts +20 -30
- package/cli/commands/daemon.ts +19 -44
- package/cli/commands/flow.ts +0 -27
- package/cli/commands/install-desktop.ts +2 -16
- package/cli/commands/login.ts +3 -43
- package/cli/commands/logout.ts +0 -7
- package/cli/commands/serve.ts +2 -32
- package/cli/commands/setup.ts +20 -194
- package/cli/commands/telemetry.ts +7 -5
- package/cli/commands/upload.ts +1 -48
- package/cli/commands/welcome.ts +64 -0
- package/cli/outbound-endpoints.ts +586 -0
- package/cli/privacy.ts +53 -0
- package/cli/runtime-notes.ts +2 -2
- package/cli/telemetry.ts +46 -149
- package/dist-cli/bin.js +6 -6
- package/dist-cli/chunks/{agent-HTSE5FA4.js → agent-52G55XTO.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-L6X2AEZL.js → agent-wrapper-BOZM43ON.js} +2 -2
- package/dist-cli/chunks/{app-fonts-FGF3ETYH.js → app-fonts-A2L6V5EZ.js} +2 -2
- package/dist-cli/chunks/{assert-HA2ZYVDN.js → assert-CJKIP4LN.js} +2 -2
- package/dist-cli/chunks/{auth-HONDAV75.js → auth-VHHN3TOB.js} +2 -2
- package/dist-cli/chunks/{beta-U7EE4GMR.js → beta-EBDIGV3E.js} +2 -2
- package/dist-cli/chunks/{camera-RTKNUTIX.js → camera-5F4KKCQ3.js} +2 -2
- package/dist-cli/chunks/chunk-3DBTS4MC.js +15 -0
- package/dist-cli/chunks/chunk-3N7M5HMJ.js +6 -0
- package/dist-cli/chunks/{chunk-S7CSBQ6G.js → chunk-4BIPA7MD.js} +1 -1
- package/dist-cli/chunks/chunk-4OKV7T5D.js +4 -0
- package/dist-cli/chunks/{chunk-CNLPLCO2.js → chunk-4ZILDTZX.js} +2 -2
- package/dist-cli/chunks/{chunk-HRBMD2FS.js → chunk-5GXRRUOA.js} +26 -26
- package/dist-cli/chunks/chunk-63ASUHOV.js +4 -0
- package/dist-cli/chunks/{chunk-XQFDEY3F.js → chunk-7GO2DSYQ.js} +1 -1
- package/dist-cli/chunks/{chunk-IWR4HFC4.js → chunk-7LGINKM6.js} +2 -2
- package/dist-cli/chunks/{chunk-TZNRKIS3.js → chunk-7UIIAHVU.js} +2 -2
- package/dist-cli/chunks/{chunk-Q2B6EQPB.js → chunk-7V4KPZ7O.js} +2 -2
- package/dist-cli/chunks/{chunk-EPEZZ6YS.js → chunk-7YMQRA6L.js} +2 -2
- package/dist-cli/chunks/{chunk-IPC45HTT.js → chunk-A2Q76LJV.js} +2 -2
- package/dist-cli/chunks/{chunk-EH35QQG4.js → chunk-BCQV63BW.js} +45 -45
- package/dist-cli/chunks/{chunk-N5PFDTFL.js → chunk-BFTDL2GX.js} +17 -17
- package/dist-cli/chunks/chunk-BHKSCNDC.js +4 -0
- package/dist-cli/chunks/{chunk-6PEZSVIG.js → chunk-DGTV3KOW.js} +1 -1
- package/dist-cli/chunks/chunk-DHM3JDCK.js +4 -0
- package/dist-cli/chunks/{chunk-KT6WMCUS.js → chunk-DPP2M4AJ.js} +1 -1
- package/dist-cli/chunks/chunk-E2RGSCHT.js +4 -0
- package/dist-cli/chunks/{chunk-S6LBAUWH.js → chunk-EPLVIDPC.js} +1 -1
- package/dist-cli/chunks/{chunk-6NLWKL7Y.js → chunk-GKGXULJK.js} +2 -2
- package/dist-cli/chunks/{chunk-7V4ULF3U.js → chunk-HK7YKH6N.js} +2 -2
- package/dist-cli/chunks/{chunk-6E6SBYIO.js → chunk-HXE344V3.js} +1 -1
- package/dist-cli/chunks/{chunk-JLUEQPEF.js → chunk-JC33TOAF.js} +1 -1
- package/dist-cli/chunks/{chunk-7JEEO33Y.js → chunk-KA4PJNTE.js} +2 -2
- package/dist-cli/chunks/{chunk-K3VNCCEJ.js → chunk-KH777UAO.js} +3 -3
- package/dist-cli/chunks/{chunk-G3UAFZE2.js → chunk-KRZPFXVN.js} +1 -1
- package/dist-cli/chunks/{chunk-R3UYHE6G.js → chunk-KZFJNDH3.js} +1 -1
- package/dist-cli/chunks/{chunk-22WJPMTQ.js → chunk-LAQGSSTT.js} +1 -1
- package/dist-cli/chunks/chunk-LRM2XCEQ.js +11 -0
- package/dist-cli/chunks/{chunk-MWUXQIA3.js → chunk-NUPRHZQW.js} +2 -2
- package/dist-cli/chunks/{chunk-JFUVWIJT.js → chunk-OPHT4DUO.js} +1 -1
- package/dist-cli/chunks/{chunk-EN32LN2B.js → chunk-P2CGGMU2.js} +2 -2
- package/dist-cli/chunks/{chunk-UCVQOQCY.js → chunk-PLB6UVVX.js} +2 -2
- package/dist-cli/chunks/{chunk-TOHQI2II.js → chunk-PLUWN2V5.js} +1 -1
- package/dist-cli/chunks/{chunk-ZPTFL5FQ.js → chunk-QNBBKRCA.js} +2 -2
- package/dist-cli/chunks/{chunk-NRTHFEPM.js → chunk-QNRWPAOA.js} +2 -2
- package/dist-cli/chunks/{chunk-63NZGJ4A.js → chunk-R7ZNRGQN.js} +1 -1
- package/dist-cli/chunks/{chunk-FZ5DRZJE.js → chunk-RB4VFUNM.js} +3 -3
- package/dist-cli/chunks/chunk-RT3DXTDP.js +25 -0
- package/dist-cli/chunks/{chunk-KBSVSAAE.js → chunk-RTDHX6CW.js} +2 -2
- package/dist-cli/chunks/{chunk-OCUXAA6O.js → chunk-T7SBFG5I.js} +2 -2
- package/dist-cli/chunks/{chunk-GRX6NSBG.js → chunk-TEU5NGUA.js} +2 -2
- package/dist-cli/chunks/chunk-TMRD5MHL.js +99 -0
- package/dist-cli/chunks/{chunk-POOCKX5B.js → chunk-TOF5TA5X.js} +11 -11
- package/dist-cli/chunks/{chunk-G6IPT2PS.js → chunk-U5YHXQHH.js} +2 -2
- package/dist-cli/chunks/{chunk-H4J7EWZC.js → chunk-UVOEHIGP.js} +1 -1
- package/dist-cli/chunks/{chunk-ZZSBCGHC.js → chunk-VLBN3KRC.js} +1 -1
- package/dist-cli/chunks/{chunk-PNMCALX5.js → chunk-WPPGU5IK.js} +2 -2
- package/dist-cli/chunks/{chunk-NDGAF5OF.js → chunk-WU72KL6Z.js} +2 -2
- package/dist-cli/chunks/chunk-XJBFJGNT.js +4 -0
- package/dist-cli/chunks/{chunk-BGLWR43R.js → chunk-XXZLK4BY.js} +1 -1
- package/dist-cli/chunks/{chunk-CRWYKW67.js → chunk-YVSUFVVB.js} +1 -1
- package/dist-cli/chunks/{chunk-EZLLZDYX.js → chunk-ZMTZ5G5H.js} +2 -2
- package/dist-cli/chunks/{cleanup-EMYD5WZG.js → cleanup-MAVZJXVW.js} +2 -2
- package/dist-cli/chunks/cli-version-2B4KRNML.js +4 -0
- package/dist-cli/chunks/{compat-W2N5QTVG.js → compat-7AURLGCS.js} +2 -2
- package/dist-cli/chunks/config-TN3Y4J5N.js +13 -0
- package/dist-cli/chunks/{control-4SFBROUE.js → control-EV2ELU5R.js} +2 -2
- package/dist-cli/chunks/daemon-KKDG5MYR.js +4 -0
- package/dist-cli/chunks/{debug-HCR2KFUA.js → debug-JICITUB6.js} +3 -3
- package/dist-cli/chunks/{desktop-T2KS5PBJ.js → desktop-4F5HGLLX.js} +3 -3
- package/dist-cli/chunks/{detox-5S7EHINH.js → detox-ZC7NHLJI.js} +2 -2
- package/dist-cli/chunks/{device-LVM3MZRJ.js → device-V57GHRXX.js} +2 -2
- package/dist-cli/chunks/{diagnose-WK37XKLI.js → diagnose-FF4IWYXC.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-X7VJOXMS.js → disk-cleanup-T277L6ZO.js} +2 -2
- package/dist-cli/chunks/drivers-LCX7S76X.js +4 -0
- package/dist-cli/chunks/{film-7KLTI3ER.js → film-G7ZAPWB7.js} +3 -3
- package/dist-cli/chunks/flow-ONZGGFGD.js +4 -0
- package/dist-cli/chunks/help-DROVDXJM.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-4RVGUVFO.js → hidden-runtime-alias-VSJNNSNI.js} +2 -2
- package/dist-cli/chunks/{home-paths-5DHSAEGZ.js → home-paths-75HP3HKA.js} +2 -2
- package/dist-cli/chunks/inspect-MDA7ESGQ.js +4 -0
- package/dist-cli/chunks/install-desktop-EIVZHIFA.js +4 -0
- package/dist-cli/chunks/login-ZSIHGHUK.js +26 -0
- package/dist-cli/chunks/logout-Q4DXMI2C.js +4 -0
- package/dist-cli/chunks/{maestro-HTRLQDJE.js → maestro-LE5LCRBL.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-GX2QNA3F.js → maestro-generate-D3ZIJCRL.js} +3 -3
- package/dist-cli/chunks/{mode-GM6KZHQP.js → mode-BWX6MDPJ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-B4TD7JQP.js → optional-demo-registry-6CVASL3S.js} +2 -2
- package/dist-cli/chunks/{perf-3PRXJQIC.js → perf-NXQZISN6.js} +2 -2
- package/dist-cli/chunks/{permissions-TJZIRF2S.js → permissions-5PD67RRO.js} +2 -2
- package/dist-cli/chunks/privacy-H5KNRNIZ.js +4 -0
- package/dist-cli/chunks/{record-LI55DTPE.js → record-YJF4KXMR.js} +3 -3
- package/dist-cli/chunks/{report-issue-TBGJVQIQ.js → report-issue-XOL5FQBG.js} +2 -2
- package/dist-cli/chunks/reset-5LZN5P5B.js +4 -0
- package/dist-cli/chunks/runtime-U36VWBH3.js +4 -0
- package/dist-cli/chunks/{screenshot-command-BEN7YYIF.js → screenshot-command-VRPJXWFS.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-3IU4KYNO.js → screenshot-layers-QP4WA2F5.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-ZRC54ST6.js → screenshots-capture-O2IBAVSP.js} +2 -2
- package/dist-cli/chunks/serve-WC6RZNJL.js +118 -0
- package/dist-cli/chunks/setup-A6BIG3KL.js +30 -0
- package/dist-cli/chunks/{skills-GKBR2HQB.js → skills-A7YC6RL5.js} +2 -2
- package/dist-cli/chunks/{state-LIHZJSL7.js → state-IJI5YROJ.js} +2 -2
- package/dist-cli/chunks/{storage-4TPN3NFB.js → storage-Z2DBO2PQ.js} +4 -4
- package/dist-cli/chunks/store-BYTCKNIC.js +4 -0
- package/dist-cli/chunks/telemetry-JLHFMD7N.js +4 -0
- package/dist-cli/chunks/{timeline-EX63UNWU.js → timeline-N7V2M6QA.js} +2 -2
- package/dist-cli/chunks/{upgrade-O6Y6EINE.js → upgrade-P2NH3BOR.js} +2 -2
- package/dist-cli/chunks/upload-Z2WX5DCD.js +4 -0
- package/dist-cli/chunks/{version-HLNL3NFB.js → version-OUHCSCUS.js} +2 -2
- package/dist-cli/chunks/{web-4EDPYPW7.js → web-6NRTF3UV.js} +2 -2
- package/dist-cli/chunks/welcome-6RS7PEJW.js +5 -0
- package/dist-cli/chunks/{what-happened-77VNUEPK.js → what-happened-FUEL3BEF.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.cjs +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 +18 -4
- package/dist-lib/home-paths.cjs +145 -11
- package/dist-lib/host/bridge-host.cjs +236 -31
- 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 +71 -4
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +337 -37
- 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 +484 -14
- 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 +25 -2
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +384 -385
- package/dist-lib/vite.cjs +193 -37
- package/package.json +2 -1
- package/scripts/dev-server-scanner.ts +12 -5
- package/skills/rnx-test/SKILL.md +4 -0
- package/src/dev-bundle-resolution.ts +13 -6
- package/src/dev-server-open.ts +197 -0
- package/src/home-paths.ts +168 -15
- package/src/host/bridge-host.ts +2 -2
- package/src/host/replacement-module-handler.ts +68 -2
- package/src/metro-plugin.ts +83 -5
- package/src/native-dev-bundle-url.ts +22 -0
- package/src/vite-plugin-one.ts +42 -28
- package/dist-cli/chunks/chunk-3JC7H4PR.js +0 -25
- package/dist-cli/chunks/chunk-6DLIC7BZ.js +0 -4
- package/dist-cli/chunks/chunk-7TNPO2OJ.js +0 -9
- package/dist-cli/chunks/chunk-AMF5KTOI.js +0 -4
- package/dist-cli/chunks/chunk-BX5VXTOQ.js +0 -101
- package/dist-cli/chunks/chunk-D73H7ACZ.js +0 -4
- package/dist-cli/chunks/chunk-DY4O7KYI.js +0 -4
- package/dist-cli/chunks/chunk-GU2V4JDG.js +0 -15
- package/dist-cli/chunks/chunk-Z2HMSVSN.js +0 -4
- package/dist-cli/chunks/cli-version-CN3NTKLH.js +0 -4
- package/dist-cli/chunks/config-SELKGT4F.js +0 -13
- package/dist-cli/chunks/daemon-V2SFCU2E.js +0 -4
- package/dist-cli/chunks/drivers-3YFTJ5WA.js +0 -4
- package/dist-cli/chunks/flow-36ANTMJU.js +0 -4
- package/dist-cli/chunks/help-ZGL26SPK.js +0 -4
- package/dist-cli/chunks/inspect-R3B55RTS.js +0 -4
- package/dist-cli/chunks/install-desktop-TZ3H3VWK.js +0 -4
- package/dist-cli/chunks/login-4DFULI7S.js +0 -28
- package/dist-cli/chunks/logout-QMCVYMBB.js +0 -4
- package/dist-cli/chunks/reset-O6MW6X7X.js +0 -4
- package/dist-cli/chunks/runtime-JESXBHRQ.js +0 -4
- package/dist-cli/chunks/serve-QGKTWPNF.js +0 -118
- package/dist-cli/chunks/setup-3WPWATCX.js +0 -32
- package/dist-cli/chunks/store-VBX3L46S.js +0 -4
- package/dist-cli/chunks/telemetry-ACNNIQIG.js +0 -4
- package/dist-cli/chunks/upload-OD2UQHMM.js +0 -4
package/cli/commands/control.ts
CHANGED
|
@@ -188,10 +188,15 @@ export async function ensureBridgeForOpen(
|
|
|
188
188
|
preferredPort: number,
|
|
189
189
|
explicitPort = false,
|
|
190
190
|
): Promise<number> {
|
|
191
|
-
if (await canConnectToBridge(preferredPort, 250)) return preferredPort
|
|
192
|
-
|
|
193
191
|
const lock = readDaemonLockfile()
|
|
194
192
|
assertExplicitBridgeLock(preferredPort, explicitPort, lock)
|
|
193
|
+
const preferredWorld = worldForBridgePort(preferredPort)
|
|
194
|
+
if (
|
|
195
|
+
(explicitPort || preferredWorld !== null) &&
|
|
196
|
+
(await canConnectToBridge(preferredPort, 250))
|
|
197
|
+
) {
|
|
198
|
+
return preferredPort
|
|
199
|
+
}
|
|
195
200
|
if (
|
|
196
201
|
lock &&
|
|
197
202
|
isDaemonLockfileFresh(lock) &&
|
|
@@ -227,12 +232,6 @@ export async function ensureBridgeForOpen(
|
|
|
227
232
|
)
|
|
228
233
|
return nextLock.bridgePort
|
|
229
234
|
}
|
|
230
|
-
if (await canConnectToBridge(preferredPort, 250)) {
|
|
231
|
-
console.error(
|
|
232
|
-
` started local bridge on port ${preferredPort}; run \`sootsim setup\` to install the background daemon`,
|
|
233
|
-
)
|
|
234
|
-
return preferredPort
|
|
235
|
-
}
|
|
236
235
|
if (childExit) {
|
|
237
236
|
throw new Error(`rnx bridge exited before becoming ready (exit ${childExit})`)
|
|
238
237
|
}
|
|
@@ -542,13 +541,9 @@ function parseOpenRuntimeConfig(args: string[]): SootSimConfig | undefined {
|
|
|
542
541
|
async function resolveOpenAppProject(
|
|
543
542
|
resolvedBundle?: ResolvedDevBundle,
|
|
544
543
|
): Promise<ResolvedAppProject | null> {
|
|
545
|
-
if (resolvedBundle)
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
return resolveAppProject(advertisedRoot, { trustStart: true })
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
return resolveAppProject(process.env.CONTRAST_REPO_DIR || process.cwd())
|
|
544
|
+
if (!resolvedBundle) return null
|
|
545
|
+
const advertisedRoot = await resolveMetroProjectRoot(resolvedBundle.bundleUrl)
|
|
546
|
+
return advertisedRoot ? resolveAppProject(advertisedRoot) : null
|
|
552
547
|
}
|
|
553
548
|
|
|
554
549
|
async function ensureConfiguredRuntime(version: string): Promise<void> {
|
|
@@ -616,16 +611,10 @@ async function stampAppFonts(
|
|
|
616
611
|
try {
|
|
617
612
|
const url = new URL(urlStr)
|
|
618
613
|
const bundleUrl = url.searchParams.get('bundle') || ''
|
|
619
|
-
if (!bundleUrl) return urlStr
|
|
620
|
-
// the dev server's project root identifies the exact app in a monorepo.
|
|
621
|
-
// CONTRAST_REPO_DIR is only the fallback for servers that do not advertise
|
|
622
|
-
// their root.
|
|
623
|
-
const repoDir =
|
|
624
|
-
project?.appDir ?? (await resolveMetroProjectRoot(bundleUrl)) ?? undefined
|
|
614
|
+
if (!bundleUrl || !project) return urlStr
|
|
625
615
|
const specs = discoverNativeLinkedAppFonts({
|
|
626
616
|
bundleUrl,
|
|
627
|
-
|
|
628
|
-
exactProjectDir: !!project || !!repoDir,
|
|
617
|
+
projectDir: project.appDir,
|
|
629
618
|
})
|
|
630
619
|
if (specs.length === 0) return urlStr
|
|
631
620
|
const reachable = await filterReachableAppFonts(specs)
|
|
@@ -716,13 +705,10 @@ async function stampAppSplash(
|
|
|
716
705
|
try {
|
|
717
706
|
const url = new URL(urlStr)
|
|
718
707
|
const bundleUrl = url.searchParams.get('bundle') || ''
|
|
719
|
-
if (!bundleUrl) return urlStr
|
|
720
|
-
const repoDir =
|
|
721
|
-
project?.appDir ?? (await resolveMetroProjectRoot(bundleUrl)) ?? undefined
|
|
708
|
+
if (!bundleUrl || !project) return urlStr
|
|
722
709
|
const spec = discoverConfigPluginAppSplash({
|
|
723
710
|
bundleUrl,
|
|
724
|
-
|
|
725
|
-
exactProjectDir: !!project || !!repoDir,
|
|
711
|
+
projectDir: project.appDir,
|
|
726
712
|
})
|
|
727
713
|
if (!spec) return urlStr
|
|
728
714
|
// HEAD-check the image before stamping so a typo'd/missing splash path never
|
|
@@ -1427,7 +1413,10 @@ export async function runLinkCommand(args: string[], opts: ControlCommandOptions
|
|
|
1427
1413
|
}
|
|
1428
1414
|
}
|
|
1429
1415
|
|
|
1430
|
-
export async function runOpenCommand(
|
|
1416
|
+
export async function runOpenCommand(
|
|
1417
|
+
args: string[],
|
|
1418
|
+
opts: ControlCommandOptions = {},
|
|
1419
|
+
): Promise<number | undefined> {
|
|
1431
1420
|
const parsed = parseBridgeCliArgs(args, {
|
|
1432
1421
|
port: opts.port,
|
|
1433
1422
|
commandTimeoutMs: opts.timeoutMs,
|
|
@@ -1748,7 +1737,7 @@ export async function runOpenCommand(args: string[], opts: ControlCommandOptions
|
|
|
1748
1737
|
))
|
|
1749
1738
|
printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, 'current sim')
|
|
1750
1739
|
await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args)
|
|
1751
|
-
return
|
|
1740
|
+
return parsed.wsPort
|
|
1752
1741
|
}
|
|
1753
1742
|
} finally {
|
|
1754
1743
|
bridge.close()
|
|
@@ -1827,6 +1816,7 @@ export async function runOpenCommand(args: string[], opts: ControlCommandOptions
|
|
|
1827
1816
|
signalDriverLaunchConnected(result)
|
|
1828
1817
|
printOpenedSim(openUrl, match, `${driver.name} driver`)
|
|
1829
1818
|
await maybeDescribeAfterOpen(parsed.wsPort, match.id, args)
|
|
1819
|
+
return parsed.wsPort
|
|
1830
1820
|
}
|
|
1831
1821
|
|
|
1832
1822
|
async function runUseLikeCommand(args: string[], opts: ControlCommandOptions = {}) {
|
package/cli/commands/daemon.ts
CHANGED
|
@@ -37,7 +37,6 @@ import {
|
|
|
37
37
|
} from '../../src/home-paths'
|
|
38
38
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
39
39
|
import { printCommandHelp } from '../help'
|
|
40
|
-
import { flushCliTelemetry, trackCliEvent } from '../telemetry'
|
|
41
40
|
import { ensureDaemonApp } from './daemon-mac-app'
|
|
42
41
|
|
|
43
42
|
// minimum seconds between launchd / systemd respawns. without this, a daemon
|
|
@@ -65,49 +64,25 @@ export async function runDaemon(args: string[], opts: DaemonOptions = {}) {
|
|
|
65
64
|
return
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'
|
|
76
|
-
|
|
77
|
-
'start'
|
|
78
|
-
|
|
79
|
-
'
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
switch (sub) {
|
|
90
|
-
case 'install':
|
|
91
|
-
return await daemonInstall({ port, force: rest.includes('--force') })
|
|
92
|
-
case 'uninstall':
|
|
93
|
-
return await daemonUninstall()
|
|
94
|
-
case 'status':
|
|
95
|
-
return await daemonStatus()
|
|
96
|
-
case 'restart':
|
|
97
|
-
return await daemonRestart()
|
|
98
|
-
case 'start':
|
|
99
|
-
return await daemonStart()
|
|
100
|
-
case 'stop':
|
|
101
|
-
return await daemonStop()
|
|
102
|
-
case 'logs':
|
|
103
|
-
return await daemonLogs(rest)
|
|
104
|
-
default:
|
|
105
|
-
console.error(` unknown daemon subcommand: ${sub}`)
|
|
106
|
-
printHelp()
|
|
107
|
-
process.exit(1)
|
|
108
|
-
}
|
|
109
|
-
} finally {
|
|
110
|
-
await flushCliTelemetry()
|
|
67
|
+
switch (sub) {
|
|
68
|
+
case 'install':
|
|
69
|
+
return daemonInstall({ port, force: rest.includes('--force') })
|
|
70
|
+
case 'uninstall':
|
|
71
|
+
return daemonUninstall()
|
|
72
|
+
case 'status':
|
|
73
|
+
return daemonStatus()
|
|
74
|
+
case 'restart':
|
|
75
|
+
return daemonRestart()
|
|
76
|
+
case 'start':
|
|
77
|
+
return daemonStart()
|
|
78
|
+
case 'stop':
|
|
79
|
+
return daemonStop()
|
|
80
|
+
case 'logs':
|
|
81
|
+
return daemonLogs(rest)
|
|
82
|
+
default:
|
|
83
|
+
console.error(` unknown daemon subcommand: ${sub}`)
|
|
84
|
+
printHelp()
|
|
85
|
+
process.exit(1)
|
|
111
86
|
}
|
|
112
87
|
}
|
|
113
88
|
|
package/cli/commands/flow.ts
CHANGED
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
keepFlowCandidate,
|
|
24
24
|
startFlowSession,
|
|
25
25
|
} from '../flow-session'
|
|
26
|
-
import { flushCliTelemetry, trackCliEvent } from '../telemetry'
|
|
27
26
|
import { createBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
|
|
28
27
|
import {
|
|
29
28
|
buildShellUrl,
|
|
@@ -334,26 +333,6 @@ flow extension:
|
|
|
334
333
|
${steps.length} steps | ${mode}${appLabel}${record ? ' | recording' : ''}${profile ? ' | profiling' : ''}${slow ? ` | ${slow}ms delay` : ''}
|
|
335
334
|
`)
|
|
336
335
|
|
|
337
|
-
// only meter flows that will result in a cloud preview upload. plain
|
|
338
|
-
// flow playback + local recording stay completely unmetered per the
|
|
339
|
-
// free/pro/enterprise beta plan (local usage is free). server emits
|
|
340
|
-
// the authoritative preview_upload events when the chained upload
|
|
341
|
-
// actually lands.
|
|
342
|
-
if (preview) {
|
|
343
|
-
trackCliEvent({
|
|
344
|
-
event: 'preview_flow_started',
|
|
345
|
-
properties: {
|
|
346
|
-
flowName: path.basename(flowPath),
|
|
347
|
-
stepCount: steps.length,
|
|
348
|
-
mode,
|
|
349
|
-
electron: wantElectron,
|
|
350
|
-
record,
|
|
351
|
-
profile,
|
|
352
|
-
previewOrigin,
|
|
353
|
-
},
|
|
354
|
-
})
|
|
355
|
-
}
|
|
356
|
-
|
|
357
336
|
let openTarget = url || targetApp || ''
|
|
358
337
|
const effectiveOpenInNewSim =
|
|
359
338
|
openInNewSim || (wantElectron && parsedBridgeArgs.simIdSource !== 'flag')
|
|
@@ -392,7 +371,6 @@ flow extension:
|
|
|
392
371
|
const discovered = await discoverSootsimUrl()
|
|
393
372
|
if (!discovered) {
|
|
394
373
|
console.error(' error: no current sim and no sootsim target found')
|
|
395
|
-
await flushCliTelemetry()
|
|
396
374
|
process.exit(1)
|
|
397
375
|
}
|
|
398
376
|
openTarget = discovered
|
|
@@ -832,11 +810,6 @@ flow extension:
|
|
|
832
810
|
saveCurrentSimId(driver.simId)
|
|
833
811
|
}
|
|
834
812
|
|
|
835
|
-
// flush before returning to caller — caller typically calls
|
|
836
|
-
// process.exit(returnedCode), and node's `exit` hook can't await, so
|
|
837
|
-
// without this the flow telemetry (and any chained upload's events)
|
|
838
|
-
// get silently dropped.
|
|
839
|
-
await flushCliTelemetry()
|
|
840
813
|
return exitCode
|
|
841
814
|
}
|
|
842
815
|
|
|
@@ -146,10 +146,10 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
146
146
|
throw new Error(`could not determine dmg mount point (output: ${mountOutput.stdout})`)
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
const appSource = join(mountPoint, '
|
|
149
|
+
const appSource = join(mountPoint, 'rnx.app')
|
|
150
150
|
if (!existsSync(appSource)) {
|
|
151
151
|
spawnSync('hdiutil', ['detach', '-force', mountPoint])
|
|
152
|
-
throw new Error(`
|
|
152
|
+
throw new Error(`rnx.app not found inside ${mountPoint}`)
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// prefer /Applications if writable, otherwise ~/Applications (same paths
|
|
@@ -319,24 +319,10 @@ examples:
|
|
|
319
319
|
console.log()
|
|
320
320
|
console.log(` installing...`)
|
|
321
321
|
|
|
322
|
-
const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
|
|
323
|
-
|
|
324
322
|
try {
|
|
325
323
|
const installedAt = await target.install(downloadPath)
|
|
326
|
-
trackCliEvent({
|
|
327
|
-
event: 'cli_install_desktop_succeeded',
|
|
328
|
-
properties: { platform: target.platform, size_bytes: size },
|
|
329
|
-
})
|
|
330
324
|
console.log(` installed: ${installedAt}`)
|
|
331
325
|
} catch (err) {
|
|
332
|
-
trackCliEvent({
|
|
333
|
-
event: 'cli_install_desktop_failed',
|
|
334
|
-
properties: {
|
|
335
|
-
platform: target.platform,
|
|
336
|
-
error: err instanceof Error ? err.message : String(err),
|
|
337
|
-
},
|
|
338
|
-
})
|
|
339
|
-
await flushCliTelemetry()
|
|
340
326
|
console.error(` install failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
341
327
|
console.error(` keeping download at ${downloadPath} for manual install.`)
|
|
342
328
|
process.exit(1)
|
package/cli/commands/login.ts
CHANGED
|
@@ -8,22 +8,15 @@ import {
|
|
|
8
8
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
9
9
|
|
|
10
10
|
const REMOTE_DEFAULT_ORIGIN = process.env.SOOTSIM_AUTH_ORIGIN || 'https://contrast.dev'
|
|
11
|
-
const LOCAL_DEFAULT_ORIGIN = 'https://contrast.localhost:3000'
|
|
12
11
|
|
|
13
12
|
type LoginResult =
|
|
14
13
|
| { ok: true; token: string; userId?: string; email?: string }
|
|
15
14
|
| { ok: false; error: string }
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
function resolveDefaultAuthOrigin(explicitOrigin?: string) {
|
|
18
17
|
if (explicitOrigin) return explicitOrigin
|
|
19
18
|
if (process.env.SOOTSIM_AUTH_ORIGIN) return process.env.SOOTSIM_AUTH_ORIGIN
|
|
20
19
|
if (process.env.SOOTSIM_UPLOAD_ORIGIN) return process.env.SOOTSIM_UPLOAD_ORIGIN
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const res = await fetch(`${LOCAL_DEFAULT_ORIGIN}/api/auth/me`)
|
|
24
|
-
if (res.ok) return LOCAL_DEFAULT_ORIGIN
|
|
25
|
-
} catch {}
|
|
26
|
-
|
|
27
20
|
return REMOTE_DEFAULT_ORIGIN
|
|
28
21
|
}
|
|
29
22
|
|
|
@@ -35,9 +28,7 @@ usage:
|
|
|
35
28
|
rnx login [--origin <url>]
|
|
36
29
|
|
|
37
30
|
options:
|
|
38
|
-
--origin <url> auth host (default:
|
|
39
|
-
prefers ${LOCAL_DEFAULT_ORIGIN} when available, otherwise
|
|
40
|
-
falls back to ${REMOTE_DEFAULT_ORIGIN}
|
|
31
|
+
--origin <url> auth host (default: ${REMOTE_DEFAULT_ORIGIN})
|
|
41
32
|
override with SOOTSIM_AUTH_ORIGIN env var
|
|
42
33
|
-h, --help
|
|
43
34
|
`)
|
|
@@ -154,9 +145,7 @@ export async function runLogin(args: string[]) {
|
|
|
154
145
|
}
|
|
155
146
|
|
|
156
147
|
const mutableArgs = [...args]
|
|
157
|
-
const origin =
|
|
158
|
-
extractStringFlag(mutableArgs, '--origin'),
|
|
159
|
-
)
|
|
148
|
+
const origin = resolveDefaultAuthOrigin(extractStringFlag(mutableArgs, '--origin'))
|
|
160
149
|
|
|
161
150
|
// in dev (localhost), skip the browser and sign in as the shared dev
|
|
162
151
|
// user via POST /api/dev-login. the no-device contract is local-only, so this
|
|
@@ -177,13 +166,6 @@ export async function runLogin(args: string[]) {
|
|
|
177
166
|
devResult.email ||
|
|
178
167
|
refreshed?.user?.id ||
|
|
179
168
|
devResult.userId
|
|
180
|
-
const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
|
|
181
|
-
trackCliEvent({
|
|
182
|
-
event: 'cli_login_succeeded',
|
|
183
|
-
identity: { userId: devResult.userId ?? refreshed?.user?.id ?? null },
|
|
184
|
-
properties: { origin, mode: 'dev' },
|
|
185
|
-
})
|
|
186
|
-
await flushCliTelemetry()
|
|
187
169
|
console.log(` signed in${label ? ` as ${label}` : ''} (dev)`)
|
|
188
170
|
return
|
|
189
171
|
}
|
|
@@ -192,15 +174,6 @@ export async function runLogin(args: string[]) {
|
|
|
192
174
|
|
|
193
175
|
const state = randomBytes(16).toString('hex')
|
|
194
176
|
|
|
195
|
-
// flush a start event BEFORE the browser wait: queued telemetry only drains
|
|
196
|
-
// on process exit, so a login that hangs (or gets ctrl+c'd) would otherwise
|
|
197
|
-
// leave zero trace. first-time-user hangs were invisible in posthog.
|
|
198
|
-
{
|
|
199
|
-
const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
|
|
200
|
-
trackCliEvent({ event: 'cli_login_started', properties: { origin } })
|
|
201
|
-
await flushCliTelemetry()
|
|
202
|
-
}
|
|
203
|
-
|
|
204
177
|
// the browser round-trip needs human action (github's authorize screen on
|
|
205
178
|
// first sign-in), so the wait is generous, but it must not be infinite: a
|
|
206
179
|
// closed tab, denied consent, or blocked popup used to hang the CLI forever.
|
|
@@ -295,12 +268,6 @@ export async function runLogin(args: string[]) {
|
|
|
295
268
|
})
|
|
296
269
|
|
|
297
270
|
if (!result.ok) {
|
|
298
|
-
const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
|
|
299
|
-
trackCliEvent({
|
|
300
|
-
event: 'cli_login_failed',
|
|
301
|
-
properties: { origin, error: result.error },
|
|
302
|
-
})
|
|
303
|
-
await flushCliTelemetry()
|
|
304
271
|
console.error(` login failed: ${result.error}`)
|
|
305
272
|
process.exit(1)
|
|
306
273
|
}
|
|
@@ -320,12 +287,5 @@ export async function runLogin(args: string[]) {
|
|
|
320
287
|
const refreshed = await refreshSharedDesktopAuthSession(origin)
|
|
321
288
|
const label =
|
|
322
289
|
refreshed?.user?.email || result.email || refreshed?.user?.id || result.userId
|
|
323
|
-
const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
|
|
324
|
-
trackCliEvent({
|
|
325
|
-
event: 'cli_login_succeeded',
|
|
326
|
-
identity: { userId: result.userId ?? refreshed?.user?.id ?? null },
|
|
327
|
-
properties: { origin },
|
|
328
|
-
})
|
|
329
|
-
await flushCliTelemetry()
|
|
330
290
|
console.log(` signed in${label ? ` as ${label}` : ''}`)
|
|
331
291
|
}
|
package/cli/commands/logout.ts
CHANGED
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
clearSharedDesktopAuthSession,
|
|
3
3
|
readSharedDesktopAuthSession,
|
|
4
4
|
} from '../../src/auth/shared-session'
|
|
5
|
-
import { flushCliTelemetry, trackCliEvent } from '../telemetry'
|
|
6
5
|
|
|
7
6
|
export async function runLogout() {
|
|
8
7
|
const current = readSharedDesktopAuthSession()
|
|
@@ -21,11 +20,5 @@ export async function runLogout() {
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
clearSharedDesktopAuthSession()
|
|
24
|
-
trackCliEvent({
|
|
25
|
-
event: 'cli_logout',
|
|
26
|
-
identity: { userId: current.user?.id ?? null },
|
|
27
|
-
properties: { origin: current.origin },
|
|
28
|
-
})
|
|
29
|
-
await flushCliTelemetry()
|
|
30
23
|
console.log(' signed out')
|
|
31
24
|
}
|
package/cli/commands/serve.ts
CHANGED
|
@@ -15,21 +15,8 @@ import {
|
|
|
15
15
|
readDaemonLockfile,
|
|
16
16
|
} from '../../src/home-paths'
|
|
17
17
|
import { SootSimBridgeHost } from '../../src/host/bridge-host'
|
|
18
|
-
import { flushCliTelemetry, trackCliEvent } from '../telemetry'
|
|
19
18
|
import { resolveDefaultUploadOrigin } from './upload'
|
|
20
19
|
|
|
21
|
-
// launchd sets `XPC_SERVICE_NAME` to the agent label and systemd sets
|
|
22
|
-
// `INVOCATION_ID` for unit-managed processes. either tells us this bridge
|
|
23
|
-
// boot is the daemon firing rather than a user running `sootsim serve`
|
|
24
|
-
// in a terminal — useful for filtering daemon traffic in posthog.
|
|
25
|
-
//
|
|
26
|
-
function runningUnderDaemon(): boolean {
|
|
27
|
-
const xpc = process.env.XPC_SERVICE_NAME || ''
|
|
28
|
-
if (xpc.includes('dev.sootsim.daemon')) return true
|
|
29
|
-
if (process.env.INVOCATION_ID) return true
|
|
30
|
-
return false
|
|
31
|
-
}
|
|
32
|
-
|
|
33
20
|
interface ServeOptions {
|
|
34
21
|
port?: number
|
|
35
22
|
}
|
|
@@ -81,9 +68,8 @@ examples:
|
|
|
81
68
|
}
|
|
82
69
|
|
|
83
70
|
ensureSootsimHome()
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
// to the same origin the CLI's own entitlement + upload paths use.
|
|
71
|
+
// use the explicit upload/auth origin when configured, otherwise production.
|
|
72
|
+
// never probe a local Contrast stack during bridge startup.
|
|
87
73
|
const contrastOrigin = await resolveDefaultUploadOrigin()
|
|
88
74
|
const host = new SootSimBridgeHost({
|
|
89
75
|
port,
|
|
@@ -115,22 +101,6 @@ examples:
|
|
|
115
101
|
for (const id of currentIds) lastSimIds.add(id)
|
|
116
102
|
}, 500)
|
|
117
103
|
|
|
118
|
-
// single boot heartbeat so we know the bridge is alive on this machine.
|
|
119
|
-
// not periodic — frequency would pollute posthog volumes for no signal.
|
|
120
|
-
// explicitly flush: this process pins the event loop with a never-
|
|
121
|
-
// resolving promise (line 155), so beforeExit will not fire and the
|
|
122
|
-
// event would otherwise sit in the queue until SIGTERM dropped it.
|
|
123
|
-
trackCliEvent({
|
|
124
|
-
event: 'daemon_heartbeat',
|
|
125
|
-
properties: {
|
|
126
|
-
bridge_port: boundPort,
|
|
127
|
-
under_daemon: runningUnderDaemon(),
|
|
128
|
-
platform: process.platform,
|
|
129
|
-
subsource: 'daemon',
|
|
130
|
-
},
|
|
131
|
-
})
|
|
132
|
-
void flushCliTelemetry()
|
|
133
|
-
|
|
134
104
|
log(`rnx bridge listening on ws://localhost:${boundPort} (runtime http on same port)`)
|
|
135
105
|
if (boundPort !== port) {
|
|
136
106
|
log(` (preferred port ${port} was taken — fell back to ${boundPort})`)
|