peachsim 0.1.527
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 +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RnxBrowserOperations,
|
|
3
|
+
RnxCommandBackend,
|
|
4
|
+
RnxCommandInvocation,
|
|
5
|
+
RnxExecutionContext,
|
|
6
|
+
} from './command-contract'
|
|
7
|
+
|
|
8
|
+
export function createRnxBrowserBackend(
|
|
9
|
+
operations: RnxBrowserOperations,
|
|
10
|
+
): RnxCommandBackend {
|
|
11
|
+
return {
|
|
12
|
+
kind: 'browser',
|
|
13
|
+
execute(invocation: RnxCommandInvocation, context: RnxExecutionContext) {
|
|
14
|
+
switch (invocation.family) {
|
|
15
|
+
case 'preview':
|
|
16
|
+
return operations.selectPreview(invocation, context)
|
|
17
|
+
case 'runtime':
|
|
18
|
+
return operations.readRuntime(invocation, context)
|
|
19
|
+
case 'tree':
|
|
20
|
+
return operations.inspectTree(invocation, context)
|
|
21
|
+
case 'layout':
|
|
22
|
+
return operations.inspectLayout(invocation, context)
|
|
23
|
+
case 'find':
|
|
24
|
+
return operations.find(invocation, context)
|
|
25
|
+
case 'wait':
|
|
26
|
+
return operations.wait(invocation, context)
|
|
27
|
+
case 'action':
|
|
28
|
+
return operations.act(invocation, context)
|
|
29
|
+
case 'screenshot':
|
|
30
|
+
return operations.screenshot(invocation, context)
|
|
31
|
+
case 'logs':
|
|
32
|
+
return operations.readLogs(invocation, context)
|
|
33
|
+
case 'network':
|
|
34
|
+
return operations.readNetwork(invocation, context)
|
|
35
|
+
case 'storage':
|
|
36
|
+
return operations.accessStorage(invocation, context)
|
|
37
|
+
case 'history':
|
|
38
|
+
return operations.readHistory(invocation, context)
|
|
39
|
+
case 'evidence':
|
|
40
|
+
return operations.collectEvidence(invocation, context)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// browser-side evaluator snippets for CLI inspect commands.
|
|
2
|
+
//
|
|
3
|
+
// the rnx CLI ships some commands that need to observe the live
|
|
4
|
+
// rnx tree or its rendered pixels. we send these strings over the rnx host's
|
|
5
|
+
// `evaluate` handler.
|
|
6
|
+
//
|
|
7
|
+
// cropping happens once, in the capture module (`bridges.screenshot`),
|
|
8
|
+
// via its `crop` option. these evals intentionally defer to that bridge
|
|
9
|
+
// instead of reimplementing the dpr-aware crop math.
|
|
10
|
+
|
|
11
|
+
export interface SampleRect {
|
|
12
|
+
x: number
|
|
13
|
+
y: number
|
|
14
|
+
w: number
|
|
15
|
+
h: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// resolve a --id/--text matcher into a SampleRect using __sootsimTest.
|
|
19
|
+
// returns null on miss so the caller can report a clear not-found error.
|
|
20
|
+
export function buildResolveRectEval(matcher: { id?: string; text?: string }): string {
|
|
21
|
+
return `(async () => {
|
|
22
|
+
const __t = window.__sootsimTest
|
|
23
|
+
if (!__t) throw new Error('__sootsimTest not available')
|
|
24
|
+
const __id = ${JSON.stringify(matcher.id || '')}
|
|
25
|
+
const __text = ${JSON.stringify(matcher.text || '')}
|
|
26
|
+
let __node = null
|
|
27
|
+
if (__id) {
|
|
28
|
+
__node = (__t.findByTestId && await __t.findByTestId(__id)) ||
|
|
29
|
+
(__t.findById && await __t.findById(__id)) || null
|
|
30
|
+
} else if (__text) {
|
|
31
|
+
__node = __t.findByText ? await __t.findByText(__text) : null
|
|
32
|
+
}
|
|
33
|
+
if (!__node) return null
|
|
34
|
+
const __pos = __node.absolutePosition || { x: __node.layout?.x || 0, y: __node.layout?.y || 0 }
|
|
35
|
+
const __layout = __node.layout || {}
|
|
36
|
+
return {
|
|
37
|
+
x: __pos.x,
|
|
38
|
+
y: __pos.y,
|
|
39
|
+
w: __layout.width || 1,
|
|
40
|
+
h: __layout.height || 1,
|
|
41
|
+
}
|
|
42
|
+
})()`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// sample-color averages rgba pixels across a logical-coord rect. the eval
|
|
46
|
+
// asks the capture bridge for an already-cropped PNG and then averages the
|
|
47
|
+
// decoded ImageData in one pass.
|
|
48
|
+
export function buildSampleColorEval(rect: SampleRect): string {
|
|
49
|
+
return `(async () => {
|
|
50
|
+
const __rect = ${JSON.stringify(rect)}
|
|
51
|
+
const __screenshot = window.__sootsimScreenshot
|
|
52
|
+
if (typeof __screenshot !== 'function') {
|
|
53
|
+
throw new Error('screenshot bridge not installed')
|
|
54
|
+
}
|
|
55
|
+
const __dataUrl = await __screenshot({ crop: __rect })
|
|
56
|
+
const __img = await new Promise((res, rej) => {
|
|
57
|
+
const img = new Image()
|
|
58
|
+
img.onload = () => res(img)
|
|
59
|
+
img.onerror = () => rej(new Error('failed to decode cropped screenshot'))
|
|
60
|
+
img.src = __dataUrl
|
|
61
|
+
})
|
|
62
|
+
const __w = __img.naturalWidth
|
|
63
|
+
const __h = __img.naturalHeight
|
|
64
|
+
const __canvas = document.createElement('canvas')
|
|
65
|
+
__canvas.width = __w
|
|
66
|
+
__canvas.height = __h
|
|
67
|
+
const __ctx = __canvas.getContext('2d')
|
|
68
|
+
if (!__ctx) throw new Error('could not acquire 2d context')
|
|
69
|
+
__ctx.drawImage(__img, 0, 0)
|
|
70
|
+
const __data = __ctx.getImageData(0, 0, __w, __h).data
|
|
71
|
+
const __n = __data.length / 4
|
|
72
|
+
let __r = 0, __g = 0, __b = 0, __a = 0
|
|
73
|
+
for (let __i = 0; __i < __data.length; __i += 4) {
|
|
74
|
+
__r += __data[__i]
|
|
75
|
+
__g += __data[__i + 1]
|
|
76
|
+
__b += __data[__i + 2]
|
|
77
|
+
__a += __data[__i + 3]
|
|
78
|
+
}
|
|
79
|
+
const __round = (v) => Math.round(v / __n)
|
|
80
|
+
const __rr = __round(__r), __gg = __round(__g), __bb = __round(__b), __aa = __round(__a)
|
|
81
|
+
const __hex =
|
|
82
|
+
'#' +
|
|
83
|
+
[__rr, __gg, __bb]
|
|
84
|
+
.map((v) => v.toString(16).padStart(2, '0'))
|
|
85
|
+
.join('')
|
|
86
|
+
const __dpr = window.devicePixelRatio || 1
|
|
87
|
+
return {
|
|
88
|
+
r: __rr, g: __gg, b: __bb, a: __aa,
|
|
89
|
+
hex: __hex,
|
|
90
|
+
samples: __n,
|
|
91
|
+
rect: { x: __rect.x, y: __rect.y, w: __rect.w, h: __rect.h },
|
|
92
|
+
deviceWidth: __w / __dpr,
|
|
93
|
+
deviceHeight: __h / __dpr,
|
|
94
|
+
}
|
|
95
|
+
})()`
|
|
96
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { compareSemver } from '@contrast/runtime-delivery'
|
|
4
|
+
import { getCliVersion } from '../src/cli-version'
|
|
5
|
+
import { cliUpdateFilePath } from '../src/home-paths'
|
|
6
|
+
import { isAgentEnv } from './commands/inspect/env'
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_CLI_RELEASE_ORIGIN = 'https://r2.rnxsim.com/rnx-cli'
|
|
9
|
+
export const CLI_UPDATE_CHECK_INTERVAL_MS = 20 * 60 * 60 * 1000
|
|
10
|
+
export const CLI_UPDATE_NOTIFICATION_COOLDOWN_MS = 7 * 24 * 60 * 60 * 1000
|
|
11
|
+
|
|
12
|
+
const CLI_UPDATE_STATE_SCHEMA = 1 as const
|
|
13
|
+
const CLI_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/
|
|
14
|
+
let stateWriteSequence = 0
|
|
15
|
+
|
|
16
|
+
interface CliUpdateState {
|
|
17
|
+
schema: typeof CLI_UPDATE_STATE_SCHEMA
|
|
18
|
+
latestVersion: string | null
|
|
19
|
+
checkedAt: number
|
|
20
|
+
lastAttemptAt: number
|
|
21
|
+
lastNotifiedVersion: string | null
|
|
22
|
+
lastNotifiedAt: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CliUpdateAvailability {
|
|
26
|
+
currentVersion: string
|
|
27
|
+
latestVersion: string
|
|
28
|
+
outdated: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CliUpdateInvocation {
|
|
32
|
+
command: string | null
|
|
33
|
+
commandArgs: readonly string[]
|
|
34
|
+
exitCode: number
|
|
35
|
+
standalone: boolean
|
|
36
|
+
stderrIsTTY: boolean
|
|
37
|
+
stdoutIsTTY: boolean
|
|
38
|
+
version: boolean
|
|
39
|
+
env?: Readonly<Record<string, string | undefined>>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function emptyState(): CliUpdateState {
|
|
43
|
+
return {
|
|
44
|
+
schema: CLI_UPDATE_STATE_SCHEMA,
|
|
45
|
+
latestVersion: null,
|
|
46
|
+
checkedAt: 0,
|
|
47
|
+
lastAttemptAt: 0,
|
|
48
|
+
lastNotifiedVersion: null,
|
|
49
|
+
lastNotifiedAt: 0,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
54
|
+
return value !== null && typeof value === 'object'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isTimestamp(value: unknown): value is number {
|
|
58
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function readState(): CliUpdateState {
|
|
62
|
+
try {
|
|
63
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(cliUpdateFilePath(), 'utf8'))
|
|
64
|
+
if (
|
|
65
|
+
!isRecord(parsed) ||
|
|
66
|
+
parsed.schema !== CLI_UPDATE_STATE_SCHEMA ||
|
|
67
|
+
(parsed.latestVersion !== null &&
|
|
68
|
+
(typeof parsed.latestVersion !== 'string' ||
|
|
69
|
+
!CLI_VERSION_PATTERN.test(parsed.latestVersion))) ||
|
|
70
|
+
!isTimestamp(parsed.checkedAt) ||
|
|
71
|
+
!isTimestamp(parsed.lastAttemptAt) ||
|
|
72
|
+
(parsed.lastNotifiedVersion !== null &&
|
|
73
|
+
(typeof parsed.lastNotifiedVersion !== 'string' ||
|
|
74
|
+
!CLI_VERSION_PATTERN.test(parsed.lastNotifiedVersion))) ||
|
|
75
|
+
!isTimestamp(parsed.lastNotifiedAt)
|
|
76
|
+
) {
|
|
77
|
+
return emptyState()
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
schema: CLI_UPDATE_STATE_SCHEMA,
|
|
81
|
+
latestVersion: parsed.latestVersion,
|
|
82
|
+
checkedAt: parsed.checkedAt,
|
|
83
|
+
lastAttemptAt: parsed.lastAttemptAt,
|
|
84
|
+
lastNotifiedVersion: parsed.lastNotifiedVersion,
|
|
85
|
+
lastNotifiedAt: parsed.lastNotifiedAt,
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
return emptyState()
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function writeState(state: CliUpdateState): boolean {
|
|
93
|
+
const file = cliUpdateFilePath()
|
|
94
|
+
const temporary = `${file}.tmp-${process.pid}-${stateWriteSequence++}`
|
|
95
|
+
try {
|
|
96
|
+
fs.mkdirSync(path.dirname(file), { recursive: true })
|
|
97
|
+
fs.writeFileSync(temporary, `${JSON.stringify(state)}\n`, 'utf8')
|
|
98
|
+
fs.renameSync(temporary, file)
|
|
99
|
+
return true
|
|
100
|
+
} catch {
|
|
101
|
+
try {
|
|
102
|
+
fs.rmSync(temporary, { force: true })
|
|
103
|
+
} catch {}
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function availability(
|
|
109
|
+
state: CliUpdateState,
|
|
110
|
+
currentVersion = getCliVersion(),
|
|
111
|
+
): CliUpdateAvailability | null {
|
|
112
|
+
if (!state.latestVersion) return null
|
|
113
|
+
return {
|
|
114
|
+
currentVersion,
|
|
115
|
+
latestVersion: state.latestVersion,
|
|
116
|
+
outdated: compareSemver(state.latestVersion, currentVersion) > 0,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function envFlagIsOff(value: string | undefined): boolean {
|
|
121
|
+
return (
|
|
122
|
+
value === '0' || value?.toLowerCase() === 'false' || value?.toLowerCase() === 'off'
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function envFlagIsOn(value: string | undefined): boolean {
|
|
127
|
+
return Boolean(value) && !envFlagIsOff(value)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function automaticCliUpdateChecksEnabled(
|
|
131
|
+
env: Readonly<Record<string, string | undefined>> = process.env,
|
|
132
|
+
): boolean {
|
|
133
|
+
return !envFlagIsOff(env.RNX_UPDATE_CHECK)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function shouldUseAutomaticCliUpdateCheck(
|
|
137
|
+
invocation: CliUpdateInvocation,
|
|
138
|
+
): boolean {
|
|
139
|
+
const env = invocation.env ?? process.env
|
|
140
|
+
if (
|
|
141
|
+
!invocation.standalone ||
|
|
142
|
+
invocation.exitCode !== 0 ||
|
|
143
|
+
invocation.version ||
|
|
144
|
+
!invocation.stdoutIsTTY ||
|
|
145
|
+
!invocation.stderrIsTTY ||
|
|
146
|
+
!automaticCliUpdateChecksEnabled(env) ||
|
|
147
|
+
envFlagIsOn(env.CI) ||
|
|
148
|
+
envFlagIsOn(env.GITHUB_ACTIONS) ||
|
|
149
|
+
envFlagIsOn(env.RNX_NO_PROMPT) ||
|
|
150
|
+
isAgentEnv(env) ||
|
|
151
|
+
invocation.commandArgs.includes('--json') ||
|
|
152
|
+
invocation.commandArgs.includes('--ci') ||
|
|
153
|
+
invocation.commandArgs.includes('--dry-run')
|
|
154
|
+
) {
|
|
155
|
+
return false
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return !['agent-wrapper', 'cleanup', 'daemon', 'serve', 'upgrade', 'version'].includes(
|
|
159
|
+
invocation.command ?? '',
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function claimAutomaticCliUpdateCheck(now = Date.now()): boolean {
|
|
164
|
+
const state = readState()
|
|
165
|
+
const lastCheck = Math.max(state.checkedAt, state.lastAttemptAt)
|
|
166
|
+
if (now >= lastCheck && now - lastCheck < CLI_UPDATE_CHECK_INTERVAL_MS) {
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
return writeState({ ...state, lastAttemptAt: now })
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function readCachedCliUpdate(
|
|
173
|
+
currentVersion = getCliVersion(),
|
|
174
|
+
): CliUpdateAvailability | null {
|
|
175
|
+
return availability(readState(), currentVersion)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function takeCliUpdateNotification(
|
|
179
|
+
currentVersion = getCliVersion(),
|
|
180
|
+
now = Date.now(),
|
|
181
|
+
): CliUpdateAvailability | null {
|
|
182
|
+
const state = readState()
|
|
183
|
+
const update = availability(state, currentVersion)
|
|
184
|
+
if (!update?.outdated || state.lastNotifiedVersion === update.latestVersion) return null
|
|
185
|
+
if (
|
|
186
|
+
now >= state.lastNotifiedAt &&
|
|
187
|
+
now - state.lastNotifiedAt < CLI_UPDATE_NOTIFICATION_COOLDOWN_MS
|
|
188
|
+
) {
|
|
189
|
+
return null
|
|
190
|
+
}
|
|
191
|
+
if (
|
|
192
|
+
!writeState({
|
|
193
|
+
...state,
|
|
194
|
+
lastNotifiedVersion: update.latestVersion,
|
|
195
|
+
lastNotifiedAt: now,
|
|
196
|
+
})
|
|
197
|
+
) {
|
|
198
|
+
return null
|
|
199
|
+
}
|
|
200
|
+
return update
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export async function fetchCliReleaseFile(
|
|
204
|
+
url: string,
|
|
205
|
+
timeoutMs: number,
|
|
206
|
+
): Promise<Buffer> {
|
|
207
|
+
let response: Response
|
|
208
|
+
try {
|
|
209
|
+
response = await fetch(url, {
|
|
210
|
+
headers: { accept: 'application/octet-stream' },
|
|
211
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
212
|
+
})
|
|
213
|
+
} catch (error) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
`could not reach the rnx update service: ${
|
|
216
|
+
error instanceof Error ? error.message : String(error)
|
|
217
|
+
}`,
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`rnx update download failed: ${response.status} ${response.statusText}`,
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
return Buffer.from(await response.arrayBuffer())
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export async function refreshCliUpdateCache(
|
|
229
|
+
options: { releaseOrigin?: string; now?: number; timeoutMs?: number } = {},
|
|
230
|
+
): Promise<CliUpdateAvailability> {
|
|
231
|
+
const releaseOrigin = (options.releaseOrigin ?? DEFAULT_CLI_RELEASE_ORIGIN).replace(
|
|
232
|
+
/\/+$/,
|
|
233
|
+
'',
|
|
234
|
+
)
|
|
235
|
+
const latestVersion = (
|
|
236
|
+
await fetchCliReleaseFile(
|
|
237
|
+
`${releaseOrigin}/channels/stable`,
|
|
238
|
+
options.timeoutMs ?? 8_000,
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
.toString('utf8')
|
|
242
|
+
.trim()
|
|
243
|
+
if (!CLI_VERSION_PATTERN.test(latestVersion)) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`rnx update service returned an invalid version: ${latestVersion || '(empty)'}`,
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const now = options.now ?? Date.now()
|
|
250
|
+
const state = readState()
|
|
251
|
+
const next: CliUpdateState = {
|
|
252
|
+
...state,
|
|
253
|
+
latestVersion,
|
|
254
|
+
checkedAt: now,
|
|
255
|
+
lastAttemptAt: now,
|
|
256
|
+
}
|
|
257
|
+
writeState(next)
|
|
258
|
+
const update = availability(next)
|
|
259
|
+
if (!update) throw new Error('rnx update cache did not retain the latest version')
|
|
260
|
+
return update
|
|
261
|
+
}
|