peachsim 0.1.627 → 0.1.629
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 +1 -1
- package/cli/bin.ts +6 -2
- package/cli/bridge-flow-runner.ts +79 -72
- package/cli/commands/cleanup.ts +6 -6
- package/cli/commands/control.ts +4 -5
- package/cli/commands/detox.ts +25 -11
- package/cli/commands/flow.ts +3 -2
- package/cli/commands/inspect/core.ts +5 -0
- package/cli/commands/inspect.ts +43 -49
- package/cli/commands/mode.ts +11 -7
- package/cli/commands/report-issue.ts +1 -1
- package/cli/commands/setup.ts +16 -11
- package/cli/commands/show-touches-mode.ts +33 -0
- package/cli/commands/skills.ts +16 -0
- package/cli/commands/test.ts +8 -1
- package/cli/commands/welcome.ts +3 -3
- package/cli/drivers/playwright-sim-host.ts +6 -5
- package/cli/help-core.ts +9 -4
- package/cli/internal-child.ts +14 -2
- package/cli/levenshtein.ts +27 -0
- package/cli/main.ts +28 -18
- package/cli/ws-bridge.ts +3 -2
- package/detox/index.ts +234 -7
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +170 -13
- package/dist-lib/dev-bundle-resolution.cjs +2 -2
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +57 -97
- 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 +44 -5
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/menu.cjs +7 -1
- package/dist-lib/menu.mjs +7 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +43 -4
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +159 -210
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +7276 -7131
- package/dist-lib/vite-kotlin.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +43 -4
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +1 -1
- package/src/dev-bundle-resolution.ts +1 -1
- package/src/host/bridge-host.ts +2 -34
- package/src/menu.ts +7 -0
- package/src/native-seam-manifest.ts +4 -16
- package/src/runtime-assets.ts +59 -2
- package/src/screenshots/frame-compose.ts +4 -1
- package/src/vite-plugin.ts +723 -25
package/cli/commands/setup.ts
CHANGED
|
@@ -54,6 +54,7 @@ interface SetupOptions {
|
|
|
54
54
|
|
|
55
55
|
interface SetupRunOptions {
|
|
56
56
|
launchConnectRN?: boolean
|
|
57
|
+
port?: number
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export interface SetupResult {
|
|
@@ -120,6 +121,7 @@ export async function runSetup(
|
|
|
120
121
|
channel: 'stable',
|
|
121
122
|
setActive: true,
|
|
122
123
|
protectVersions: activeRuntime ? [activeRuntime] : [],
|
|
124
|
+
quiet: !options.json,
|
|
123
125
|
})
|
|
124
126
|
const result = options.json
|
|
125
127
|
? await install()
|
|
@@ -130,10 +132,16 @@ export async function runSetup(
|
|
|
130
132
|
let serviceInstalled = serviceStatus.installed
|
|
131
133
|
if (service && !serviceStatus.installed && !options.dryRun) {
|
|
132
134
|
if (options.json) {
|
|
133
|
-
await daemonInstall({
|
|
135
|
+
await daemonInstall({
|
|
136
|
+
port: runOptions.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
137
|
+
force: false,
|
|
138
|
+
})
|
|
134
139
|
} else {
|
|
135
140
|
console.log(`\n ${accent('◆')} ${bold('Enabling the background service')}`)
|
|
136
|
-
await daemonInstall({
|
|
141
|
+
await daemonInstall({
|
|
142
|
+
port: runOptions.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
143
|
+
force: false,
|
|
144
|
+
})
|
|
137
145
|
}
|
|
138
146
|
serviceInstalled = true
|
|
139
147
|
}
|
|
@@ -144,13 +152,10 @@ export async function runSetup(
|
|
|
144
152
|
|
|
145
153
|
if (launchConnectRN) {
|
|
146
154
|
console.log(`\n ${accent('◆')} Opening ConnectRN`)
|
|
147
|
-
await runOpenCommand(
|
|
148
|
-
'ConnectRN',
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
'--no-describe',
|
|
152
|
-
'--quiet',
|
|
153
|
-
])
|
|
155
|
+
await runOpenCommand(
|
|
156
|
+
['ConnectRN', '--driver', simulatorDriver, '--no-describe', '--quiet'],
|
|
157
|
+
{ port: runOptions.port },
|
|
158
|
+
)
|
|
154
159
|
}
|
|
155
160
|
|
|
156
161
|
const productAnalytics = await decidePrivacy(options, privacy)
|
|
@@ -324,7 +329,7 @@ async function decideSimulatorDriver(
|
|
|
324
329
|
desktopDescription,
|
|
325
330
|
'The Desktop app opens in a dedicated native window.',
|
|
326
331
|
])
|
|
327
|
-
const choice = await select('Where should peach open
|
|
332
|
+
const choice = await select('Where should peach open?', [
|
|
328
333
|
'Browser (recommended) No additional download',
|
|
329
334
|
desktopChoice,
|
|
330
335
|
])
|
|
@@ -343,7 +348,7 @@ async function decidePrivacy(
|
|
|
343
348
|
'Reports can contain package compatibility or an error class.',
|
|
344
349
|
'They never contain your code or app data.',
|
|
345
350
|
])
|
|
346
|
-
return confirm('Share bounded diagnostics to improve peach
|
|
351
|
+
return confirm('Share bounded diagnostics to improve peach?', false)
|
|
347
352
|
}
|
|
348
353
|
|
|
349
354
|
async function decideRepository(
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// peach mode show-touches — toggle OS touch indicators (Show Single Touches / Show taps)
|
|
2
|
+
// in the running peach sim.
|
|
3
|
+
|
|
4
|
+
import { rnxExit } from '../run-rnx'
|
|
5
|
+
import { runShellBooleanMode, type ShellBooleanModeOptions } from './shell-boolean-mode'
|
|
6
|
+
|
|
7
|
+
export async function runShowTouchesMode(args: string[], opts: ShellBooleanModeOptions) {
|
|
8
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
9
|
+
console.log(`
|
|
10
|
+
peach mode show-touches — toggle touch indicator overlays
|
|
11
|
+
|
|
12
|
+
usage:
|
|
13
|
+
peach mode show-touches [on|off|toggle]
|
|
14
|
+
|
|
15
|
+
arguments:
|
|
16
|
+
on enable touch indicators
|
|
17
|
+
off disable touch indicators
|
|
18
|
+
toggle flip the current state (default)
|
|
19
|
+
|
|
20
|
+
examples:
|
|
21
|
+
peach mode show-touches
|
|
22
|
+
peach mode show-touches on
|
|
23
|
+
peach mode show-touches off
|
|
24
|
+
`)
|
|
25
|
+
rnxExit(0)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await runShellBooleanMode(args, opts, {
|
|
29
|
+
modeKey: 'showTouches',
|
|
30
|
+
displayName: 'show-touches',
|
|
31
|
+
actionId: 'toggle-touches',
|
|
32
|
+
})
|
|
33
|
+
}
|
package/cli/commands/skills.ts
CHANGED
|
@@ -9,10 +9,26 @@ import * as fs from 'fs'
|
|
|
9
9
|
import * as os from 'os'
|
|
10
10
|
import * as path from 'path'
|
|
11
11
|
import { fileURLToPath } from 'url'
|
|
12
|
+
import { getCliVersion } from '../../src/cli-version'
|
|
13
|
+
import { rnxHomeDir } from '../../src/home-paths'
|
|
12
14
|
import { rnxPublicBrand } from '../../src/public-brand'
|
|
13
15
|
import { rnxExit } from '../run-rnx'
|
|
14
16
|
|
|
17
|
+
declare const __PEACH_BUNDLED_SKILLS__: Record<string, string>
|
|
18
|
+
|
|
15
19
|
function getSkillsDir(): string {
|
|
20
|
+
// the standalone binary carries its skills instead of a package directory;
|
|
21
|
+
// write them once per cli version so installs can link to real files.
|
|
22
|
+
if (typeof __PEACH_BUNDLED_SKILLS__ !== 'undefined') {
|
|
23
|
+
const dir = path.join(rnxHomeDir(), 'skills', getCliVersion())
|
|
24
|
+
for (const [file, body] of Object.entries(__PEACH_BUNDLED_SKILLS__)) {
|
|
25
|
+
const target = path.join(dir, file)
|
|
26
|
+
if (fs.existsSync(target)) continue
|
|
27
|
+
fs.mkdirSync(path.dirname(target), { recursive: true })
|
|
28
|
+
fs.writeFileSync(target, body)
|
|
29
|
+
}
|
|
30
|
+
return dir
|
|
31
|
+
}
|
|
16
32
|
try {
|
|
17
33
|
const pkgPath = fileURLToPath(
|
|
18
34
|
import.meta.resolve(`${rnxPublicBrand.packageName}/package.json`),
|
package/cli/commands/test.ts
CHANGED
|
@@ -984,7 +984,14 @@ export async function runTest(
|
|
|
984
984
|
return runCloudTest(args, opts)
|
|
985
985
|
}
|
|
986
986
|
|
|
987
|
-
|
|
987
|
+
// a missing or unknown target is the caller's mistake: one line, no stack.
|
|
988
|
+
let selected: ReturnType<typeof resolveTestCommand>
|
|
989
|
+
try {
|
|
990
|
+
selected = resolveTestCommand(args)
|
|
991
|
+
} catch (error) {
|
|
992
|
+
console.error(` error: ${error instanceof Error ? error.message : String(error)}`)
|
|
993
|
+
return 1
|
|
994
|
+
}
|
|
988
995
|
const app = appFromArgs(args)
|
|
989
996
|
const appTarget = app
|
|
990
997
|
? await resolveTestAppTarget(app)
|
package/cli/commands/welcome.ts
CHANGED
|
@@ -4,14 +4,14 @@ import { printBrand } from '../ui'
|
|
|
4
4
|
import { runOpenCommand } from './control'
|
|
5
5
|
import { runSetup } from './setup'
|
|
6
6
|
|
|
7
|
-
export async function runWelcome(): Promise<number> {
|
|
7
|
+
export async function runWelcome(port: number | undefined): Promise<number> {
|
|
8
8
|
if (!isOnboardingComplete() && canPromptForPrivacyChoice()) {
|
|
9
|
-
await runSetup([], { launchConnectRN: true })
|
|
9
|
+
await runSetup([], { launchConnectRN: true, port })
|
|
10
10
|
return 0
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
printBrand('Run any React Native app in a local simulator.')
|
|
14
14
|
console.log(`\n Opening ConnectRN`)
|
|
15
|
-
await runOpenCommand(['ConnectRN', '--no-describe', '--quiet'])
|
|
15
|
+
await runOpenCommand(['ConnectRN', '--no-describe', '--quiet'], { port })
|
|
16
16
|
return 0
|
|
17
17
|
}
|
|
@@ -446,16 +446,17 @@ const cleanupProfile = () => {
|
|
|
446
446
|
const request = readBrowserCompositeCaptureRequest(value);
|
|
447
447
|
const session = await source.page.context().newCDPSession(source.page);
|
|
448
448
|
try {
|
|
449
|
+
const { clip, originX, originY } = resolveBrowserCompositeCdpClip(
|
|
450
|
+
request,
|
|
451
|
+
await session.send('Page.getLayoutMetrics'),
|
|
452
|
+
);
|
|
449
453
|
const result = await session.send('Page.captureScreenshot', {
|
|
450
454
|
format: 'png',
|
|
451
455
|
fromSurface: true,
|
|
452
456
|
captureBeyondViewport: true,
|
|
453
|
-
clip
|
|
454
|
-
request,
|
|
455
|
-
await session.send('Page.getLayoutMetrics'),
|
|
456
|
-
),
|
|
457
|
+
clip,
|
|
457
458
|
});
|
|
458
|
-
return 'data:image/png;base64,' + result.data;
|
|
459
|
+
return { dataUrl: 'data:image/png;base64,' + result.data, originX, originY };
|
|
459
460
|
} finally {
|
|
460
461
|
await session.detach();
|
|
461
462
|
}
|
package/cli/help-core.ts
CHANGED
|
@@ -96,8 +96,13 @@ Run \`peach <command> --help\` for leaf availability and usage.`
|
|
|
96
96
|
export function renderRnxHelp(options: RnxHelpOptions): string {
|
|
97
97
|
const command = options.command ?? null
|
|
98
98
|
const commandArgs = options.commandArgs ?? []
|
|
99
|
+
// the preview selectors and backend lists describe the factory's browser
|
|
100
|
+
// backend; the public cli runs the node backend and never sees them.
|
|
101
|
+
const factory = options.backend === 'browser'
|
|
99
102
|
if (!command) {
|
|
100
|
-
|
|
103
|
+
const index = renderCliIndexHelp(HELP_CONTEXT, formatFlagHelp()).trimEnd()
|
|
104
|
+
if (!factory) return index
|
|
105
|
+
return `${index}
|
|
101
106
|
|
|
102
107
|
browser preview selectors:
|
|
103
108
|
peach web select the existing Factory web preview
|
|
@@ -108,7 +113,7 @@ ${renderRootAvailability(options.backend)}`
|
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
let body: string | null
|
|
111
|
-
if (command === 'web' || command === 'ios' || command === 'android') {
|
|
116
|
+
if (factory && (command === 'web' || command === 'ios' || command === 'android')) {
|
|
112
117
|
body = renderPreviewHelp(command)
|
|
113
118
|
} else if (options.group === command && !options.prefer) {
|
|
114
119
|
body = renderCliGroupHelp(command, HELP_CONTEXT, formatFlagHelp())
|
|
@@ -130,11 +135,11 @@ ${renderRootAvailability(options.backend)}`
|
|
|
130
135
|
const registration = getRnxCommandRegistration(command)
|
|
131
136
|
if (!registration) return body
|
|
132
137
|
const current = getRnxCommandAvailability(command, commandArgs, options.backend)
|
|
138
|
+
if (!factory && current.available) return body
|
|
133
139
|
const currentLine = current.available
|
|
134
140
|
? `${options.backend} backend: available`
|
|
135
141
|
: `${options.backend} backend: ${current.reason}`
|
|
136
|
-
const factoryLeaves =
|
|
137
|
-
options.backend === 'browser' ? renderFactoryBrowserLeaves(command) : null
|
|
142
|
+
const factoryLeaves = factory ? renderFactoryBrowserLeaves(command) : null
|
|
138
143
|
return `${body.trimEnd()}
|
|
139
144
|
|
|
140
145
|
${factoryLeaves ? `${factoryLeaves}\n\n` : ''}${backendLabel(command, commandArgs)}
|
package/cli/internal-child.ts
CHANGED
|
@@ -18,6 +18,12 @@ import * as vm from 'node:vm'
|
|
|
18
18
|
|
|
19
19
|
export const RNX_INTERNAL_COMMAND = '__internal'
|
|
20
20
|
|
|
21
|
+
// playwright's installer forks its downloader script with process.execPath,
|
|
22
|
+
// which here is this binary. the installer child sets this for its whole
|
|
23
|
+
// process tree, and bin.ts then runs a forked `.js` argument as a script
|
|
24
|
+
// instead of reading it as a peach command.
|
|
25
|
+
export const RNX_FORKED_SCRIPT_ENV = 'PEACH_RUNS_FORKED_SCRIPTS'
|
|
26
|
+
|
|
21
27
|
export const RNX_INTERNAL_CHILDREN = {
|
|
22
28
|
playwrightProbe: 'playwright-probe',
|
|
23
29
|
playwrightInstall: 'playwright-install',
|
|
@@ -113,8 +119,14 @@ function playwrightInstall(args: string[]): void {
|
|
|
113
119
|
if (!cliPath) {
|
|
114
120
|
throw new Error('internal playwright-install needs the package CLI path')
|
|
115
121
|
}
|
|
116
|
-
process.
|
|
117
|
-
|
|
122
|
+
process.env[RNX_FORKED_SCRIPT_ENV] = '1'
|
|
123
|
+
runScript(cliPath, cliArgs)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** run a javascript file as node would, with argv shaped for its own parser. */
|
|
127
|
+
export function runScript(scriptPath: string, args: string[]): void {
|
|
128
|
+
process.argv = [process.argv[0], scriptPath, ...args]
|
|
129
|
+
createRequire(scriptPath)(scriptPath)
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
/** the detached browser host. its source is CJS that resolves playwright from
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function levenshtein(a: string, b: string): number {
|
|
2
|
+
if (a === b) return 0
|
|
3
|
+
if (!a.length) return b.length
|
|
4
|
+
if (!b.length) return a.length
|
|
5
|
+
// standard two-row dp: prev[] is the previous row, cur[] is the row being
|
|
6
|
+
// computed; swap pointers per outer iteration. the earlier in-place rolling
|
|
7
|
+
// version overwrote prev[j-1] twice per cell and never set prev[0]=i, so
|
|
8
|
+
// distance(`kitten`,`sitting`) returned 8 instead of 3 and the fuzzy-suggest
|
|
9
|
+
// ranking was effectively random.
|
|
10
|
+
let prev = new Array<number>(b.length + 1)
|
|
11
|
+
let cur = new Array<number>(b.length + 1)
|
|
12
|
+
for (let j = 0; j <= b.length; j++) prev[j] = j
|
|
13
|
+
for (let i = 1; i <= a.length; i++) {
|
|
14
|
+
cur[0] = i
|
|
15
|
+
for (let j = 1; j <= b.length; j++) {
|
|
16
|
+
cur[j] = Math.min(
|
|
17
|
+
prev[j] + 1,
|
|
18
|
+
cur[j - 1] + 1,
|
|
19
|
+
prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1),
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
const tmp = prev
|
|
23
|
+
prev = cur
|
|
24
|
+
cur = tmp
|
|
25
|
+
}
|
|
26
|
+
return prev[b.length]
|
|
27
|
+
}
|
package/cli/main.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// when none of its hidden entry points claimed the process.
|
|
4
4
|
|
|
5
5
|
import { rnxPublicBrand } from '../src/public-brand'
|
|
6
|
-
import {
|
|
6
|
+
import { levenshtein } from './levenshtein'
|
|
7
|
+
import { COMMANDS, parseArgs, TOP_LEVEL_RUNTIME_COMMANDS } from './parse-args'
|
|
7
8
|
import { RnxExit } from './run-rnx'
|
|
8
9
|
import { rnxSelfInvocation } from './self-invocation'
|
|
9
10
|
import { IS_STANDALONE } from './standalone'
|
|
@@ -37,18 +38,29 @@ function handleTopLevelError(err: unknown): never {
|
|
|
37
38
|
msg.startsWith('peach bridge exited before becoming ready') ||
|
|
38
39
|
msg.startsWith(`${rnxPublicBrand.commandName} open: requested bridge port`) ||
|
|
39
40
|
msg.startsWith('background daemon setup is unavailable') ||
|
|
40
|
-
msg.startsWith('peach bridge did not start within')
|
|
41
|
+
msg.startsWith('peach bridge did not start within') ||
|
|
42
|
+
msg.startsWith('could not resolve a native bundle for ')
|
|
41
43
|
if (isKnownCliFailure && !process.env.SOOTSIM_VERBOSE) {
|
|
42
44
|
process.stderr.write(` ${msg}\n`)
|
|
43
45
|
process.exit(1)
|
|
44
46
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
}
|
|
47
|
+
// bun can render an async-thrown error's stack with a bare `Error` header, so
|
|
48
|
+
// the message always goes first.
|
|
49
|
+
process.stderr.write(` ${msg}\n`)
|
|
50
|
+
if (err instanceof Error && err.stack) process.stderr.write(`${err.stack}\n`)
|
|
50
51
|
process.exit(1)
|
|
51
52
|
}
|
|
53
|
+
function printUnknownCommand(attempted: string) {
|
|
54
|
+
const closest = [...COMMANDS]
|
|
55
|
+
.map((name) => ({ name, distance: levenshtein(attempted, name) }))
|
|
56
|
+
.sort((a, b) => a.distance - b.distance)[0]
|
|
57
|
+
console.error(` unknown command: ${attempted}`)
|
|
58
|
+
if (closest && closest.distance <= 2) {
|
|
59
|
+
console.error(` did you mean \`${rnxPublicBrand.commandName} ${closest.name}\`?`)
|
|
60
|
+
}
|
|
61
|
+
console.error(` run \`${rnxPublicBrand.commandName} --help\` to see the full surface.`)
|
|
62
|
+
}
|
|
63
|
+
|
|
52
64
|
process.on('unhandledRejection', handleTopLevelError)
|
|
53
65
|
process.on('uncaughtException', handleTopLevelError)
|
|
54
66
|
|
|
@@ -73,7 +85,11 @@ const isCliUpdateWorker =
|
|
|
73
85
|
parsed.commandArgs[0] === '--check-worker'
|
|
74
86
|
const isBareWelcome = !parsed.command && parsed.commandArgs.length === 0
|
|
75
87
|
const isReadOnlyInvocation =
|
|
76
|
-
parsed.version ||
|
|
88
|
+
parsed.version ||
|
|
89
|
+
parsed.help ||
|
|
90
|
+
parsed.commandArgs.includes('--help') ||
|
|
91
|
+
parsed.commandArgs.includes('-h') ||
|
|
92
|
+
parsed.commandArgs.includes('--dry-run')
|
|
77
93
|
|
|
78
94
|
if (isCliUpdateWorker) {
|
|
79
95
|
if (IS_STANDALONE) {
|
|
@@ -264,7 +280,7 @@ if (device || theme) {
|
|
|
264
280
|
// returning runs open ConnectRN directly; app discovery belongs inside it.
|
|
265
281
|
if (!parsed.command && parsed.commandArgs.length === 0) {
|
|
266
282
|
const { runWelcome } = await import('./commands/welcome')
|
|
267
|
-
await exitWithFlush(await runWelcome())
|
|
283
|
+
await exitWithFlush(await runWelcome(port))
|
|
268
284
|
}
|
|
269
285
|
|
|
270
286
|
// route to command. an empty command at this point only happens if the
|
|
@@ -280,10 +296,7 @@ if (!command) {
|
|
|
280
296
|
if (parsed.commandArgs.length > 0) {
|
|
281
297
|
const attempted =
|
|
282
298
|
parsed.commandArgs.find((a) => !a.startsWith('-')) ?? parsed.commandArgs[0]
|
|
283
|
-
|
|
284
|
-
console.error(
|
|
285
|
-
` run \`${rnxPublicBrand.commandName} --help\` to see the full surface.`,
|
|
286
|
-
)
|
|
299
|
+
printUnknownCommand(attempted)
|
|
287
300
|
await exitWithFlush(1)
|
|
288
301
|
}
|
|
289
302
|
const { printHelp } = await import('./help')
|
|
@@ -608,7 +621,7 @@ try {
|
|
|
608
621
|
|
|
609
622
|
case 'setup': {
|
|
610
623
|
const { runSetup } = await import('./commands/setup')
|
|
611
|
-
await runSetup(parsed.commandArgs)
|
|
624
|
+
await runSetup(parsed.commandArgs, { port })
|
|
612
625
|
break
|
|
613
626
|
}
|
|
614
627
|
|
|
@@ -685,10 +698,7 @@ try {
|
|
|
685
698
|
}
|
|
686
699
|
|
|
687
700
|
default: {
|
|
688
|
-
|
|
689
|
-
console.error(
|
|
690
|
-
` run \`${rnxPublicBrand.commandName} --help\` to see the full surface.`,
|
|
691
|
-
)
|
|
701
|
+
printUnknownCommand(command)
|
|
692
702
|
await exitWithFlush(1)
|
|
693
703
|
}
|
|
694
704
|
}
|
package/cli/ws-bridge.ts
CHANGED
|
@@ -145,9 +145,10 @@ function resolveDefaultDevBridgeLockfile(): DevBridgeLockfile | null {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// another checkout's bridge on its own offset belongs to that checkout's
|
|
149
|
+
// world; only the canonical bridge is shared, and past it the daemon serves.
|
|
148
150
|
return (
|
|
149
|
-
lockfiles.find((lockfile) => lockfile.bridgePort === DEFAULT_SOOTSIM_BRIDGE_PORT) ??
|
|
150
|
-
lockfiles[0]
|
|
151
|
+
lockfiles.find((lockfile) => lockfile.bridgePort === DEFAULT_SOOTSIM_BRIDGE_PORT) ?? null
|
|
151
152
|
)
|
|
152
153
|
}
|
|
153
154
|
|