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.
Files changed (324) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +640 -0
  3. package/cli/app-config.ts +82 -0
  4. package/cli/app-fonts.ts +388 -0
  5. package/cli/app-project.ts +59 -0
  6. package/cli/app-splash.ts +171 -0
  7. package/cli/app-state-reset.ts +26 -0
  8. package/cli/auth.ts +184 -0
  9. package/cli/bin.ts +59 -0
  10. package/cli/bridge-diagnostics.ts +226 -0
  11. package/cli/bridge-flow-runner.ts +2806 -0
  12. package/cli/browser-backend.ts +44 -0
  13. package/cli/browser-evals.ts +96 -0
  14. package/cli/cli-update.ts +261 -0
  15. package/cli/cloud-client.ts +1530 -0
  16. package/cli/cloud-dispatch.ts +206 -0
  17. package/cli/cloud-session.ts +227 -0
  18. package/cli/command-contract.ts +221 -0
  19. package/cli/command-registry.ts +304 -0
  20. package/cli/commands/agent-wrapper.ts +1048 -0
  21. package/cli/commands/agent.ts +439 -0
  22. package/cli/commands/app-fonts.ts +99 -0
  23. package/cli/commands/assert.ts +542 -0
  24. package/cli/commands/auth.ts +71 -0
  25. package/cli/commands/box/bundle-plane.ts +71 -0
  26. package/cli/commands/box/checkout-plane.ts +256 -0
  27. package/cli/commands/box/plane-share.ts +208 -0
  28. package/cli/commands/box/rnx-command.ts +60 -0
  29. package/cli/commands/box/search-command.ts +157 -0
  30. package/cli/commands/box.ts +925 -0
  31. package/cli/commands/camera.ts +266 -0
  32. package/cli/commands/cleanup.ts +169 -0
  33. package/cli/commands/compat.ts +176 -0
  34. package/cli/commands/config.ts +34 -0
  35. package/cli/commands/control.ts +2154 -0
  36. package/cli/commands/cpu-profile.ts +941 -0
  37. package/cli/commands/daemon-mac-app.ts +165 -0
  38. package/cli/commands/daemon.ts +800 -0
  39. package/cli/commands/debug.ts +751 -0
  40. package/cli/commands/desktop.ts +39 -0
  41. package/cli/commands/detect.ts +201 -0
  42. package/cli/commands/detox.ts +481 -0
  43. package/cli/commands/device.ts +134 -0
  44. package/cli/commands/diagnose.ts +589 -0
  45. package/cli/commands/do-chain.ts +408 -0
  46. package/cli/commands/electron.ts +94 -0
  47. package/cli/commands/film.ts +379 -0
  48. package/cli/commands/flow.ts +1240 -0
  49. package/cli/commands/inspect/actions.ts +516 -0
  50. package/cli/commands/inspect/core.ts +2086 -0
  51. package/cli/commands/inspect/count.ts +17 -0
  52. package/cli/commands/inspect/describe.ts +119 -0
  53. package/cli/commands/inspect/env.ts +25 -0
  54. package/cli/commands/inspect/find.ts +169 -0
  55. package/cli/commands/inspect/get-layout.ts +53 -0
  56. package/cli/commands/inspect/keyboard.ts +54 -0
  57. package/cli/commands/inspect/list.ts +175 -0
  58. package/cli/commands/inspect/memory.ts +215 -0
  59. package/cli/commands/inspect/redaction.ts +39 -0
  60. package/cli/commands/inspect/resolve-target.ts +77 -0
  61. package/cli/commands/inspect/screens.ts +78 -0
  62. package/cli/commands/inspect/settle.ts +32 -0
  63. package/cli/commands/inspect/settling.ts +197 -0
  64. package/cli/commands/inspect/shared.ts +259 -0
  65. package/cli/commands/inspect/sleep.ts +15 -0
  66. package/cli/commands/inspect/tree.ts +23 -0
  67. package/cli/commands/inspect/url.ts +17 -0
  68. package/cli/commands/inspect/wait-event.ts +211 -0
  69. package/cli/commands/inspect/wait-idle.ts +25 -0
  70. package/cli/commands/inspect/wait-ready.ts +87 -0
  71. package/cli/commands/inspect/wait-selector.ts +59 -0
  72. package/cli/commands/inspect/wait.ts +32 -0
  73. package/cli/commands/inspect.ts +4738 -0
  74. package/cli/commands/install-cli.ts +275 -0
  75. package/cli/commands/install-desktop.ts +385 -0
  76. package/cli/commands/login.ts +357 -0
  77. package/cli/commands/logout.ts +24 -0
  78. package/cli/commands/maestro-generate.ts +375 -0
  79. package/cli/commands/maestro.ts +536 -0
  80. package/cli/commands/mode.ts +58 -0
  81. package/cli/commands/no-bridge-hint.ts +80 -0
  82. package/cli/commands/perf.ts +67 -0
  83. package/cli/commands/permissions.ts +203 -0
  84. package/cli/commands/platform.ts +410 -0
  85. package/cli/commands/preview.ts +103 -0
  86. package/cli/commands/profile.ts +106 -0
  87. package/cli/commands/react.ts +353 -0
  88. package/cli/commands/record.ts +1435 -0
  89. package/cli/commands/report-issue.ts +305 -0
  90. package/cli/commands/reset.ts +89 -0
  91. package/cli/commands/runtime.ts +348 -0
  92. package/cli/commands/screenshot-command.ts +106 -0
  93. package/cli/commands/screenshot-layers.ts +144 -0
  94. package/cli/commands/screenshot-mode.ts +38 -0
  95. package/cli/commands/screenshot.ts +492 -0
  96. package/cli/commands/screenshots-capture.ts +608 -0
  97. package/cli/commands/screenshots.ts +127 -0
  98. package/cli/commands/serve.ts +139 -0
  99. package/cli/commands/setup.ts +416 -0
  100. package/cli/commands/shell-boolean-mode.ts +82 -0
  101. package/cli/commands/skills.ts +468 -0
  102. package/cli/commands/slides.ts +357 -0
  103. package/cli/commands/state.ts +94 -0
  104. package/cli/commands/storage.ts +58 -0
  105. package/cli/commands/telemetry.ts +55 -0
  106. package/cli/commands/test.ts +535 -0
  107. package/cli/commands/three-mode.ts +771 -0
  108. package/cli/commands/timeline.ts +121 -0
  109. package/cli/commands/upgrade.ts +167 -0
  110. package/cli/commands/upload.ts +1203 -0
  111. package/cli/commands/version.ts +63 -0
  112. package/cli/commands/welcome.ts +17 -0
  113. package/cli/commands/what-happened.ts +328 -0
  114. package/cli/current-sim.ts +217 -0
  115. package/cli/desktop-companion.ts +315 -0
  116. package/cli/drivers/electron.ts +70 -0
  117. package/cli/drivers/index.ts +20 -0
  118. package/cli/drivers/playwright-provisioning.ts +184 -0
  119. package/cli/drivers/playwright-sim-host.ts +537 -0
  120. package/cli/drivers/playwright.ts +209 -0
  121. package/cli/drivers/registry.ts +65 -0
  122. package/cli/drivers/types.ts +102 -0
  123. package/cli/flow-export.ts +55 -0
  124. package/cli/flow-file.ts +142 -0
  125. package/cli/flow-live-status.ts +126 -0
  126. package/cli/flow-session.ts +140 -0
  127. package/cli/help-core.ts +143 -0
  128. package/cli/help.ts +44 -0
  129. package/cli/hidden-runtime-alias.ts +19 -0
  130. package/cli/hints.ts +214 -0
  131. package/cli/inspect-notice-state.ts +114 -0
  132. package/cli/internal-child.ts +176 -0
  133. package/cli/maestro-js.ts +323 -0
  134. package/cli/main.ts +704 -0
  135. package/cli/open-url.ts +8 -0
  136. package/cli/outbound-endpoints.ts +830 -0
  137. package/cli/parent-pid.ts +204 -0
  138. package/cli/parse-args.ts +189 -0
  139. package/cli/privacy.ts +53 -0
  140. package/cli/prompt.ts +56 -0
  141. package/cli/recording-access.ts +108 -0
  142. package/cli/registry.ts +2 -0
  143. package/cli/resolve-assets.ts +63 -0
  144. package/cli/rnx-in-process.ts +98 -0
  145. package/cli/run-registry.ts +226 -0
  146. package/cli/run-rnx-core.ts +148 -0
  147. package/cli/run-rnx.ts +137 -0
  148. package/cli/runtime-notes.ts +66 -0
  149. package/cli/runtime-summary.ts +25 -0
  150. package/cli/secure-file.ts +31 -0
  151. package/cli/self-invocation.ts +58 -0
  152. package/cli/send-to-box.ts +109 -0
  153. package/cli/setup-repository.ts +191 -0
  154. package/cli/shell-init.ts +98 -0
  155. package/cli/standalone.ts +4 -0
  156. package/cli/telemetry.ts +84 -0
  157. package/cli/ui.ts +68 -0
  158. package/cli/ws-bridge.ts +1020 -0
  159. package/detox/attempt-events.cjs +23 -0
  160. package/detox/colors.ts +54 -0
  161. package/detox/config-loader.ts +135 -0
  162. package/detox/element-types.ts +48 -0
  163. package/detox/expectations.ts +534 -0
  164. package/detox/gestures.ts +501 -0
  165. package/detox/index.ts +2694 -0
  166. package/detox/jest-preset.cjs +29 -0
  167. package/detox/jest-setup-after-env.cjs +22 -0
  168. package/detox/matchers.ts +30 -0
  169. package/detox/motion-change.cjs +109 -0
  170. package/detox/motion-change.d.cts +35 -0
  171. package/detox/navigation-lifecycle.ts +290 -0
  172. package/detox/navigation.ts +43 -0
  173. package/detox/proof-frame.cjs +114 -0
  174. package/detox/record-block-execution.cjs +78 -0
  175. package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
  176. package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
  177. package/detox/screenshots/color-test-rest-norngh.png +0 -0
  178. package/detox/screenshots/theme-blue-toggle.png +0 -0
  179. package/detox/screenshots/theme-blue.png +0 -0
  180. package/detox/screenshots/theme-red-toggle.png +0 -0
  181. package/detox/screenshots/theme-red.png +0 -0
  182. package/dist-lib/agent-daemon-client.cjs +502 -0
  183. package/dist-lib/agent-events.cjs +48 -0
  184. package/dist-lib/agent-identity.cjs +53 -0
  185. package/dist-lib/agent-sessions.cjs +759 -0
  186. package/dist-lib/attached-projects.cjs +526 -0
  187. package/dist-lib/auth/shared-session.cjs +208 -0
  188. package/dist-lib/backend-origin.cjs +88 -0
  189. package/dist-lib/beta.cjs +41 -0
  190. package/dist-lib/beta.mjs +13 -0
  191. package/dist-lib/bridge-constants.cjs +161 -0
  192. package/dist-lib/bridge-contract-input.cjs +451 -0
  193. package/dist-lib/bridge-contract-input.mjs +414 -0
  194. package/dist-lib/bridge-contract.cjs +130 -0
  195. package/dist-lib/bridge-contract.mjs +94 -0
  196. package/dist-lib/capture-contract.cjs +220 -0
  197. package/dist-lib/capture-contract.mjs +190 -0
  198. package/dist-lib/cli-constants.cjs +32 -0
  199. package/dist-lib/cloud-contract.cjs +194 -0
  200. package/dist-lib/cloud-contract.mjs +145 -0
  201. package/dist-lib/cloud.cjs +670 -0
  202. package/dist-lib/cloud.mjs +639 -0
  203. package/dist-lib/config.cjs +96 -0
  204. package/dist-lib/detox/index.cjs +3789 -0
  205. package/dist-lib/detox/jest-preset.cjs +29 -0
  206. package/dist-lib/dev-bundle-resolution.cjs +290 -0
  207. package/dist-lib/home-paths.cjs +638 -0
  208. package/dist-lib/host/bridge-host.cjs +10903 -0
  209. package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
  210. package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
  211. package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
  212. package/dist-lib/host/replacement-module-handler.cjs +469 -0
  213. package/dist-lib/host/websocket-proxy.cjs +298 -0
  214. package/dist-lib/index.cjs +4268 -0
  215. package/dist-lib/jump-to-source-babel.cjs +93 -0
  216. package/dist-lib/jump-to-source-native.cjs +112 -0
  217. package/dist-lib/menu.cjs +646 -0
  218. package/dist-lib/menu.mjs +604 -0
  219. package/dist-lib/metro-fingerprint-registry.cjs +186 -0
  220. package/dist-lib/metro-fingerprint-registry.mjs +156 -0
  221. package/dist-lib/metro-production-bundle.cjs +329 -0
  222. package/dist-lib/metro-production-bundle.mjs +295 -0
  223. package/dist-lib/metro.cjs +904 -0
  224. package/dist-lib/profiles.cjs +246 -0
  225. package/dist-lib/public-brand.cjs +39 -0
  226. package/dist-lib/react-native-host-modules.cjs +51 -0
  227. package/dist-lib/react-native-host-modules.mjs +25 -0
  228. package/dist-lib/render-mode.cjs +54 -0
  229. package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
  230. package/dist-lib/sdk.cjs +2433 -0
  231. package/dist-lib/sdk.mjs +2336 -0
  232. package/dist-lib/skills.cjs +39132 -0
  233. package/dist-lib/swift-submit.cjs +92 -0
  234. package/dist-lib/swift-submit.mjs +65 -0
  235. package/dist-lib/swift.cjs +1646 -0
  236. package/dist-lib/vite.cjs +1591 -0
  237. package/package.json +290 -0
  238. package/scripts/dev-server-scanner.ts +1291 -0
  239. package/scripts/optional-demo-registry.ts +113 -0
  240. package/skills/contrast/SKILL.md +165 -0
  241. package/skills/rnx-debug/SKILL.md +433 -0
  242. package/skills/rnx-perf/SKILL.md +399 -0
  243. package/skills/rnx-setup/SKILL.md +172 -0
  244. package/skills/rnx-test/SKILL.md +321 -0
  245. package/skills/rnx-visual/SKILL.md +126 -0
  246. package/src/agent-daemon-client.ts +410 -0
  247. package/src/agent-events.ts +71 -0
  248. package/src/agent-identity.ts +23 -0
  249. package/src/agent-prompt.ts +71 -0
  250. package/src/agent-sessions.ts +580 -0
  251. package/src/app-url.ts +39 -0
  252. package/src/attached-projects.ts +539 -0
  253. package/src/auth/shared-session.ts +235 -0
  254. package/src/backend-origin.ts +70 -0
  255. package/src/beta.ts +19 -0
  256. package/src/bridge-constants.ts +175 -0
  257. package/src/bridge-contract-input.ts +502 -0
  258. package/src/bridge-contract.ts +558 -0
  259. package/src/browser-cache.ts +16 -0
  260. package/src/capture-contract.ts +587 -0
  261. package/src/cli-constants.ts +1 -0
  262. package/src/cli-version.ts +40 -0
  263. package/src/cloud-contract.ts +274 -0
  264. package/src/cloud.ts +762 -0
  265. package/src/codex-client.ts +234 -0
  266. package/src/config.ts +132 -0
  267. package/src/connect.ts +101 -0
  268. package/src/dev-bundle-resolution.ts +346 -0
  269. package/src/dev-server-open.ts +198 -0
  270. package/src/disk-cleanup.ts +540 -0
  271. package/src/flow-timeout-scale.ts +15 -0
  272. package/src/home-paths.ts +806 -0
  273. package/src/host/agent-host.ts +666 -0
  274. package/src/host/bridge-host.ts +2788 -0
  275. package/src/host/fetch-proxy-handler.ts +449 -0
  276. package/src/host/fetch-proxy-overrides.ts +51 -0
  277. package/src/host/open-url.ts +89 -0
  278. package/src/host/plane-host.ts +203 -0
  279. package/src/host/replacement-module-handler.ts +158 -0
  280. package/src/host/websocket-proxy.ts +315 -0
  281. package/src/index.ts +71 -0
  282. package/src/jump-to-source-babel.ts +135 -0
  283. package/src/jump-to-source-native.ts +102 -0
  284. package/src/menu.ts +777 -0
  285. package/src/metro-fingerprint-registry.ts +302 -0
  286. package/src/metro-plugin.ts +341 -0
  287. package/src/metro-production-bundle.ts +471 -0
  288. package/src/native-dev-bundle-url.ts +118 -0
  289. package/src/native-seam-manifest.ts +341 -0
  290. package/src/playwright-host-log.ts +16 -0
  291. package/src/plist.ts +27 -0
  292. package/src/poll-until.ts +123 -0
  293. package/src/profiles.ts +179 -0
  294. package/src/public-brand.ts +9 -0
  295. package/src/react-native-host-modules.ts +26 -0
  296. package/src/render-mode.ts +27 -0
  297. package/src/rolldown-plugin-swift.ts +240 -0
  298. package/src/runtime-assets.ts +233 -0
  299. package/src/runtime-delivery.ts +54 -0
  300. package/src/screenshots/compose.ts +422 -0
  301. package/src/screenshots/frame-compose.ts +514 -0
  302. package/src/screenshots/orchestrate.ts +256 -0
  303. package/src/screenshots/org-deck.ts +91 -0
  304. package/src/screenshots/registry.ts +58 -0
  305. package/src/screenshots/schema.ts +364 -0
  306. package/src/sdk.ts +15 -0
  307. package/src/settings-bundle.ts +418 -0
  308. package/src/shell-bridge-identity.ts +15 -0
  309. package/src/sim-client.ts +697 -0
  310. package/src/skills/builtin/a11y-review.ts +132 -0
  311. package/src/skills/builtin/compat-check.ts +71 -0
  312. package/src/skills/builtin/maestro-test.ts +121 -0
  313. package/src/skills/builtin/perf-profile.ts +90 -0
  314. package/src/skills/builtin/screenshot-all.ts +52 -0
  315. package/src/skills/builtin/visual-diff.ts +100 -0
  316. package/src/skills/registry.ts +107 -0
  317. package/src/skills/types.ts +41 -0
  318. package/src/swift-submit.ts +185 -0
  319. package/src/swift.ts +7 -0
  320. package/src/team-machine-prompt.ts +73 -0
  321. package/src/vite-plugin-one.ts +264 -0
  322. package/src/vite-plugin-swift.ts +620 -0
  323. package/src/vite-plugin.ts +1946 -0
  324. package/src/worklets-babel.ts +250 -0
@@ -0,0 +1,364 @@
1
+ import { readFileSync } from 'fs'
2
+ import path from 'path'
3
+ import { devices, type DeviceModel } from 'sootsim-engine/settings'
4
+ import yaml from 'yaml'
5
+ import {
6
+ cloneBackgroundSpec,
7
+ DEFAULT_FRAME_SHADOW,
8
+ DEFAULT_FRAME_STYLE,
9
+ resolveBackgroundPreset,
10
+ resolveCanvasPreset,
11
+ toAssetKey,
12
+ type BackgroundPresetName,
13
+ type BackgroundSpec,
14
+ type CanvasPreset,
15
+ type FrameComposeSpec,
16
+ type PosePresetName,
17
+ type TextPresetName,
18
+ } from './registry'
19
+
20
+ export type CaptureMode = 'raw' | 'framed' | 'raw+framed'
21
+ export type CapturePathMode = 'auto' | 'plan' | 'flow'
22
+
23
+ export interface NormalizedScreenshotSlide {
24
+ id: string
25
+ assetKey: string
26
+ screenshot: string
27
+ headline: string
28
+ subheadline: string
29
+ eyebrow: string
30
+ pose?: PosePresetName
31
+ scale?: number
32
+ offsetY?: number
33
+ background?: BackgroundSpec
34
+ }
35
+
36
+ export interface NormalizedCapturePlan {
37
+ flowPath: string | null
38
+ fromDir: string | null
39
+ outDir: string
40
+ rawDir: string
41
+ framedDir: string
42
+ mode: CaptureMode
43
+ pathMode: CapturePathMode
44
+ simId: string | null
45
+ openInNewSim: boolean
46
+ }
47
+
48
+ export interface NormalizedComposePlan {
49
+ outDir: string
50
+ locale: string
51
+ canvases: CanvasPreset[]
52
+ frame: FrameComposeSpec
53
+ background: BackgroundSpec
54
+ text: {
55
+ preset: TextPresetName
56
+ color: string
57
+ subColor: string
58
+ eyebrowColor: string
59
+ }
60
+ slides: NormalizedScreenshotSlide[]
61
+ }
62
+
63
+ export interface NormalizedScreenshotsPlan {
64
+ planPath: string
65
+ planDir: string
66
+ appTarget: string | null
67
+ deviceModel: DeviceModel | null
68
+ capture: NormalizedCapturePlan
69
+ compose: NormalizedComposePlan
70
+ }
71
+
72
+ function isRecord(value: unknown): value is Record<string, unknown> {
73
+ return !!value && typeof value === 'object' && !Array.isArray(value)
74
+ }
75
+
76
+ function expectRecord(value: unknown, label: string): Record<string, unknown> {
77
+ if (!isRecord(value)) throw new Error(`${label} must be an object`)
78
+ return value
79
+ }
80
+
81
+ function readString(value: unknown, fallback = ''): string {
82
+ return typeof value === 'string' ? value : fallback
83
+ }
84
+
85
+ function readOptionalString(value: unknown): string | null {
86
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null
87
+ }
88
+
89
+ function readBoolean(value: unknown, fallback: boolean): boolean {
90
+ return typeof value === 'boolean' ? value : fallback
91
+ }
92
+
93
+ function readNumber(value: unknown, fallback: number): number {
94
+ return typeof value === 'number' && Number.isFinite(value) ? value : fallback
95
+ }
96
+
97
+ function readDeviceModel(
98
+ value: unknown,
99
+ fallback: DeviceModel | null,
100
+ ): DeviceModel | null {
101
+ if (typeof value !== 'string' || value.trim().length === 0) return fallback
102
+ return Object.prototype.hasOwnProperty.call(devices, value)
103
+ ? (value as DeviceModel)
104
+ : null
105
+ }
106
+
107
+ function normalizeBackground(value: unknown, fallback: BackgroundSpec): BackgroundSpec {
108
+ if (typeof value === 'string') {
109
+ const preset = resolveBackgroundPreset(value)
110
+ if (!preset) throw new Error(`unknown background preset: ${value}`)
111
+ return preset
112
+ }
113
+ if (!isRecord(value)) return cloneBackgroundSpec(fallback)
114
+ const type =
115
+ value.type === 'solid' || value.type === 'gradient' ? value.type : fallback.type
116
+ if (type === 'solid') {
117
+ return {
118
+ type,
119
+ color: readString(value.color, fallback.color ?? '#000000'),
120
+ glow: readOptionalString(value.glow) ?? fallback.glow,
121
+ }
122
+ }
123
+ const stops = Array.isArray(value.stops)
124
+ ? value.stops
125
+ .map((stop) => {
126
+ if (!isRecord(stop)) return null
127
+ const offset = readNumber(stop.offset, Number.NaN)
128
+ const color = readOptionalString(stop.color)
129
+ if (!Number.isFinite(offset) || !color) return null
130
+ return { offset, color }
131
+ })
132
+ .filter((stop): stop is { offset: number; color: string } => !!stop)
133
+ : (fallback.stops?.map((stop) => ({ ...stop })) ?? [])
134
+ return {
135
+ type,
136
+ direction: readNumber(value.direction, fallback.direction ?? 180),
137
+ glow: readOptionalString(value.glow) ?? fallback.glow,
138
+ stops:
139
+ stops.length > 0 ? stops : (fallback.stops?.map((stop) => ({ ...stop })) ?? []),
140
+ }
141
+ }
142
+
143
+ function normalizeCanvasList(value: unknown): CanvasPreset[] {
144
+ const names = Array.isArray(value) ? value : ['iphone-6-9']
145
+ const presets = names.map((entry) => {
146
+ if (typeof entry !== 'string')
147
+ throw new Error('compose.canvases entries must be strings')
148
+ const preset = resolveCanvasPreset(entry)
149
+ if (!preset) throw new Error(`unknown canvas preset: ${entry}`)
150
+ return preset
151
+ })
152
+ if (presets.length === 0)
153
+ throw new Error('compose.canvases must include at least one preset')
154
+ return presets
155
+ }
156
+
157
+ function normalizeTextPreset(value: unknown): TextPresetName {
158
+ switch (value) {
159
+ case 'editorial-left':
160
+ case 'minimal-bottom':
161
+ case 'none':
162
+ case 'bold-top':
163
+ return value
164
+ default:
165
+ return 'bold-top'
166
+ }
167
+ }
168
+
169
+ function normalizeCapturePathMode(value: unknown): CapturePathMode {
170
+ switch (value) {
171
+ case 'plan':
172
+ case 'flow':
173
+ case 'auto':
174
+ return value
175
+ default:
176
+ return 'auto'
177
+ }
178
+ }
179
+
180
+ function normalizePose(value: unknown): PosePresetName | undefined {
181
+ switch (value) {
182
+ case 'straight':
183
+ case 'tilted-left':
184
+ case 'tilted-right':
185
+ case 'cut-bottom':
186
+ case 'cut-top':
187
+ return value
188
+ default:
189
+ return undefined
190
+ }
191
+ }
192
+
193
+ function resolvePlanPath(planDir: string, value: string): string {
194
+ return path.isAbsolute(value) ? value : path.resolve(planDir, value)
195
+ }
196
+
197
+ function normalizeSlides(
198
+ value: unknown,
199
+ fallbackBackground: BackgroundSpec,
200
+ ): NormalizedScreenshotSlide[] {
201
+ if (!Array.isArray(value) || value.length === 0) {
202
+ throw new Error('compose.slides must be a non-empty array')
203
+ }
204
+ return value.map((entry, index) => {
205
+ const slide = expectRecord(entry, `compose.slides[${index}]`)
206
+ const screenshot = readOptionalString(slide.screenshot)
207
+ if (!screenshot) {
208
+ throw new Error(`compose.slides[${index}].screenshot is required`)
209
+ }
210
+ const explicitId = readOptionalString(slide.id)
211
+ const assetKey = toAssetKey(explicitId || screenshot)
212
+ return {
213
+ id: explicitId || assetKey,
214
+ assetKey,
215
+ screenshot,
216
+ headline: readString(slide.headline),
217
+ subheadline: readString(slide.subheadline),
218
+ eyebrow: readString(slide.eyebrow),
219
+ pose: normalizePose(slide.pose),
220
+ scale:
221
+ typeof slide.scale === 'number' && Number.isFinite(slide.scale)
222
+ ? slide.scale
223
+ : undefined,
224
+ offsetY:
225
+ typeof slide.offsetY === 'number' && Number.isFinite(slide.offsetY)
226
+ ? slide.offsetY
227
+ : undefined,
228
+ background:
229
+ slide.theme || slide.background
230
+ ? normalizeBackground(slide.theme ?? slide.background, fallbackBackground)
231
+ : undefined,
232
+ }
233
+ })
234
+ }
235
+
236
+ export function loadScreenshotsPlan(planPath: string): NormalizedScreenshotsPlan {
237
+ const resolvedPlanPath = path.resolve(planPath)
238
+ const planDir = path.dirname(resolvedPlanPath)
239
+ const raw = yaml.parse(readFileSync(resolvedPlanPath, 'utf8'))
240
+ const root = expectRecord(raw, 'screenshots plan')
241
+ const capture = expectRecord(root.capture ?? {}, 'capture')
242
+ const compose = expectRecord(root.compose ?? {}, 'compose')
243
+
244
+ const appTarget =
245
+ typeof root.app === 'number' ? String(root.app) : readOptionalString(root.app)
246
+ const deviceModel = readDeviceModel(root.device, null)
247
+ const captureOutDir = resolvePlanPath(
248
+ planDir,
249
+ readString(capture.out, path.join('.rnx', 'screenshots', 'capture')),
250
+ )
251
+ const captureFrom = readOptionalString(capture.from)
252
+ const flowPath = readOptionalString(capture.flow)
253
+ if (!captureFrom && !flowPath) {
254
+ throw new Error('capture.flow or capture.from is required')
255
+ }
256
+ const captureMode =
257
+ capture.mode === 'raw' || capture.mode === 'framed' || capture.mode === 'raw+framed'
258
+ ? capture.mode
259
+ : ('raw+framed' as CaptureMode)
260
+ const capturePathMode = normalizeCapturePathMode(capture.pathMode)
261
+ const defaultBackground = normalizeBackground(
262
+ compose.background ?? ('cyan' as BackgroundPresetName),
263
+ resolveBackgroundPreset('cyan')!,
264
+ )
265
+ const frameConfig: FrameComposeSpec = {
266
+ show: readBoolean(
267
+ compose.frame && isRecord(compose.frame) ? compose.frame.show : undefined,
268
+ true,
269
+ ),
270
+ style:
271
+ readDeviceModel(
272
+ compose.frame && isRecord(compose.frame) ? compose.frame.style : null,
273
+ null,
274
+ ) ||
275
+ deviceModel ||
276
+ DEFAULT_FRAME_STYLE,
277
+ pose:
278
+ normalizePose(
279
+ compose.frame && isRecord(compose.frame) ? compose.frame.pose : undefined,
280
+ ) || 'straight',
281
+ scale: readNumber(
282
+ compose.frame && isRecord(compose.frame) ? compose.frame.scale : undefined,
283
+ 1,
284
+ ),
285
+ offsetY: readNumber(
286
+ compose.frame && isRecord(compose.frame) ? compose.frame.offsetY : undefined,
287
+ 0,
288
+ ),
289
+ shadow: {
290
+ color: readString(
291
+ compose.frame && isRecord(compose.frame) && isRecord(compose.frame.shadow)
292
+ ? compose.frame.shadow.color
293
+ : undefined,
294
+ DEFAULT_FRAME_SHADOW.color,
295
+ ),
296
+ blur: readNumber(
297
+ compose.frame && isRecord(compose.frame) && isRecord(compose.frame.shadow)
298
+ ? compose.frame.shadow.blur
299
+ : undefined,
300
+ DEFAULT_FRAME_SHADOW.blur,
301
+ ),
302
+ spread: readNumber(
303
+ compose.frame && isRecord(compose.frame) && isRecord(compose.frame.shadow)
304
+ ? compose.frame.shadow.spread
305
+ : undefined,
306
+ DEFAULT_FRAME_SHADOW.spread,
307
+ ),
308
+ opacity: readNumber(
309
+ compose.frame && isRecord(compose.frame) && isRecord(compose.frame.shadow)
310
+ ? compose.frame.shadow.opacity
311
+ : undefined,
312
+ DEFAULT_FRAME_SHADOW.opacity,
313
+ ),
314
+ },
315
+ }
316
+
317
+ return {
318
+ planPath: resolvedPlanPath,
319
+ planDir,
320
+ appTarget,
321
+ deviceModel,
322
+ capture: {
323
+ flowPath: flowPath ? resolvePlanPath(planDir, flowPath) : null,
324
+ fromDir: captureFrom ? resolvePlanPath(planDir, captureFrom) : null,
325
+ outDir: captureOutDir,
326
+ rawDir: captureFrom
327
+ ? resolvePlanPath(planDir, captureFrom)
328
+ : path.join(captureOutDir, 'raw'),
329
+ framedDir: path.join(captureOutDir, 'framed'),
330
+ mode: captureMode,
331
+ pathMode: capturePathMode,
332
+ simId: readOptionalString(capture.sim),
333
+ openInNewSim: readBoolean(capture.new, false),
334
+ },
335
+ compose: {
336
+ outDir: resolvePlanPath(
337
+ planDir,
338
+ readString(compose.out, path.join('.rnx', 'screenshots', 'exports')),
339
+ ),
340
+ locale: readString(compose.locale, 'en'),
341
+ canvases: normalizeCanvasList(compose.canvases),
342
+ frame: frameConfig,
343
+ background: defaultBackground,
344
+ text: {
345
+ preset: normalizeTextPreset(
346
+ compose.text && isRecord(compose.text) ? compose.text.preset : undefined,
347
+ ),
348
+ color: readString(
349
+ compose.text && isRecord(compose.text) ? compose.text.color : undefined,
350
+ '#ffffff',
351
+ ),
352
+ subColor: readString(
353
+ compose.text && isRecord(compose.text) ? compose.text.subColor : undefined,
354
+ 'rgba(232,240,247,0.86)',
355
+ ),
356
+ eyebrowColor: readString(
357
+ compose.text && isRecord(compose.text) ? compose.text.eyebrowColor : undefined,
358
+ 'rgba(229,242,255,0.72)',
359
+ ),
360
+ },
361
+ slides: normalizeSlides(compose.slides, defaultBackground),
362
+ },
363
+ }
364
+ }
package/src/sdk.ts ADDED
@@ -0,0 +1,15 @@
1
+ // rnxsim/sdk — the scriptable sim-driving surface.
2
+ //
3
+ // exports the SimClient class plus the transport-agnostic inspect verbs it is
4
+ // built from. this entry MUST stay browser-safe (Contrast's in-browser agent
5
+ // imports it against an in-process preview bridge), so the node-only ws
6
+ // `connect()` lives on the ROOT `rnxsim` entry, not here.
7
+
8
+ export * from './sim-client'
9
+ export * from '../cli/commands/inspect/core'
10
+ export * from '../cli/commands/inspect/actions'
11
+ export { waitForSootsimIdle } from '../cli/commands/inspect/settling'
12
+ export type {
13
+ WaitForSootsimIdleOptions,
14
+ WaitForSootsimIdleResult,
15
+ } from '../cli/commands/inspect/settling'