rnxsim 0.1.376 → 0.1.378
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 +28 -25
- package/cli/app-config.ts +9 -12
- package/cli/app-fonts.ts +3 -3
- package/cli/app-project.ts +8 -8
- package/cli/auth.ts +7 -9
- package/cli/bin.ts +16 -31
- package/cli/bridge-flow-runner.ts +3 -3
- package/cli/browser-backend.ts +44 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +291 -0
- package/cli/commands/agent-wrapper.ts +2 -2
- package/cli/commands/app-fonts.ts +2 -2
- package/cli/commands/assert.ts +3 -3
- package/cli/commands/auth.ts +1 -1
- package/cli/commands/box/cloud-box.ts +1 -1
- package/cli/commands/box/plane-share.ts +2 -2
- package/cli/commands/box.ts +4 -6
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +29 -29
- package/cli/commands/cpu-profile.ts +7 -7
- package/cli/commands/daemon-mac-app.ts +7 -7
- package/cli/commands/daemon.ts +10 -10
- package/cli/commands/debug.ts +11 -11
- package/cli/commands/detox.ts +13 -13
- package/cli/commands/diagnose.ts +6 -6
- package/cli/commands/do-chain.ts +1 -2
- package/cli/commands/electron.ts +1 -3
- package/cli/commands/film.ts +3 -3
- package/cli/commands/flow.ts +43 -43
- package/cli/commands/inspect/count.ts +1 -1
- package/cli/commands/inspect/describe.ts +1 -1
- package/cli/commands/inspect/env.ts +2 -2
- package/cli/commands/inspect/get-layout.ts +1 -1
- package/cli/commands/inspect/keyboard.ts +1 -1
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/memory.ts +1 -1
- package/cli/commands/inspect/resolve-target.ts +1 -1
- package/cli/commands/inspect/screens.ts +1 -1
- package/cli/commands/inspect/tree.ts +1 -1
- package/cli/commands/inspect/url.ts +1 -1
- package/cli/commands/inspect/wait-event.ts +5 -5
- package/cli/commands/inspect.ts +34 -34
- package/cli/commands/install-desktop.ts +3 -3
- package/cli/commands/login.ts +6 -6
- package/cli/commands/maestro-generate.ts +5 -5
- package/cli/commands/maestro.ts +5 -5
- package/cli/commands/profile.ts +1 -1
- package/cli/commands/record.ts +9 -9
- package/cli/commands/runtime.ts +18 -18
- package/cli/commands/screenshot-command.ts +1 -1
- package/cli/commands/screenshot-layers.ts +5 -5
- package/cli/commands/screenshot-mode.ts +1 -1
- package/cli/commands/screenshot.ts +8 -8
- package/cli/commands/screenshots-capture.ts +5 -5
- package/cli/commands/serve.ts +3 -3
- package/cli/commands/setup.ts +20 -12
- package/cli/commands/skills.ts +5 -5
- package/cli/commands/slides.ts +1 -1
- package/cli/commands/telemetry.ts +1 -1
- package/cli/commands/three-mode.ts +1 -1
- package/cli/commands/timeline.ts +8 -8
- package/cli/commands/upgrade.ts +116 -131
- package/cli/commands/upload.ts +12 -12
- package/cli/commands/version.ts +7 -7
- package/cli/commands/what-happened.ts +9 -9
- package/cli/current-sim.ts +3 -3
- package/cli/desktop-companion.ts +1 -1
- package/cli/drivers/playwright.ts +9 -9
- package/cli/drivers/registry.ts +1 -1
- package/cli/drivers/types.ts +1 -1
- package/cli/flow-file.ts +2 -2
- package/cli/flow-session.ts +1 -1
- package/cli/help-core.ts +136 -0
- package/cli/help.ts +17 -53
- package/cli/hints.ts +5 -5
- package/cli/inspect-notice-state.ts +1 -1
- package/cli/maestro-js.ts +1 -1
- package/cli/outbound-endpoints.ts +23 -5
- package/cli/parse-args.ts +19 -66
- package/cli/recording-access.ts +1 -1
- package/cli/registry.ts +1 -0
- package/cli/run-registry.ts +1 -1
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +6 -9
- package/cli/runtime-notes.ts +3 -3
- package/cli/standalone.ts +4 -0
- package/cli/ws-bridge.ts +8 -8
- package/detox/config-loader.ts +2 -2
- package/detox/index.ts +8 -8
- package/detox/jest-preset.cjs +1 -1
- package/detox/navigation.ts +2 -2
- package/dist-lib/agent-daemon-client.cjs +5 -5
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +2 -2
- package/dist-lib/agent-sessions.cjs +10 -10
- package/dist-lib/attached-projects.cjs +6 -6
- package/dist-lib/auth/shared-session.cjs +6 -6
- 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 +25 -25
- package/dist-lib/detox/index.cjs +73 -31
- package/dist-lib/detox/jest-preset.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +29 -29
- package/dist-lib/host/bridge-host.cjs +128 -49
- 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 +14 -14
- 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 +8 -8
- package/dist-lib/profiles.cjs +12 -12
- 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 +8 -8
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +329 -160
- package/dist-lib/vite.cjs +9 -9
- package/package.json +4 -11
- package/scripts/dev-server-scanner.ts +2 -2
- package/scripts/optional-demo-registry.ts +1 -1
- package/skills/contrast/SKILL.md +3 -3
- package/skills/rnx-debug/SKILL.md +1 -1
- package/skills/rnx-test/SKILL.md +2 -2
- package/src/agent-identity.ts +1 -1
- package/src/agent-sessions.ts +7 -5
- package/src/cli-version.ts +12 -4
- package/src/config.ts +26 -28
- package/src/disk-cleanup.ts +11 -11
- package/src/home-paths.ts +28 -28
- package/src/host/bridge-host.ts +16 -16
- package/src/metro-plugin.ts +2 -2
- package/src/profiles.ts +2 -2
- package/src/runtime-assets.ts +7 -7
- package/src/runtime-delivery.ts +13 -13
- package/src/screenshots/orchestrate.ts +1 -1
- package/src/screenshots/schema.ts +2 -2
- package/src/skills/builtin/a11y-review.ts +2 -2
- package/src/skills/builtin/compat-check.ts +2 -2
- package/src/skills/builtin/maestro-test.ts +2 -2
- package/src/skills/builtin/perf-profile.ts +2 -2
- package/src/skills/builtin/screenshot-all.ts +2 -2
- package/src/skills/builtin/visual-diff.ts +2 -2
- package/src/skills/registry.ts +8 -8
- package/src/skills/types.ts +1 -1
- package/src/vite-plugin-one.ts +3 -3
- package/src/vite-plugin.ts +15 -2
- package/dist-cli/bin.js +0 -15
- package/dist-cli/chunks/agent-H42FCKFF.js +0 -48
- package/dist-cli/chunks/agent-wrapper-BBZKTZS6.js +0 -17
- package/dist-cli/chunks/app-fonts-43VXIKF4.js +0 -4
- package/dist-cli/chunks/assert-IXOLVO5Z.js +0 -49
- package/dist-cli/chunks/auth-KFMFB6FU.js +0 -12
- package/dist-cli/chunks/beta-5AO3SJB7.js +0 -4
- package/dist-cli/chunks/box-ZHM66L6K.js +0 -1730
- package/dist-cli/chunks/camera-FNJVFCDQ.js +0 -33
- package/dist-cli/chunks/chunk-37MCSPTE.js +0 -71
- package/dist-cli/chunks/chunk-3PEMSUAQ.js +0 -30
- package/dist-cli/chunks/chunk-4TQ5HOK3.js +0 -7
- package/dist-cli/chunks/chunk-5YZYDEMI.js +0 -4
- package/dist-cli/chunks/chunk-6CV3R3XD.js +0 -15
- package/dist-cli/chunks/chunk-7LGK5XU6.js +0 -4
- package/dist-cli/chunks/chunk-7R2TK2NY.js +0 -4
- package/dist-cli/chunks/chunk-7VZZQQEE.js +0 -497
- package/dist-cli/chunks/chunk-AFOVILIL.js +0 -130
- package/dist-cli/chunks/chunk-BEU7CD7E.js +0 -9
- package/dist-cli/chunks/chunk-CE4JQJ6Y.js +0 -6
- package/dist-cli/chunks/chunk-CIE6CZXL.js +0 -142
- package/dist-cli/chunks/chunk-CSJ7L7ZL.js +0 -312
- package/dist-cli/chunks/chunk-CWCQP53A.js +0 -27
- package/dist-cli/chunks/chunk-DCS5FK5N.js +0 -7
- package/dist-cli/chunks/chunk-DEV3E3MV.js +0 -4
- package/dist-cli/chunks/chunk-DGJMIVZM.js +0 -5
- package/dist-cli/chunks/chunk-DGX3MN65.js +0 -5
- package/dist-cli/chunks/chunk-DNPQMTW5.js +0 -4
- package/dist-cli/chunks/chunk-DOVBJBVD.js +0 -5
- package/dist-cli/chunks/chunk-DPBJ3S3J.js +0 -3
- package/dist-cli/chunks/chunk-FVZBGPCU.js +0 -4
- package/dist-cli/chunks/chunk-GDKMOIUT.js +0 -4
- package/dist-cli/chunks/chunk-GIF2NJCS.js +0 -32
- package/dist-cli/chunks/chunk-GZE57ORL.js +0 -4
- package/dist-cli/chunks/chunk-H3U56DKI.js +0 -24
- package/dist-cli/chunks/chunk-HZLOYAPH.js +0 -4
- package/dist-cli/chunks/chunk-J2IKAEU2.js +0 -4
- package/dist-cli/chunks/chunk-JXAXYK7W.js +0 -11
- package/dist-cli/chunks/chunk-KJE2O2GK.js +0 -4
- package/dist-cli/chunks/chunk-KMNVDZZI.js +0 -423
- package/dist-cli/chunks/chunk-LC3QRIRB.js +0 -10
- package/dist-cli/chunks/chunk-LGFTAQYC.js +0 -4
- package/dist-cli/chunks/chunk-LQMUA5IY.js +0 -4
- package/dist-cli/chunks/chunk-MFIQTWC5.js +0 -4
- package/dist-cli/chunks/chunk-MGALNF2F.js +0 -7
- package/dist-cli/chunks/chunk-MLBZZHOY.js +0 -4
- package/dist-cli/chunks/chunk-NNRF7GIB.js +0 -107
- package/dist-cli/chunks/chunk-NORLYTTO.js +0 -7
- package/dist-cli/chunks/chunk-P6KVGV3H.js +0 -14
- package/dist-cli/chunks/chunk-PAJTUK33.js +0 -4
- package/dist-cli/chunks/chunk-QELIC5XP.js +0 -4
- package/dist-cli/chunks/chunk-QRDF33WD.js +0 -11
- package/dist-cli/chunks/chunk-R76BA7C7.js +0 -535
- package/dist-cli/chunks/chunk-RVEB4CZ2.js +0 -4
- package/dist-cli/chunks/chunk-SK4M7NXT.js +0 -5
- package/dist-cli/chunks/chunk-SKMG5DD7.js +0 -5
- package/dist-cli/chunks/chunk-TEESPOYR.js +0 -4
- package/dist-cli/chunks/chunk-TH2UFGVP.js +0 -4
- package/dist-cli/chunks/chunk-TLP3T3VO.js +0 -4
- package/dist-cli/chunks/chunk-TZUABDIJ.js +0 -38
- package/dist-cli/chunks/chunk-UB2W6OQM.js +0 -99
- package/dist-cli/chunks/chunk-UYVXALPB.js +0 -506
- package/dist-cli/chunks/chunk-VQDYFFIG.js +0 -5
- package/dist-cli/chunks/chunk-VWCNJPCJ.js +0 -5
- package/dist-cli/chunks/chunk-VZIK4WIS.js +0 -74
- package/dist-cli/chunks/chunk-W3FNXAQP.js +0 -4
- package/dist-cli/chunks/chunk-XCDNVNP3.js +0 -4
- package/dist-cli/chunks/chunk-XSVILA4Z.js +0 -4
- package/dist-cli/chunks/chunk-XUTJ7ZWD.js +0 -4
- package/dist-cli/chunks/chunk-YTXY3MHW.js +0 -4
- package/dist-cli/chunks/chunk-ZF7PVX44.js +0 -28
- package/dist-cli/chunks/chunk-ZSSG7OR7.js +0 -4
- package/dist-cli/chunks/cleanup-MLOK2OZA.js +0 -25
- package/dist-cli/chunks/cli-version-OBNR366V.js +0 -4
- package/dist-cli/chunks/compat-SHMFSKU7.js +0 -23
- package/dist-cli/chunks/config-TPEAEUJ2.js +0 -13
- package/dist-cli/chunks/connect-3LEXWTE5.js +0 -4
- package/dist-cli/chunks/control-Z3FWA6BO.js +0 -4
- package/dist-cli/chunks/daemon-RSVYSC65.js +0 -4
- package/dist-cli/chunks/debug-GUVAK2KR.js +0 -200
- package/dist-cli/chunks/desktop-OOP2PTKP.js +0 -31
- package/dist-cli/chunks/detox-C2ILVBEC.js +0 -52
- package/dist-cli/chunks/device-NXIQQJWR.js +0 -18
- package/dist-cli/chunks/diagnose-2JBGYE5L.js +0 -43
- package/dist-cli/chunks/disk-cleanup-VURWJYQV.js +0 -4
- package/dist-cli/chunks/do-chain-DJ4UQC7A.js +0 -5
- package/dist-cli/chunks/drivers-JMA2OIKU.js +0 -4
- package/dist-cli/chunks/env-KTNPKEZR.js +0 -4
- package/dist-cli/chunks/film-DCPS7EID.js +0 -74
- package/dist-cli/chunks/flow-4DZ7B2OA.js +0 -4
- package/dist-cli/chunks/help-34CJMQY2.js +0 -4
- package/dist-cli/chunks/hidden-runtime-alias-HHT2C7WE.js +0 -4
- package/dist-cli/chunks/home-paths-KTPGCPMS.js +0 -4
- package/dist-cli/chunks/inspect-JF5WYJRD.js +0 -4
- package/dist-cli/chunks/install-desktop-ZIC4CDXI.js +0 -4
- package/dist-cli/chunks/login-TTJAOI2Q.js +0 -26
- package/dist-cli/chunks/logout-ERAQ6SKW.js +0 -4
- package/dist-cli/chunks/maestro-W46QCF77.js +0 -108
- package/dist-cli/chunks/maestro-generate-VBLM3MTU.js +0 -36
- package/dist-cli/chunks/mode-ZEDZK7R7.js +0 -26
- package/dist-cli/chunks/optional-demo-registry-ZUTPSVYQ.js +0 -4
- package/dist-cli/chunks/perf-YVT2WXT4.js +0 -48
- package/dist-cli/chunks/permissions-L7VVDHFP.js +0 -13
- package/dist-cli/chunks/platform-7TJOU2FB.js +0 -6
- package/dist-cli/chunks/privacy-57UOTB5J.js +0 -4
- package/dist-cli/chunks/record-VXG37P7U.js +0 -72
- package/dist-cli/chunks/report-issue-WNNOBZHC.js +0 -29
- package/dist-cli/chunks/reset-H5NBFE5U.js +0 -4
- package/dist-cli/chunks/resolve-target-57TK5WLE.js +0 -4
- package/dist-cli/chunks/runtime-QU2NIF2K.js +0 -4
- package/dist-cli/chunks/screenshot-command-AN56TTG7.js +0 -159
- package/dist-cli/chunks/screenshot-layers-3W5R7DB2.js +0 -20
- package/dist-cli/chunks/screenshots-capture-6AWJY7XZ.js +0 -42
- package/dist-cli/chunks/serve-GLYO5Q7J.js +0 -56
- package/dist-cli/chunks/setup-UA2HLD7S.js +0 -4
- package/dist-cli/chunks/sim-client-5C2RDQQO.js +0 -4
- package/dist-cli/chunks/skills-EYXWBRNQ.js +0 -50
- package/dist-cli/chunks/state-REJ7W6K3.js +0 -14
- package/dist-cli/chunks/storage-CFMDHI3V.js +0 -37
- package/dist-cli/chunks/store-XMCUA45G.js +0 -4
- package/dist-cli/chunks/telemetry-FBL3NAKB.js +0 -4
- package/dist-cli/chunks/timeline-HMCHN5FO.js +0 -24
- package/dist-cli/chunks/upgrade-2QSPAA3P.js +0 -7
- package/dist-cli/chunks/upload-DUQBKZYV.js +0 -4
- package/dist-cli/chunks/version-IOA6QFGB.js +0 -6
- package/dist-cli/chunks/web-NCGUYVCJ.js +0 -4
- package/dist-cli/chunks/welcome-QYGSQCWQ.js +0 -5
- package/dist-cli/chunks/what-happened-YTOUK4LO.js +0 -25
- package/dist-cli/chunks/ws-bridge-OF4OZARG.js +0 -4
- package/scripts/postinstall.cjs +0 -3
- package/scripts/preuninstall.cjs +0 -118
package/cli/help-core.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { cliCommandMetas } from '@sootsim/skills/cli'
|
|
2
|
+
import {
|
|
3
|
+
renderCliCommandHelp,
|
|
4
|
+
renderCliGroupHelp,
|
|
5
|
+
renderCliIndexHelp,
|
|
6
|
+
} from '@sootsim/skills/cli/renderers'
|
|
7
|
+
import { formatFlagHelp } from 'sootsim-engine/settings/cli-flags'
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
10
|
+
DEFAULT_SOOTSIM_BRIDGE_URL,
|
|
11
|
+
} from '../src/bridge-constants'
|
|
12
|
+
import {
|
|
13
|
+
getRnxCommandAvailability,
|
|
14
|
+
getRnxFirstPositional,
|
|
15
|
+
getRnxCommandRegistration,
|
|
16
|
+
RNX_COMMAND_REGISTRY,
|
|
17
|
+
} from './command-registry'
|
|
18
|
+
import type { RnxBackendKind } from './command-contract'
|
|
19
|
+
|
|
20
|
+
export interface RnxHelpOptions {
|
|
21
|
+
backend: RnxBackendKind
|
|
22
|
+
command?: string | null
|
|
23
|
+
commandArgs?: string[]
|
|
24
|
+
prefer?: 'command' | 'verb'
|
|
25
|
+
group?: string | null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const HELP_CONTEXT = {
|
|
29
|
+
bridgePort: DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
30
|
+
defaultShellUrl: DEFAULT_SOOTSIM_BRIDGE_URL,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function backendLabel(command: string, args: readonly string[]): string {
|
|
34
|
+
const available = (['node', 'browser'] satisfies RnxBackendKind[]).filter(
|
|
35
|
+
(backend) => getRnxCommandAvailability(command, args, backend).available,
|
|
36
|
+
)
|
|
37
|
+
return `available backends: ${available.join(', ')}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderWebHelp(): string {
|
|
41
|
+
return `rnx web — select or ensure the current branch's existing web preview
|
|
42
|
+
|
|
43
|
+
usage:
|
|
44
|
+
rnx web
|
|
45
|
+
|
|
46
|
+
The browser backend selects the Factory-owned web iframe. It never launches a
|
|
47
|
+
browser, host process, or Cloudflare runtime.`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function renderFactoryBrowserLeaves(command: string): string | null {
|
|
51
|
+
switch (command) {
|
|
52
|
+
case 'do':
|
|
53
|
+
return `Factory browser leaves:
|
|
54
|
+
rnx do navigate /route`
|
|
55
|
+
case 'shell':
|
|
56
|
+
return `Factory browser leaves:
|
|
57
|
+
rnx shell appearance light|dark`
|
|
58
|
+
case 'assert':
|
|
59
|
+
return `Factory browser leaves:
|
|
60
|
+
rnx assert find (--testid <id>|--text <text>|--role <role>) [--exists|--empty] [--contains <text>]`
|
|
61
|
+
case 'screenshot':
|
|
62
|
+
return `Factory browser leaves:
|
|
63
|
+
rnx screenshot
|
|
64
|
+
rnx screenshot ask <question>
|
|
65
|
+
rnx screenshot appearance light|dark /route --by <query-kind> --value <target>
|
|
66
|
+
rnx screenshot motion <task-id> /route --trigger-by <kind> --trigger-value <target> --result-by <kind> --result-value <target> [--duration-ms <100..2000>]`
|
|
67
|
+
default:
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function renderRootAvailability(backend: RnxBackendKind): string {
|
|
73
|
+
const visibleCommands = new Set([...cliCommandMetas.map((meta) => meta.id), 'web'])
|
|
74
|
+
const visibleRegistry = RNX_COMMAND_REGISTRY.filter((entry) =>
|
|
75
|
+
visibleCommands.has(entry.name),
|
|
76
|
+
)
|
|
77
|
+
const available = visibleRegistry
|
|
78
|
+
.filter((entry) => getRnxCommandAvailability(entry.name, [], backend).available)
|
|
79
|
+
.map((entry) => entry.name)
|
|
80
|
+
const unavailable = visibleRegistry
|
|
81
|
+
.filter((entry) => !getRnxCommandAvailability(entry.name, [], backend).available)
|
|
82
|
+
.map((entry) => entry.name)
|
|
83
|
+
|
|
84
|
+
return `backend availability (${backend}):
|
|
85
|
+
available: ${available.join(', ')}
|
|
86
|
+
unavailable: ${unavailable.join(', ')}
|
|
87
|
+
|
|
88
|
+
Run \`rnx <command> --help\` for leaf availability and usage.`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function renderRnxHelp(options: RnxHelpOptions): string {
|
|
92
|
+
const command = options.command ?? null
|
|
93
|
+
const commandArgs = options.commandArgs ?? []
|
|
94
|
+
if (!command) {
|
|
95
|
+
return `${renderCliIndexHelp(HELP_CONTEXT, formatFlagHelp()).trimEnd()}
|
|
96
|
+
|
|
97
|
+
browser preview selector:
|
|
98
|
+
rnx web select the existing Factory web preview
|
|
99
|
+
|
|
100
|
+
${renderRootAvailability(options.backend)}`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let body: string | null
|
|
104
|
+
if (command === 'web') {
|
|
105
|
+
body = renderWebHelp()
|
|
106
|
+
} else if (options.group === command && !options.prefer) {
|
|
107
|
+
body = renderCliGroupHelp(command, HELP_CONTEXT, formatFlagHelp())
|
|
108
|
+
} else {
|
|
109
|
+
const subVerb = getRnxFirstPositional(commandArgs)
|
|
110
|
+
const grouping = new Set(['do', 'get', 'debug', 'wait'])
|
|
111
|
+
const helpName = options.prefer === 'verb' && subVerb ? subVerb : command
|
|
112
|
+
body = renderCliCommandHelp(helpName, HELP_CONTEXT, {
|
|
113
|
+
prefer: options.prefer,
|
|
114
|
+
group: options.group,
|
|
115
|
+
})
|
|
116
|
+
if (!body && grouping.has(command)) {
|
|
117
|
+
body = renderCliGroupHelp(command, HELP_CONTEXT, formatFlagHelp())
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!body) return `unknown command: ${command}`
|
|
122
|
+
|
|
123
|
+
const registration = getRnxCommandRegistration(command)
|
|
124
|
+
if (!registration) return body
|
|
125
|
+
const current = getRnxCommandAvailability(command, commandArgs, options.backend)
|
|
126
|
+
const currentLine = current.available
|
|
127
|
+
? `${options.backend} backend: available`
|
|
128
|
+
: `${options.backend} backend: ${current.reason}`
|
|
129
|
+
const factoryLeaves =
|
|
130
|
+
options.backend === 'browser' ? renderFactoryBrowserLeaves(command) : null
|
|
131
|
+
return `${body.trimEnd()}
|
|
132
|
+
|
|
133
|
+
${factoryLeaves ? `${factoryLeaves}\n\n` : ''}${backendLabel(command, commandArgs)}
|
|
134
|
+
|
|
135
|
+
${currentLine}`
|
|
136
|
+
}
|
package/cli/help.ts
CHANGED
|
@@ -1,61 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
renderCliCommandHelp,
|
|
3
|
-
renderCliGroupHelp,
|
|
4
|
-
renderCliIndexHelp,
|
|
5
|
-
} from '@sootsim/skills/cli/renderers'
|
|
6
|
-
import { formatFlagHelp } from 'sootsim-engine/settings/cli-flags'
|
|
7
1
|
import { BETA_TAGLINE, IS_BETA } from '../src/beta'
|
|
8
|
-
import {
|
|
9
|
-
DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
10
|
-
DEFAULT_SOOTSIM_BRIDGE_URL,
|
|
11
|
-
} from '../src/bridge-constants'
|
|
12
2
|
import { getCliVersion } from '../src/cli-version'
|
|
13
3
|
import { rnxPublicBrand } from '../src/public-brand'
|
|
4
|
+
import { renderRnxHelp } from './help-core'
|
|
14
5
|
import { maybeHint } from './hints'
|
|
15
6
|
import { getRuntimeSummary } from './runtime-summary'
|
|
16
7
|
|
|
17
|
-
// header line shown at the top of `--help` so users can always tell what
|
|
18
|
-
// they're running — the CLI npm version and the active engine runtime
|
|
19
|
-
// version are independent, which is exactly the confusion `sootsim
|
|
20
|
-
// upgrade` exists to clear up.
|
|
21
8
|
function versionSummaryLine(): string {
|
|
22
9
|
return `${rnxPublicBrand.commandName} CLI v${getCliVersion()} · ${getRuntimeSummary().primary}`
|
|
23
10
|
}
|
|
24
11
|
|
|
25
|
-
export function printHelp() {
|
|
26
|
-
const base = renderCliIndexHelp(
|
|
27
|
-
{
|
|
28
|
-
bridgePort: DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
29
|
-
defaultShellUrl: DEFAULT_SOOTSIM_BRIDGE_URL,
|
|
30
|
-
},
|
|
31
|
-
formatFlagHelp(),
|
|
32
|
-
)
|
|
12
|
+
export function printHelp(): void {
|
|
33
13
|
const betaLine = IS_BETA ? `\n${BETA_TAGLINE}\n` : ''
|
|
34
14
|
console.log(
|
|
35
|
-
`${versionSummaryLine()}\n${betaLine}${
|
|
36
|
-
`,
|
|
15
|
+
`${versionSummaryLine()}\n${betaLine}${renderRnxHelp({ backend: 'node' })}\n`,
|
|
37
16
|
)
|
|
38
|
-
// once-ever nudge so users learn the clean teardown path before they need it.
|
|
39
|
-
// the npm preuninstall hook runs the same teardown automatically when it
|
|
40
|
-
// fires; this is the documented manual fallback.
|
|
41
17
|
maybeHint('clean-uninstall')
|
|
42
18
|
}
|
|
43
19
|
|
|
44
|
-
// bare `sootsim` prints the registry-backed surface. setup/open own work.
|
|
45
|
-
|
|
46
|
-
// print the help page for a grouping verb (do / get / debug / wait) built
|
|
47
|
-
// entirely from the registry — no hardcoded strings. returns true if the
|
|
48
|
-
// group was known, false if the caller should fall through.
|
|
49
20
|
export function printGroupHelp(group: string): boolean {
|
|
50
|
-
const output =
|
|
21
|
+
const output = renderRnxHelp({
|
|
22
|
+
backend: 'node',
|
|
23
|
+
command: group,
|
|
51
24
|
group,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
defaultShellUrl: DEFAULT_SOOTSIM_BRIDGE_URL,
|
|
55
|
-
},
|
|
56
|
-
formatFlagHelp(),
|
|
57
|
-
)
|
|
58
|
-
if (!output) return false
|
|
25
|
+
})
|
|
26
|
+
if (output.startsWith('unknown command:')) return false
|
|
59
27
|
console.log(`${output}\n`)
|
|
60
28
|
return true
|
|
61
29
|
}
|
|
@@ -63,18 +31,14 @@ export function printGroupHelp(group: string): boolean {
|
|
|
63
31
|
export function printCommandHelp(
|
|
64
32
|
name: string,
|
|
65
33
|
options: { prefer?: 'command' | 'verb'; group?: string | null } = {},
|
|
66
|
-
) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
options,
|
|
74
|
-
)
|
|
75
|
-
if (!output) {
|
|
76
|
-
console.log(`unknown command: ${name}`)
|
|
77
|
-
return
|
|
78
|
-
}
|
|
34
|
+
): void {
|
|
35
|
+
const command = options.group ?? name
|
|
36
|
+
const output = renderRnxHelp({
|
|
37
|
+
backend: 'node',
|
|
38
|
+
command,
|
|
39
|
+
commandArgs: options.group ? [name] : [],
|
|
40
|
+
prefer: options.prefer,
|
|
41
|
+
group: options.group,
|
|
42
|
+
})
|
|
79
43
|
console.log(`${output}\n`)
|
|
80
44
|
}
|
package/cli/hints.ts
CHANGED
|
@@ -46,11 +46,11 @@ interface HintStateFile {
|
|
|
46
46
|
const STATE_VERSION = 1 as const
|
|
47
47
|
|
|
48
48
|
function identityStatePath(): string {
|
|
49
|
-
return join(tmpdir(), `
|
|
49
|
+
return join(tmpdir(), `rnx-cli-hints-${getCliIdentityKey()}.json`)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function globalStatePath(): string {
|
|
53
|
-
return join(tmpdir(), `
|
|
53
|
+
return join(tmpdir(), `rnx-cli-hints-global.json`)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
function readState(path: string): HintStateFile {
|
|
@@ -76,7 +76,7 @@ function writeState(path: string, state: HintStateFile) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function modeFromEnv(): 'normal' | 'always' | 'off' {
|
|
79
|
-
const v = (process.env.
|
|
79
|
+
const v = (process.env.RNX_HINTS || '').toLowerCase()
|
|
80
80
|
if (v === 'off' || v === '0' || v === 'false') return 'off'
|
|
81
81
|
if (v === 'always' || v === 'verbose') return 'always'
|
|
82
82
|
return 'normal'
|
|
@@ -119,7 +119,7 @@ function shouldShow(id: string, frequency: HintFrequency): boolean {
|
|
|
119
119
|
export function maybeHint(id: string, ...args: unknown[]): boolean {
|
|
120
120
|
const spec = registry.get(id)
|
|
121
121
|
if (!spec) {
|
|
122
|
-
if (process.env.
|
|
122
|
+
if (process.env.RNX_HINTS_DEBUG) {
|
|
123
123
|
console.error(` [hints] no hint registered for id "${id}"`)
|
|
124
124
|
}
|
|
125
125
|
return false
|
|
@@ -210,7 +210,7 @@ defineHint<[]>('clean-uninstall', {
|
|
|
210
210
|
// hint documents the explicit daemon cleanup command.
|
|
211
211
|
frequency: 'once-ever',
|
|
212
212
|
render: () => [
|
|
213
|
-
`to remove the background daemon and all ~/.
|
|
213
|
+
`to remove the background daemon and all ~/.rnx data, run \`rnx daemon uninstall\`.`,
|
|
214
214
|
`the optional desktop app and its macOS preference plist are separate from the daemon.`,
|
|
215
215
|
],
|
|
216
216
|
})
|
|
@@ -23,7 +23,7 @@ interface InspectNoticeState {
|
|
|
23
23
|
export function getInspectNoticeStatePath() {
|
|
24
24
|
return resolve(
|
|
25
25
|
process.env[INSPECT_NOTICE_PATH_ENV] ||
|
|
26
|
-
join(tmpdir(), '
|
|
26
|
+
join(tmpdir(), 'rnx-inspect-notice-state.json'),
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
|
package/cli/maestro-js.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// divergences (deliberate, sootsim-side ergonomics — keep this list short):
|
|
18
18
|
// 1. envBinding is seeded from the full process.env, not just MAESTRO_*.
|
|
19
19
|
// sootsim flows historically resolve `${SOOTSIM_*}` credentials from the
|
|
20
|
-
// shell environment and `
|
|
20
|
+
// shell environment and `rnx maestro --env K=V` writes process.env.
|
|
21
21
|
// 2. a *bare identifier* template (`${NAME}`) that evaluates to undefined
|
|
22
22
|
// throws a loud "missing variable" error instead of interpolating the
|
|
23
23
|
// literal text "undefined" into a tap target or login form. complex
|
|
@@ -9,6 +9,7 @@ export type OutboundCategory =
|
|
|
9
9
|
| 'local-development'
|
|
10
10
|
| 'same-origin-runtime'
|
|
11
11
|
| 'guest-app-network'
|
|
12
|
+
| 'release-delivery'
|
|
12
13
|
|
|
13
14
|
export interface OutboundEndpointDeclaration {
|
|
14
15
|
category: OutboundCategory
|
|
@@ -38,11 +39,18 @@ export const OUTBOUND_ENDPOINTS: Record<string, OutboundEndpointDeclaration> = {
|
|
|
38
39
|
payload:
|
|
39
40
|
'explicit auth, billing, preview, issue report, test, or generated-flow request; a stored login may refresh auth/subscription state',
|
|
40
41
|
},
|
|
41
|
-
|
|
42
|
+
cli_delivery: {
|
|
42
43
|
category: 'explicit-user-action',
|
|
43
|
-
destination:
|
|
44
|
+
destination:
|
|
45
|
+
'https://r2.rnxsim.com/rnx-cli/channels/stable and the selected executable/checksum',
|
|
46
|
+
preConsent: false,
|
|
47
|
+
payload: 'requested CLI version, platform, and architecture only',
|
|
48
|
+
},
|
|
49
|
+
cli_release_publish: {
|
|
50
|
+
category: 'release-delivery',
|
|
51
|
+
destination: 'configured R2 origin and https://r2.rnxsim.com/rnx-cli',
|
|
44
52
|
preConsent: false,
|
|
45
|
-
payload: '
|
|
53
|
+
payload: 'release executables, checksums, version, and source identity',
|
|
46
54
|
},
|
|
47
55
|
release_notes: {
|
|
48
56
|
category: 'explicit-user-action',
|
|
@@ -332,10 +340,20 @@ export const DECLARED_OUTBOUND_CALLS: Record<string, OutboundCallDeclaration> =
|
|
|
332
340
|
{ category: 'contrast_user_action', count: 1 },
|
|
333
341
|
'packages/sootsim/cli/commands/screenshots-capture.ts :: fetch :: `${apiOrigin}/api/sootsim/screenshot-decks?org=${encodeURIComponent(org)}&repo=${encodeURIComponent(repo)}`':
|
|
334
342
|
{ category: 'contrast_user_action', count: 1 },
|
|
335
|
-
'packages/sootsim/cli/commands/upgrade.ts :: fetch ::
|
|
336
|
-
category: '
|
|
343
|
+
'packages/sootsim/cli/commands/upgrade.ts :: fetch :: url': {
|
|
344
|
+
category: 'cli_delivery',
|
|
337
345
|
count: 1,
|
|
338
346
|
},
|
|
347
|
+
'packages/sootsim/scripts/publish-cli-binaries.ts :: fetch :: `${url}?sha256=${digest}`':
|
|
348
|
+
{
|
|
349
|
+
category: 'cli_release_publish',
|
|
350
|
+
count: 1,
|
|
351
|
+
},
|
|
352
|
+
'packages/sootsim/scripts/publish-cli-binaries.ts :: fetch :: `${publicOrigin}/${channelKey}?sourceSha=${sourceSha}`':
|
|
353
|
+
{
|
|
354
|
+
category: 'cli_release_publish',
|
|
355
|
+
count: 1,
|
|
356
|
+
},
|
|
339
357
|
'packages/sootsim/cli/commands/upload.ts :: fetch :: url': {
|
|
340
358
|
category: 'presigned_upload',
|
|
341
359
|
count: 1,
|
package/cli/parse-args.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// shared CLI argument parser — handles global flags, commands, and per-command flags
|
|
2
2
|
|
|
3
|
+
import { RNX_COMMAND_NAMES, RNX_NODE_COMMAND_NAMES } from './command-registry'
|
|
4
|
+
|
|
3
5
|
export interface ParsedArgs {
|
|
4
6
|
command: string | null
|
|
5
7
|
commandArgs: string[]
|
|
@@ -7,6 +9,7 @@ export interface ParsedArgs {
|
|
|
7
9
|
help: boolean
|
|
8
10
|
version: boolean
|
|
9
11
|
verbose: boolean
|
|
12
|
+
warnings: string[]
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
const GLOBAL_FLAGS: Record<
|
|
@@ -30,9 +33,9 @@ const GLOBAL_FLAGS: Record<
|
|
|
30
33
|
|
|
31
34
|
// top-level verbs that route into runInspect. the surface is intentionally
|
|
32
35
|
// tiny — everything else lives under one of the grouping verbs:
|
|
33
|
-
// - `
|
|
34
|
-
// - `
|
|
35
|
-
// - `
|
|
36
|
+
// - `rnx get <noun>` reads
|
|
37
|
+
// - `rnx do <action>` writes
|
|
38
|
+
// - `rnx debug <tool>` instrumentation (handled by runDebug)
|
|
36
39
|
// `describe` and `find` stay at root as the most common entrypoints.
|
|
37
40
|
// `list` stays at root because it's a sim-management read.
|
|
38
41
|
export const TOP_LEVEL_RUNTIME_COMMANDS = new Set([
|
|
@@ -47,9 +50,9 @@ export const TOP_LEVEL_RUNTIME_COMMANDS = new Set([
|
|
|
47
50
|
'shell',
|
|
48
51
|
])
|
|
49
52
|
|
|
50
|
-
// grouping verbs that take a sub-verb (`
|
|
51
|
-
// `
|
|
52
|
-
// form (`
|
|
53
|
+
// grouping verbs that take a sub-verb (`rnx wait ready`,
|
|
54
|
+
// `rnx do tap-id`). agents and humans very often type the hyphenated
|
|
55
|
+
// form (`rnx wait-ready`, `rnx do-tap-id`) — it reads as one
|
|
53
56
|
// command and matches the typed-tool names (rnx_wait_ready). bin.ts
|
|
54
57
|
// normalizes `<verb>-<rest>` → `<verb> <rest>` for these so the intuitive
|
|
55
58
|
// spelling just works instead of failing as "unknown command".
|
|
@@ -60,64 +63,9 @@ export const HYPHENATED_GROUPING_VERBS = new Set(['do', 'get', 'wait', 'shell',
|
|
|
60
63
|
// `packages/sootsim-skills/src/cli/meta.ts` (or sit on the internal
|
|
61
64
|
// allowlist in `test/sootsimCliRegistry.test.ts`), so help, website docs,
|
|
62
65
|
// and agent skills can never drift from what the parser accepts.
|
|
63
|
-
export const COMMANDS = new Set(
|
|
64
|
-
'detox',
|
|
65
|
-
'maestro',
|
|
66
|
-
'record',
|
|
67
|
-
'film',
|
|
68
|
-
'storage',
|
|
69
|
-
'permissions',
|
|
70
|
-
'perf',
|
|
71
|
-
'screenshot',
|
|
72
|
-
'state',
|
|
73
|
-
'reset',
|
|
74
|
-
'camera',
|
|
75
|
-
'mode',
|
|
76
|
-
'debug',
|
|
77
|
-
'timeline',
|
|
78
|
-
'what-happened',
|
|
79
|
-
'shell',
|
|
80
|
-
'assert',
|
|
81
|
-
'device',
|
|
82
|
-
'open',
|
|
83
|
-
// platform entrypoints — start a simulator on that platform. the execution
|
|
84
|
-
// environment (host, local box, cloud box) comes from the command context,
|
|
85
|
-
// not from a separate spelling per place.
|
|
86
|
-
'ios',
|
|
87
|
-
'android',
|
|
88
|
-
// the box environment: bare `box` is local, `box create` is cloud.
|
|
89
|
-
'box',
|
|
90
|
-
'list',
|
|
91
|
-
'use',
|
|
92
|
-
'claim',
|
|
93
|
-
'close',
|
|
94
|
-
'compat',
|
|
95
|
-
'report-issue',
|
|
96
|
-
'desktop',
|
|
97
|
-
'login',
|
|
98
|
-
'logout',
|
|
99
|
-
'auth',
|
|
100
|
-
'setup',
|
|
101
|
-
'serve',
|
|
102
|
-
'daemon',
|
|
103
|
-
'runtime',
|
|
104
|
-
'upgrade',
|
|
105
|
-
'version',
|
|
106
|
-
'skill',
|
|
107
|
-
'config',
|
|
108
|
-
'cleanup',
|
|
109
|
-
// stage config-plugin fonts into a build's asset manifest (run.sh build path)
|
|
110
|
-
'app-fonts',
|
|
111
|
-
// internal — not user-facing, spawned as a subprocess by electron main
|
|
112
|
-
// and by `sootsim agent start`.
|
|
113
|
-
'agent-wrapper',
|
|
114
|
-
// attached projects + local agent sessions.
|
|
115
|
-
'agent',
|
|
116
|
-
...TOP_LEVEL_RUNTIME_COMMANDS,
|
|
117
|
-
])
|
|
66
|
+
export const COMMANDS = new Set(RNX_NODE_COMMAND_NAMES)
|
|
118
67
|
|
|
119
|
-
export function
|
|
120
|
-
const args = argv.slice(2)
|
|
68
|
+
export function parseRnxArgs(args: string[]): ParsedArgs {
|
|
121
69
|
const result: ParsedArgs = {
|
|
122
70
|
command: null,
|
|
123
71
|
commandArgs: [],
|
|
@@ -125,6 +73,7 @@ export function parseArgs(argv: string[]): ParsedArgs {
|
|
|
125
73
|
help: false,
|
|
126
74
|
version: false,
|
|
127
75
|
verbose: false,
|
|
76
|
+
warnings: [],
|
|
128
77
|
}
|
|
129
78
|
|
|
130
79
|
let i = 0
|
|
@@ -154,14 +103,14 @@ export function parseArgs(argv: string[]): ParsedArgs {
|
|
|
154
103
|
const val = args[i + 1]
|
|
155
104
|
if (val === undefined || val.startsWith('-')) {
|
|
156
105
|
// missing value — treat as error, pass through
|
|
157
|
-
|
|
106
|
+
result.warnings.push(` warning: ${arg} requires a value`)
|
|
158
107
|
i++
|
|
159
108
|
continue
|
|
160
109
|
}
|
|
161
110
|
if (def.type === 'number') {
|
|
162
111
|
const num = Number(val)
|
|
163
112
|
if (Number.isNaN(num)) {
|
|
164
|
-
|
|
113
|
+
result.warnings.push(` warning: ${arg} requires a number, got "${val}"`)
|
|
165
114
|
i += 2
|
|
166
115
|
continue
|
|
167
116
|
}
|
|
@@ -193,7 +142,7 @@ export function parseArgs(argv: string[]): ParsedArgs {
|
|
|
193
142
|
break
|
|
194
143
|
}
|
|
195
144
|
}
|
|
196
|
-
if (
|
|
145
|
+
if (RNX_COMMAND_NAMES.has(arg)) {
|
|
197
146
|
result.command = arg
|
|
198
147
|
const rest = args.slice(i + 1)
|
|
199
148
|
// strip leading -- separator if present
|
|
@@ -217,3 +166,7 @@ export function parseArgs(argv: string[]): ParsedArgs {
|
|
|
217
166
|
|
|
218
167
|
return result
|
|
219
168
|
}
|
|
169
|
+
|
|
170
|
+
export function parseArgs(argv: string[]): ParsedArgs {
|
|
171
|
+
return parseRnxArgs(argv.slice(2))
|
|
172
|
+
}
|
package/cli/recording-access.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface RecordingEntitlementOptions {
|
|
|
42
42
|
* origin stored in the shared desktop session. */
|
|
43
43
|
originOverride?: string
|
|
44
44
|
/** allow GitHub installation/action auth to record for pr preview uploads.
|
|
45
|
-
* this is intentionally opt-in so local `
|
|
45
|
+
* this is intentionally opt-in so local `rnx record` stays tied to
|
|
46
46
|
* the user's paid/trial desktop entitlement. */
|
|
47
47
|
allowGitHubAuth?: boolean
|
|
48
48
|
}
|
package/cli/registry.ts
CHANGED
package/cli/run-registry.ts
CHANGED
|
@@ -99,7 +99,7 @@ export function resolveRunProvenance(): RunProvenance {
|
|
|
99
99
|
|
|
100
100
|
const branch = contrastBranch ?? gitOutput('git rev-parse --abbrev-ref HEAD')
|
|
101
101
|
// env slug wins when present; otherwise infer from the github remote so a
|
|
102
|
-
// a plain local `
|
|
102
|
+
// a plain local `rnx maestro test --preview` still lands on its repo's dashboard.
|
|
103
103
|
const remote = envOwner ? null : ownerRepoFromGitRemote()
|
|
104
104
|
return {
|
|
105
105
|
owner: envOwner ?? remote?.owner ?? null,
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRnxCommandInvocation,
|
|
3
|
+
getRnxCommandAvailability,
|
|
4
|
+
getRnxFirstPositional,
|
|
5
|
+
} from './command-registry'
|
|
6
|
+
import { renderRnxHelp } from './help-core'
|
|
7
|
+
import { resolveHiddenRuntimeAlias } from './hidden-runtime-alias'
|
|
8
|
+
import { parseRnxArgs } from './parse-args'
|
|
9
|
+
import type {
|
|
10
|
+
CommandArtifact,
|
|
11
|
+
CommandExecutionResult,
|
|
12
|
+
CommandWriter,
|
|
13
|
+
RunRnxCoreOptions,
|
|
14
|
+
SemanticInvocation,
|
|
15
|
+
} from './command-contract'
|
|
16
|
+
|
|
17
|
+
interface CapturedCommandWriter {
|
|
18
|
+
writer: CommandWriter
|
|
19
|
+
stdout: string[]
|
|
20
|
+
stderr: string[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createCapturedWriter(writer?: CommandWriter): CapturedCommandWriter {
|
|
24
|
+
const stdout: string[] = []
|
|
25
|
+
const stderr: string[] = []
|
|
26
|
+
return {
|
|
27
|
+
stdout,
|
|
28
|
+
stderr,
|
|
29
|
+
writer: {
|
|
30
|
+
stdout(text) {
|
|
31
|
+
stdout.push(text)
|
|
32
|
+
writer?.stdout(text)
|
|
33
|
+
},
|
|
34
|
+
stderr(text) {
|
|
35
|
+
stderr.push(text)
|
|
36
|
+
writer?.stderr(text)
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function result(
|
|
43
|
+
captured: CapturedCommandWriter,
|
|
44
|
+
exitCode: number,
|
|
45
|
+
invocations: SemanticInvocation[] = [],
|
|
46
|
+
artifacts: CommandArtifact[] = [],
|
|
47
|
+
): CommandExecutionResult {
|
|
48
|
+
return {
|
|
49
|
+
exitCode,
|
|
50
|
+
stdout: captured.stdout.join(''),
|
|
51
|
+
stderr: captured.stderr.join(''),
|
|
52
|
+
invocations,
|
|
53
|
+
artifacts,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function runRnxCore(
|
|
58
|
+
argv: string[],
|
|
59
|
+
options: RunRnxCoreOptions,
|
|
60
|
+
): Promise<CommandExecutionResult> {
|
|
61
|
+
const captured = createCapturedWriter(options.writer)
|
|
62
|
+
const signal = options.signal ?? new AbortController().signal
|
|
63
|
+
let parsed = parseRnxArgs(argv)
|
|
64
|
+
for (const warning of parsed.warnings) captured.writer.stderr(`${warning}\n`)
|
|
65
|
+
|
|
66
|
+
if (!parsed.command && parsed.commandArgs.length > 0) {
|
|
67
|
+
parsed = resolveHiddenRuntimeAlias(parsed)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (parsed.version) {
|
|
71
|
+
captured.writer.stderr(
|
|
72
|
+
'rnx --version is unavailable in the browser backend; use the node backend.\n',
|
|
73
|
+
)
|
|
74
|
+
return result(captured, 1)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!parsed.command) {
|
|
78
|
+
if (parsed.commandArgs.length > 0) {
|
|
79
|
+
const attempted = getRnxFirstPositional(parsed.commandArgs) ?? parsed.commandArgs[0]
|
|
80
|
+
captured.writer.stderr(`unknown command: ${attempted}\n`)
|
|
81
|
+
return result(captured, 1)
|
|
82
|
+
}
|
|
83
|
+
captured.writer.stdout(`${renderRnxHelp({ backend: options.backend.kind })}\n`)
|
|
84
|
+
return result(captured, 0)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const command = parsed.command
|
|
88
|
+
const helpRequested =
|
|
89
|
+
parsed.help ||
|
|
90
|
+
parsed.commandArgs.includes('--help') ||
|
|
91
|
+
parsed.commandArgs.includes('-h')
|
|
92
|
+
if (helpRequested) {
|
|
93
|
+
const grouping = new Set(['do', 'get', 'debug', 'wait'])
|
|
94
|
+
const subVerb = getRnxFirstPositional(parsed.commandArgs)
|
|
95
|
+
captured.writer.stdout(
|
|
96
|
+
`${renderRnxHelp({
|
|
97
|
+
backend: options.backend.kind,
|
|
98
|
+
command,
|
|
99
|
+
commandArgs: parsed.commandArgs,
|
|
100
|
+
prefer: grouping.has(command) && subVerb ? 'verb' : undefined,
|
|
101
|
+
group: grouping.has(command) ? command : undefined,
|
|
102
|
+
})}\n`,
|
|
103
|
+
)
|
|
104
|
+
return result(captured, 0)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const availability = getRnxCommandAvailability(
|
|
108
|
+
command,
|
|
109
|
+
parsed.commandArgs,
|
|
110
|
+
options.backend.kind,
|
|
111
|
+
)
|
|
112
|
+
if (!availability.available) {
|
|
113
|
+
captured.writer.stderr(`${availability.reason ?? `rnx ${command} is unavailable`}\n`)
|
|
114
|
+
return result(captured, 1)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (signal.aborted) {
|
|
118
|
+
captured.writer.stderr('rnx: command cancelled\n')
|
|
119
|
+
return result(captured, 1)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const invocation = createRnxCommandInvocation({
|
|
123
|
+
command,
|
|
124
|
+
args: parsed.commandArgs,
|
|
125
|
+
globalFlags: parsed.globalFlags,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const execution = await options.backend.execute(invocation, {
|
|
130
|
+
writer: captured.writer,
|
|
131
|
+
signal,
|
|
132
|
+
})
|
|
133
|
+
return result(
|
|
134
|
+
captured,
|
|
135
|
+
execution.exitCode,
|
|
136
|
+
execution.invocations,
|
|
137
|
+
execution.artifacts,
|
|
138
|
+
)
|
|
139
|
+
} catch (error) {
|
|
140
|
+
const message = signal.aborted
|
|
141
|
+
? 'command cancelled'
|
|
142
|
+
: error instanceof Error
|
|
143
|
+
? error.message
|
|
144
|
+
: String(error)
|
|
145
|
+
captured.writer.stderr(`rnx: ${message}\n`)
|
|
146
|
+
return result(captured, 1)
|
|
147
|
+
}
|
|
148
|
+
}
|