rnxsim 0.1.313 → 0.1.314
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/LICENSE +11 -10
- package/README.md +5 -0
- package/cli/app-config.ts +65 -0
- package/cli/app-fonts.ts +408 -0
- package/cli/app-project.ts +231 -0
- package/cli/app-splash.ts +185 -0
- package/cli/app-state-reset.ts +24 -0
- package/cli/auth.ts +155 -0
- package/cli/bin.ts +594 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2830 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/commands/agent-wrapper.ts +986 -0
- package/cli/commands/agent.ts +423 -0
- package/cli/commands/app-fonts.ts +98 -0
- package/cli/commands/assert.ts +541 -0
- package/cli/commands/auth.ts +59 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +87 -0
- package/cli/commands/config.ts +32 -0
- package/cli/commands/control.ts +2142 -0
- package/cli/commands/cpu-profile.ts +269 -0
- package/cli/commands/daemon-mac-app.ts +169 -0
- package/cli/commands/daemon.ts +874 -0
- package/cli/commands/debug.ts +719 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +197 -0
- package/cli/commands/detox.ts +385 -0
- package/cli/commands/device.ts +133 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/electron.ts +95 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1124 -0
- package/cli/commands/inspect/actions.ts +622 -0
- package/cli/commands/inspect/core.ts +2405 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +192 -0
- package/cli/commands/inspect/env.ts +23 -0
- package/cli/commands/inspect/find.ts +171 -0
- package/cli/commands/inspect/get-layout.ts +39 -0
- package/cli/commands/inspect/keyboard.ts +52 -0
- package/cli/commands/inspect/list.ts +58 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +82 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +22 -0
- package/cli/commands/inspect/settling.ts +158 -0
- package/cli/commands/inspect/shared.ts +353 -0
- package/cli/commands/inspect/sleep.ts +14 -0
- package/cli/commands/inspect/tree.ts +32 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +210 -0
- package/cli/commands/inspect/wait-idle.ts +24 -0
- package/cli/commands/inspect/wait-ready.ts +74 -0
- package/cli/commands/inspect/wait-selector.ts +54 -0
- package/cli/commands/inspect/wait.ts +31 -0
- package/cli/commands/inspect.ts +4519 -0
- package/cli/commands/install-desktop.ts +351 -0
- package/cli/commands/login.ts +331 -0
- package/cli/commands/logout.ts +31 -0
- package/cli/commands/maestro-generate.ts +361 -0
- package/cli/commands/maestro.ts +453 -0
- package/cli/commands/mode.ts +57 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +66 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/profile.ts +108 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1434 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +85 -0
- package/cli/commands/runtime.ts +351 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +143 -0
- package/cli/commands/screenshot-mode.ts +37 -0
- package/cli/commands/screenshot.ts +488 -0
- package/cli/commands/screenshots-capture.ts +607 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +168 -0
- package/cli/commands/setup.ts +545 -0
- package/cli/commands/shell-boolean-mode.ts +81 -0
- package/cli/commands/skills.ts +467 -0
- package/cli/commands/slides.ts +361 -0
- package/cli/commands/state.ts +87 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +54 -0
- package/cli/commands/three-mode.ts +763 -0
- package/cli/commands/timeline.ts +122 -0
- package/cli/commands/upgrade.ts +208 -0
- package/cli/commands/upload.ts +1225 -0
- package/cli/commands/version.ts +54 -0
- package/cli/commands/what-happened.ts +327 -0
- package/cli/current-sim.ts +204 -0
- package/cli/desktop-companion.ts +300 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +180 -0
- package/cli/drivers/playwright.ts +698 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +120 -0
- package/cli/flow-session.ts +187 -0
- package/cli/help.ts +80 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +216 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/maestro-js.ts +334 -0
- package/cli/open-url.ts +8 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +211 -0
- package/cli/prompt.ts +51 -0
- package/cli/recording-access.ts +107 -0
- package/cli/registry.ts +1 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/run-registry.ts +226 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/setup-repository.ts +187 -0
- package/cli/telemetry.ts +187 -0
- package/cli/ws-bridge.ts +798 -0
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-XZ2KTPCU.js → agent-7YBDCYMA.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-JJYYW2WH.js → agent-wrapper-2GHFBHCR.js} +2 -2
- package/dist-cli/chunks/{app-fonts-IXRNQG6B.js → app-fonts-RSNVPQSU.js} +2 -2
- package/dist-cli/chunks/{assert-54T5SK5F.js → assert-XCMX3XJX.js} +2 -2
- package/dist-cli/chunks/{auth-FI5UDI45.js → auth-B442HRAX.js} +2 -2
- package/dist-cli/chunks/{beta-JV6UKADW.js → beta-XJ55JK3M.js} +2 -2
- package/dist-cli/chunks/camera-UGYSSLIK.js +33 -0
- package/dist-cli/chunks/{chunk-3NV2NCNX.js → chunk-277AEQZX.js} +2 -2
- package/dist-cli/chunks/{chunk-2YR5BGA5.js → chunk-2JNSK774.js} +2 -2
- package/dist-cli/chunks/{chunk-RSZWCKNT.js → chunk-32WOTSTR.js} +3 -3
- package/dist-cli/chunks/{chunk-WEXDAC74.js → chunk-3S753SNQ.js} +2 -2
- package/dist-cli/chunks/{chunk-IJO63TDP.js → chunk-46ZOLOYA.js} +2 -2
- package/dist-cli/chunks/{chunk-WUSWBCWA.js → chunk-5L7ELDQL.js} +8 -9
- package/dist-cli/chunks/{chunk-WF3T4SVI.js → chunk-7OOPFSQS.js} +2 -2
- package/dist-cli/chunks/{chunk-TZFFR3SD.js → chunk-7SV3RPRW.js} +2 -2
- package/dist-cli/chunks/{chunk-WWZIXIRD.js → chunk-7ZC35MOU.js} +1 -1
- package/dist-cli/chunks/chunk-AMG5E6CC.js +9 -0
- package/dist-cli/chunks/{chunk-WINYQ44O.js → chunk-APWNH3A4.js} +1 -1
- package/dist-cli/chunks/chunk-B57XUKY3.js +4 -0
- package/dist-cli/chunks/{chunk-YDGQTMQL.js → chunk-C2NL26TD.js} +1 -1
- package/dist-cli/chunks/{chunk-NMF2ZMZQ.js → chunk-D2FNUWAB.js} +4 -4
- package/dist-cli/chunks/{chunk-YIFT42WN.js → chunk-E5T4XSJ3.js} +2 -2
- package/dist-cli/chunks/{chunk-46EUUFJ5.js → chunk-EAC34EQS.js} +1 -1
- package/dist-cli/chunks/{chunk-OVFJFXUD.js → chunk-EG32ML36.js} +2 -2
- package/dist-cli/chunks/{chunk-5YJCOWCH.js → chunk-FXUAC6D5.js} +1 -1
- package/dist-cli/chunks/chunk-GQSL4USA.js +6 -0
- package/dist-cli/chunks/{chunk-VFCMSYZK.js → chunk-HAXW27SS.js} +2 -2
- package/dist-cli/chunks/{chunk-2D2UPBBR.js → chunk-IZAHPAN6.js} +1 -1
- package/dist-cli/chunks/{chunk-7GN3LVWB.js → chunk-J62KM5TB.js} +2 -2
- package/dist-cli/chunks/{chunk-BTWORNNG.js → chunk-JEMCD5E4.js} +1 -1
- package/dist-cli/chunks/{chunk-DCEMHR2Y.js → chunk-JZS3Q37N.js} +2 -2
- package/dist-cli/chunks/{chunk-D4FFVGI5.js → chunk-KR4JON7D.js} +1 -1
- package/dist-cli/chunks/chunk-KWCYKQIQ.js +4 -0
- package/dist-cli/chunks/{chunk-VNQEB4L7.js → chunk-MCWPL644.js} +2 -2
- package/dist-cli/chunks/chunk-MJYK3N2I.js +4 -0
- package/dist-cli/chunks/{chunk-5TEF3ET3.js → chunk-O6TRIZNS.js} +2 -2
- package/dist-cli/chunks/{chunk-QKDWYITG.js → chunk-P7XL2E73.js} +3 -3
- package/dist-cli/chunks/{chunk-BBULZ7CG.js → chunk-PFQTUKQ4.js} +62 -87
- package/dist-cli/chunks/{chunk-GGRX24GF.js → chunk-PG5RZCTN.js} +2 -2
- package/dist-cli/chunks/{chunk-W6K4EFPH.js → chunk-QGRI2Z4M.js} +2 -2
- package/dist-cli/chunks/{chunk-ZMJD5GEC.js → chunk-QLXXE7GE.js} +1 -1
- package/dist-cli/chunks/{chunk-VZXWHRUZ.js → chunk-QOJJJWJE.js} +89 -133
- package/dist-cli/chunks/{chunk-OZSSI4WN.js → chunk-RWZY5427.js} +2 -2
- package/dist-cli/chunks/{chunk-UC6U3MML.js → chunk-RZKU2K3J.js} +2 -2
- package/dist-cli/chunks/{chunk-IJ5CAZZC.js → chunk-SBV4IK4H.js} +1 -1
- package/dist-cli/chunks/{chunk-DZS6WPUI.js → chunk-SGMVFFMK.js} +1 -1
- package/dist-cli/chunks/{chunk-OHAZNXLK.js → chunk-TAX4UT2N.js} +1 -1
- package/dist-cli/chunks/{chunk-5DHC6KHQ.js → chunk-TUOFAWXT.js} +1 -1
- package/dist-cli/chunks/{chunk-GASE6UBA.js → chunk-UHZLOHGP.js} +1 -1
- package/dist-cli/chunks/{chunk-F5ZRSS3C.js → chunk-VC7V76U3.js} +1 -1
- package/dist-cli/chunks/{chunk-RTN5C5RL.js → chunk-VQVMLW4U.js} +1 -1
- package/dist-cli/chunks/{chunk-WMIIKMGK.js → chunk-VUKKYPZN.js} +2 -2
- package/dist-cli/chunks/{chunk-5TPRP5QT.js → chunk-WGGRJDRE.js} +1 -1
- package/dist-cli/chunks/chunk-X6H76EKP.js +15 -0
- package/dist-cli/chunks/chunk-XLZ5FNRT.js +27 -0
- package/dist-cli/chunks/{chunk-HI5TFJWN.js → chunk-XULEACM4.js} +2 -2
- package/dist-cli/chunks/{chunk-MJRLLB4R.js → chunk-YFSDM7AX.js} +4 -4
- package/dist-cli/chunks/chunk-YWI3UEVX.js +5 -0
- package/dist-cli/chunks/{chunk-XEVZYVIW.js → chunk-ZBSJO4NB.js} +10 -9
- package/dist-cli/chunks/{cleanup-P27PA6JI.js → cleanup-EYLGCA6Z.js} +2 -2
- package/dist-cli/chunks/cli-version-LL2UGIHE.js +4 -0
- package/dist-cli/chunks/{compat-ZD65FED3.js → compat-TLJYHB4E.js} +2 -2
- package/dist-cli/chunks/{config-XMJRNM2A.js → config-4JWUOEXK.js} +2 -2
- package/dist-cli/chunks/{control-KMIQT3QP.js → control-HPAOYF4N.js} +2 -2
- package/dist-cli/chunks/daemon-OYLASXLE.js +4 -0
- package/dist-cli/chunks/{debug-PT4HOP7N.js → debug-4BKXF6KI.js} +5 -5
- package/dist-cli/chunks/{desktop-S3FG72AK.js → desktop-ZQ6ZD2S6.js} +3 -3
- package/dist-cli/chunks/{detox-B3D4IFCN.js → detox-WNPASSS3.js} +2 -2
- package/dist-cli/chunks/{device-XBNDSB2R.js → device-BXLXVG3V.js} +2 -2
- package/dist-cli/chunks/{diagnose-HMQXJE5N.js → diagnose-3QX7W5RW.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-BLCZ5BSZ.js → disk-cleanup-KSWKI7WB.js} +2 -2
- package/dist-cli/chunks/drivers-EPIEFF7P.js +4 -0
- package/dist-cli/chunks/{film-BJGTBYZB.js → film-GDMR33VO.js} +3 -3
- package/dist-cli/chunks/flow-NKMPBYCJ.js +4 -0
- package/dist-cli/chunks/help-OGCBHOKA.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-ANOYADHM.js → hidden-runtime-alias-S2GTDX3T.js} +2 -2
- package/dist-cli/chunks/home-paths-QRCDLTTV.js +4 -0
- package/dist-cli/chunks/inspect-FUYMOZPY.js +4 -0
- package/dist-cli/chunks/install-desktop-FR6YKW7Y.js +4 -0
- package/dist-cli/chunks/{login-FJ737MWG.js → login-IJAPUZHI.js} +4 -4
- package/dist-cli/chunks/{logout-ZCNMMHMY.js → logout-QMXDFU2X.js} +2 -2
- package/dist-cli/chunks/{maestro-SZTNKLDF.js → maestro-ZXU3YCVX.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-DCFAIZ4H.js → maestro-generate-PYB5QY7K.js} +3 -3
- package/dist-cli/chunks/{mode-GRMQCRXR.js → mode-WGUCL5FZ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-W36EWFFB.js → optional-demo-registry-WH2O6H36.js} +2 -2
- package/dist-cli/chunks/{perf-QYBAAUZG.js → perf-TOD3UFAH.js} +2 -2
- package/dist-cli/chunks/{permissions-3QCQ6VF4.js → permissions-I5BRJGTB.js} +2 -2
- package/dist-cli/chunks/{record-QPPC2S4E.js → record-ZYL2FYSK.js} +3 -3
- package/dist-cli/chunks/{report-issue-7NMFP4HK.js → report-issue-TAI6DYZO.js} +2 -2
- package/dist-cli/chunks/reset-7YGYKQPQ.js +4 -0
- package/dist-cli/chunks/runtime-B4JO6QRI.js +4 -0
- package/dist-cli/chunks/{screenshot-command-67AECJFB.js → screenshot-command-7ANLODZY.js} +7 -7
- package/dist-cli/chunks/{screenshot-layers-ASWBYPJL.js → screenshot-layers-A7FYXSVU.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-PXA3HFQK.js → screenshots-capture-WT2ZY6CB.js} +2 -2
- package/dist-cli/chunks/serve-TG5WKA4V.js +44 -0
- package/dist-cli/chunks/{setup-7DWPMRSB.js → setup-PCWLD22V.js} +2 -2
- package/dist-cli/chunks/{skills-S3Y22TUA.js → skills-27ZHWCQS.js} +2 -2
- package/dist-cli/chunks/state-ZQVY46ZO.js +14 -0
- package/dist-cli/chunks/{storage-XUIMJWAJ.js → storage-OYC57C4X.js} +6 -6
- package/dist-cli/chunks/store-32HSPZHI.js +4 -0
- package/dist-cli/chunks/telemetry-PBJR7XHR.js +4 -0
- package/dist-cli/chunks/{timeline-TMPLQPSP.js → timeline-RAJJFQT6.js} +2 -2
- package/dist-cli/chunks/{upgrade-7HDSIM7K.js → upgrade-OEFNZRIP.js} +2 -2
- package/dist-cli/chunks/upload-LQJITLKK.js +4 -0
- package/dist-cli/chunks/version-NIXTY6PL.js +6 -0
- package/dist-cli/chunks/{web-DG3WBYD3.js → web-XBUTBVGR.js} +2 -2
- package/dist-cli/chunks/{what-happened-XFVUTZR7.js → what-happened-YNHRFUDX.js} +3 -3
- 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 +20 -0
- 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 +67 -28
- package/dist-lib/host/bridge-host.cjs +140 -12
- 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/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2815 -40
- 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.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +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 +2549 -2061
- package/dist-lib/sdk.mjs +2543 -2061
- package/dist-lib/skills.cjs +480 -280
- package/dist-lib/vite.cjs +1 -1
- package/package.json +8 -2
- package/src/bridge-constants.ts +3 -4
- package/src/bridge-contract.ts +251 -0
- package/src/connect.ts +83 -0
- package/src/disk-cleanup.ts +30 -0
- package/src/home-paths.ts +81 -38
- package/src/host/bridge-host.ts +134 -6
- package/src/index.ts +27 -1
- package/src/sdk.ts +8 -0
- package/src/sim-client.ts +660 -0
- package/dist-cli/chunks/camera-VL73YIKP.js +0 -22
- package/dist-cli/chunks/chunk-4NPPOV2N.js +0 -5
- package/dist-cli/chunks/chunk-FSUYIVJ6.js +0 -9
- package/dist-cli/chunks/chunk-G2WW6L2C.js +0 -23
- package/dist-cli/chunks/chunk-KTHV3RUS.js +0 -26
- package/dist-cli/chunks/chunk-LF2ZVT7O.js +0 -6
- package/dist-cli/chunks/chunk-NFK7T35W.js +0 -4
- package/dist-cli/chunks/chunk-TIVZIMMW.js +0 -4
- package/dist-cli/chunks/cli-version-WWLPBDQ7.js +0 -4
- package/dist-cli/chunks/daemon-G2ME7NLB.js +0 -4
- package/dist-cli/chunks/drivers-LDECZGP2.js +0 -4
- package/dist-cli/chunks/flow-UEQNVTU7.js +0 -4
- package/dist-cli/chunks/help-T5FYSVGB.js +0 -4
- package/dist-cli/chunks/home-paths-GT3LFNOR.js +0 -4
- package/dist-cli/chunks/inspect-ZA6XF5LD.js +0 -4
- package/dist-cli/chunks/install-desktop-TIMUDHPL.js +0 -4
- package/dist-cli/chunks/runtime-XOAXMSTU.js +0 -4
- package/dist-cli/chunks/serve-BI2NBAXG.js +0 -44
- package/dist-cli/chunks/store-JTHEJLAZ.js +0 -4
- package/dist-cli/chunks/telemetry-ZYJGD2DB.js +0 -4
- package/dist-cli/chunks/upload-GMSZPWM6.js +0 -4
- package/dist-cli/chunks/version-HOCHZ37L.js +0 -6
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearSharedDesktopAuthSession,
|
|
3
|
+
readSharedDesktopAuthSession,
|
|
4
|
+
} from '../../src/auth/shared-session'
|
|
5
|
+
import { flushCliTelemetry, trackCliEvent } from '../telemetry'
|
|
6
|
+
|
|
7
|
+
export async function runLogout() {
|
|
8
|
+
const current = readSharedDesktopAuthSession()
|
|
9
|
+
if (!current?.token) {
|
|
10
|
+
console.log(' not signed in')
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
await fetch(`${current.origin.replace(/\/$/, '')}/api/auth/sign-out`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: { authorization: `Bearer ${current.token}` },
|
|
18
|
+
})
|
|
19
|
+
} catch {
|
|
20
|
+
// best-effort only
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
clearSharedDesktopAuthSession()
|
|
24
|
+
trackCliEvent({
|
|
25
|
+
event: 'cli_logout',
|
|
26
|
+
identity: { userId: current.user?.id ?? null },
|
|
27
|
+
properties: { origin: current.origin },
|
|
28
|
+
})
|
|
29
|
+
await flushCliTelemetry()
|
|
30
|
+
console.log(' signed out')
|
|
31
|
+
}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
// plain-language Maestro authoring for `sootsim maestro generate`.
|
|
2
|
+
|
|
3
|
+
import { mkdtempSync, writeFileSync } from 'fs'
|
|
4
|
+
import { tmpdir } from 'os'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
import yaml from 'yaml'
|
|
7
|
+
import { authHeaderValue, resolveCliAuth } from '../auth'
|
|
8
|
+
import { registerRun, stepSummaryFromTrace } from '../run-registry'
|
|
9
|
+
import { createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
|
|
10
|
+
import { inspectDescribe } from './inspect/core'
|
|
11
|
+
import { resolveDefaultUploadOrigin } from './upload'
|
|
12
|
+
|
|
13
|
+
const DEFAULT_TEST_MODEL = process.env.SOOTSIM_TEST_MODEL || 'deepseek-v4-flash'
|
|
14
|
+
const DESCRIBE_CONTEXT_LIMIT = 18_000
|
|
15
|
+
const LLM_TIMEOUT_MS = 180_000
|
|
16
|
+
|
|
17
|
+
function flagValue(args: string[], name: string): string | undefined {
|
|
18
|
+
const index = args.indexOf(name)
|
|
19
|
+
return index >= 0 ? args[index + 1] : undefined
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function flagValueAny(args: string[], names: string[]): string | undefined {
|
|
23
|
+
for (const name of names) {
|
|
24
|
+
const value = flagValue(args, name)
|
|
25
|
+
if (value) return value
|
|
26
|
+
}
|
|
27
|
+
return undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const VALUE_FLAGS = new Set([
|
|
31
|
+
'--origin',
|
|
32
|
+
'--preview-origin',
|
|
33
|
+
'--public-origin',
|
|
34
|
+
'--preview-public-origin',
|
|
35
|
+
'--owner',
|
|
36
|
+
'--repo',
|
|
37
|
+
'--url',
|
|
38
|
+
'--driver',
|
|
39
|
+
'--sim',
|
|
40
|
+
'--device',
|
|
41
|
+
'--slow',
|
|
42
|
+
'--tail-wait',
|
|
43
|
+
'--remap',
|
|
44
|
+
'--replace',
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
function findPrompt(args: string[]): { prompt: string; index: number } | null {
|
|
48
|
+
for (let i = 0; i < args.length; i++) {
|
|
49
|
+
const arg = args[i]
|
|
50
|
+
if (!arg) continue
|
|
51
|
+
if (VALUE_FLAGS.has(arg)) {
|
|
52
|
+
i += 1
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
if (arg.startsWith('-')) continue
|
|
56
|
+
return { prompt: arg, index: i }
|
|
57
|
+
}
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function stripPromptForBridge(args: string[], promptIndex: number): string[] {
|
|
62
|
+
return args.filter((_, index) => index !== promptIndex)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function describeCurrentSim(args: string[], promptIndex: number): Promise<string> {
|
|
66
|
+
const bridgeArgs = stripPromptForBridge(args, promptIndex)
|
|
67
|
+
const parsedBridgeArgs = parseBridgeCliArgs(bridgeArgs, {
|
|
68
|
+
stripBooleanFlags: [
|
|
69
|
+
'--new',
|
|
70
|
+
'--headless',
|
|
71
|
+
'--headed',
|
|
72
|
+
'--electron',
|
|
73
|
+
'--preview-open',
|
|
74
|
+
],
|
|
75
|
+
stripValueFlags: [...VALUE_FLAGS],
|
|
76
|
+
})
|
|
77
|
+
const bridge = createBridgeFromParsed(parsedBridgeArgs)
|
|
78
|
+
try {
|
|
79
|
+
const describe = await inspectDescribe(bridge, {
|
|
80
|
+
describe: true,
|
|
81
|
+
verbose: false,
|
|
82
|
+
filter: '',
|
|
83
|
+
compact: true,
|
|
84
|
+
hideXy: true,
|
|
85
|
+
})
|
|
86
|
+
const parts = [
|
|
87
|
+
describe.shell ? `shell: ${JSON.stringify(describe.shell)}` : '',
|
|
88
|
+
describe.keyboard ? `keyboard: ${JSON.stringify(describe.keyboard)}` : '',
|
|
89
|
+
typeof describe.nodeCount === 'number' ? `nodes: ${describe.nodeCount}` : '',
|
|
90
|
+
describe.tree || '',
|
|
91
|
+
].filter(Boolean)
|
|
92
|
+
const text = parts.join('\n')
|
|
93
|
+
return text.length > DESCRIBE_CONTEXT_LIMIT
|
|
94
|
+
? text.slice(0, DESCRIBE_CONTEXT_LIMIT) + '\n[tree truncated]'
|
|
95
|
+
: text
|
|
96
|
+
} finally {
|
|
97
|
+
bridge.close()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const SOOTSIM_TEST_SYSTEM_PROMPT = `
|
|
102
|
+
You write Maestro-compatible rnx YAML flows from a user's plain-language test goal.
|
|
103
|
+
Return only JSON, no markdown, with this exact shape:
|
|
104
|
+
{"summary":"short human-readable result goal","steps":[{"waitFor":{"text":"...","timeout":10000}}]}
|
|
105
|
+
|
|
106
|
+
Use only these flow commands:
|
|
107
|
+
- waitFor: { "text"?: string, "id"?: string, "timeout"?: number }
|
|
108
|
+
- assertVisible: string or { "text"?: string, "id"?: string }
|
|
109
|
+
- assertNotVisible: string or { "text"?: string, "id"?: string }
|
|
110
|
+
- tapOn: string or { "text"?: string, "id"?: string, "index"?: number }
|
|
111
|
+
- inputText: string
|
|
112
|
+
- pressKey: string
|
|
113
|
+
- hideKeyboard: true
|
|
114
|
+
- swipe: { "direction": "UP" | "DOWN" | "LEFT" | "RIGHT", "duration"?: number }
|
|
115
|
+
- waitForAnimationToEnd: true
|
|
116
|
+
- takeScreenshot: "label"
|
|
117
|
+
|
|
118
|
+
Prefer ids/testIDs from the tree. Prefer visible text when no id exists.
|
|
119
|
+
Do not invent app-specific data that is not visible. Keep the flow short.
|
|
120
|
+
End with an assertion or wait that proves the user's goal.
|
|
121
|
+
`.trim()
|
|
122
|
+
|
|
123
|
+
function buildPromptRequest(prompt: string, describe: string): string {
|
|
124
|
+
return `
|
|
125
|
+
User goal:
|
|
126
|
+
${prompt}
|
|
127
|
+
|
|
128
|
+
Current rnx visible tree:
|
|
129
|
+
${describe || '[no tree available]'}
|
|
130
|
+
|
|
131
|
+
Generate the shortest replayable flow that verifies the goal from this current state.
|
|
132
|
+
`.trim()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function generateFlowJson(args: {
|
|
136
|
+
prompt: string
|
|
137
|
+
describe: string
|
|
138
|
+
origin: string
|
|
139
|
+
authHeader: string
|
|
140
|
+
}): Promise<string> {
|
|
141
|
+
const res = await fetch(`${args.origin.replace(/\/$/, '')}/api/llm`, {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: {
|
|
144
|
+
'content-type': 'application/json',
|
|
145
|
+
authorization: args.authHeader,
|
|
146
|
+
},
|
|
147
|
+
body: JSON.stringify({
|
|
148
|
+
modelId: DEFAULT_TEST_MODEL,
|
|
149
|
+
context: {
|
|
150
|
+
systemPrompt: SOOTSIM_TEST_SYSTEM_PROMPT,
|
|
151
|
+
messages: [
|
|
152
|
+
{
|
|
153
|
+
role: 'user',
|
|
154
|
+
content: buildPromptRequest(args.prompt, args.describe),
|
|
155
|
+
timestamp: Date.now(),
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
options: { maxTokens: 1800, temperature: 0.2 },
|
|
160
|
+
threadId: null,
|
|
161
|
+
}),
|
|
162
|
+
signal: AbortSignal.timeout(LLM_TIMEOUT_MS),
|
|
163
|
+
})
|
|
164
|
+
if (!res.ok || !res.body) {
|
|
165
|
+
const text = await res.text().catch(() => '')
|
|
166
|
+
throw new Error(`/api/llm ${res.status}${text ? `: ${text}` : ''}`)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const reader = res.body.getReader()
|
|
170
|
+
const decoder = new TextDecoder()
|
|
171
|
+
const deltas: string[] = []
|
|
172
|
+
let buffer = ''
|
|
173
|
+
// /api/llm speaks pi-agent-core's proxy event protocol. text events carry
|
|
174
|
+
// visible deltas; transport diagnostics and keepalives are ignored here.
|
|
175
|
+
const handleLine = (line: string) => {
|
|
176
|
+
const trimmed = line.trim()
|
|
177
|
+
if (!trimmed) return
|
|
178
|
+
const event = JSON.parse(trimmed) as {
|
|
179
|
+
type?: string
|
|
180
|
+
delta?: string
|
|
181
|
+
errorMessage?: string
|
|
182
|
+
}
|
|
183
|
+
if (event.type === 'text_delta' && event.delta) {
|
|
184
|
+
deltas.push(event.delta)
|
|
185
|
+
} else if (event.type === 'error') {
|
|
186
|
+
throw new Error(event.errorMessage || 'llm error')
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (;;) {
|
|
191
|
+
const { value, done } = await reader.read()
|
|
192
|
+
if (done) break
|
|
193
|
+
buffer += decoder.decode(value, { stream: true })
|
|
194
|
+
let newline: number
|
|
195
|
+
while ((newline = buffer.indexOf('\n')) >= 0) {
|
|
196
|
+
handleLine(buffer.slice(0, newline))
|
|
197
|
+
buffer = buffer.slice(newline + 1)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
buffer += decoder.decode()
|
|
201
|
+
if (buffer.trim()) handleLine(buffer)
|
|
202
|
+
|
|
203
|
+
const text = deltas.join('').trim()
|
|
204
|
+
if (!text) throw new Error('llm returned an empty test flow')
|
|
205
|
+
return text
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function extractJson(text: string): unknown {
|
|
209
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i)
|
|
210
|
+
const candidate = fenced
|
|
211
|
+
? fenced[1]
|
|
212
|
+
: text.slice(text.indexOf('{'), text.lastIndexOf('}') + 1)
|
|
213
|
+
return JSON.parse(candidate)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
217
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function parseGeneratedFlow(text: string): {
|
|
221
|
+
summary: string
|
|
222
|
+
steps: Record<string, unknown>[]
|
|
223
|
+
yamlText: string
|
|
224
|
+
} {
|
|
225
|
+
const parsed = extractJson(text)
|
|
226
|
+
if (!isRecord(parsed)) throw new Error('llm did not return a JSON object')
|
|
227
|
+
const summary =
|
|
228
|
+
typeof parsed.summary === 'string' && parsed.summary.trim()
|
|
229
|
+
? parsed.summary.trim().slice(0, 500)
|
|
230
|
+
: 'rnx generated test'
|
|
231
|
+
const rawSteps = parsed.steps
|
|
232
|
+
if (!Array.isArray(rawSteps) || rawSteps.length === 0) {
|
|
233
|
+
throw new Error('llm returned no flow steps')
|
|
234
|
+
}
|
|
235
|
+
const steps = rawSteps.map((step, index) => {
|
|
236
|
+
if (!isRecord(step)) throw new Error(`flow step ${index + 1} is not an object`)
|
|
237
|
+
return step
|
|
238
|
+
})
|
|
239
|
+
return { summary, steps, yamlText: yaml.stringify(steps) }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function buildFlowArgs(
|
|
243
|
+
args: string[],
|
|
244
|
+
promptIndex: number,
|
|
245
|
+
flowPath: string,
|
|
246
|
+
origin: string,
|
|
247
|
+
) {
|
|
248
|
+
const out = [
|
|
249
|
+
flowPath,
|
|
250
|
+
'--preview',
|
|
251
|
+
'--preview-origin',
|
|
252
|
+
origin,
|
|
253
|
+
'--billing-kind',
|
|
254
|
+
'test_run',
|
|
255
|
+
]
|
|
256
|
+
const passthroughValues = new Set([
|
|
257
|
+
'--public-origin',
|
|
258
|
+
'--preview-public-origin',
|
|
259
|
+
'--owner',
|
|
260
|
+
'--repo',
|
|
261
|
+
'--url',
|
|
262
|
+
'--driver',
|
|
263
|
+
'--sim',
|
|
264
|
+
'--device',
|
|
265
|
+
'--slow',
|
|
266
|
+
'--tail-wait',
|
|
267
|
+
'--remap',
|
|
268
|
+
'--replace',
|
|
269
|
+
])
|
|
270
|
+
const passthroughBooleans = new Set([
|
|
271
|
+
'--new',
|
|
272
|
+
'--headless',
|
|
273
|
+
'--headed',
|
|
274
|
+
'--electron',
|
|
275
|
+
'--preview-open',
|
|
276
|
+
'--no-shell',
|
|
277
|
+
'--shell-only',
|
|
278
|
+
])
|
|
279
|
+
for (let i = 0; i < args.length; i++) {
|
|
280
|
+
if (i === promptIndex) continue
|
|
281
|
+
const arg = args[i]
|
|
282
|
+
if (arg === '--origin' || arg === '--preview-origin') {
|
|
283
|
+
i += 1
|
|
284
|
+
continue
|
|
285
|
+
}
|
|
286
|
+
if (arg === '--public-origin') {
|
|
287
|
+
const value = args[i + 1]
|
|
288
|
+
if (value) out.push('--preview-public-origin', value)
|
|
289
|
+
i += 1
|
|
290
|
+
continue
|
|
291
|
+
}
|
|
292
|
+
if (passthroughValues.has(arg)) {
|
|
293
|
+
const value = args[i + 1]
|
|
294
|
+
if (value) out.push(arg, value)
|
|
295
|
+
i += 1
|
|
296
|
+
continue
|
|
297
|
+
}
|
|
298
|
+
if (passthroughBooleans.has(arg)) out.push(arg)
|
|
299
|
+
}
|
|
300
|
+
return out
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export async function runMaestroGenerate(args: string[]): Promise<number> {
|
|
304
|
+
const promptArg = findPrompt(args)
|
|
305
|
+
if (!promptArg) {
|
|
306
|
+
console.error(' usage: rnxsim maestro generate "test goal"')
|
|
307
|
+
return 1
|
|
308
|
+
}
|
|
309
|
+
const { prompt, index: promptIndex } = promptArg
|
|
310
|
+
const cliAuth = resolveCliAuth()
|
|
311
|
+
if (!cliAuth || cliAuth.kind === 'github') {
|
|
312
|
+
console.error(' rnxsim maestro generate "<goal>" needs a login or RNX_API_KEY.')
|
|
313
|
+
console.error(' API keys must include preview_upload and llm scopes.')
|
|
314
|
+
return 1
|
|
315
|
+
}
|
|
316
|
+
const authHeader = authHeaderValue(cliAuth)
|
|
317
|
+
const origin = await resolveDefaultUploadOrigin(
|
|
318
|
+
flagValueAny(args, ['--origin', '--preview-origin']),
|
|
319
|
+
)
|
|
320
|
+
console.log(' inspecting current sim…')
|
|
321
|
+
const describe = await describeCurrentSim(args, promptIndex)
|
|
322
|
+
console.log(' generating Maestro flow…')
|
|
323
|
+
const generated = await generateFlowJson({ prompt, describe, origin, authHeader })
|
|
324
|
+
const flow = parseGeneratedFlow(generated)
|
|
325
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'sootsim-maestro-generate-'))
|
|
326
|
+
const flowPath = join(tempDir, 'flow.yaml')
|
|
327
|
+
writeFileSync(flowPath, flow.yamlText)
|
|
328
|
+
console.log(` flow: ${flowPath}`)
|
|
329
|
+
|
|
330
|
+
const startedAt = Date.now()
|
|
331
|
+
const { runFlowPlayback, getLastFlowPreviewUploadResult, getLastFlowTraceSteps } =
|
|
332
|
+
await import('./flow')
|
|
333
|
+
const flowArgs = buildFlowArgs(args, promptIndex, flowPath, origin)
|
|
334
|
+
const exitCode = await runFlowPlayback(flowArgs)
|
|
335
|
+
const upload = getLastFlowPreviewUploadResult()
|
|
336
|
+
const traceSteps = getLastFlowTraceSteps()
|
|
337
|
+
const failedStep = traceSteps.find((step) => step.status === 'failure')
|
|
338
|
+
const status = exitCode === 0 ? 'passed' : 'failed'
|
|
339
|
+
const run = await registerRun({
|
|
340
|
+
origin,
|
|
341
|
+
kind: 'maestro',
|
|
342
|
+
prompt,
|
|
343
|
+
summary: flow.summary,
|
|
344
|
+
status,
|
|
345
|
+
failureMessage:
|
|
346
|
+
status === 'failed' ? (failedStep?.error ?? 'flow playback failed') : null,
|
|
347
|
+
previewShareId: upload?.shareId ?? null,
|
|
348
|
+
owner: flagValue(args, '--owner') ?? null,
|
|
349
|
+
repo: flagValue(args, '--repo') ?? null,
|
|
350
|
+
durationMs: Date.now() - startedAt,
|
|
351
|
+
flowYamlSizeBytes: Buffer.byteLength(flow.yamlText, 'utf8'),
|
|
352
|
+
...stepSummaryFromTrace(traceSteps),
|
|
353
|
+
auth: cliAuth,
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
console.log(`\n result: ${status}`)
|
|
357
|
+
if (run) console.log(` run: ${run.id}`)
|
|
358
|
+
if (upload?.previewUrl) console.log(` preview: ${upload.previewUrl}`)
|
|
359
|
+
if (run?.traceUrl) console.log(` replay: ${run.traceUrl}`)
|
|
360
|
+
return exitCode
|
|
361
|
+
}
|