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,41 @@
1
+ // skill type definitions — self-contained agent capabilities
2
+
3
+ export type SkillType = 'testing' | 'screenshot' | 'review' | 'performance' | 'custom'
4
+
5
+ export interface SkillTool {
6
+ name: string
7
+ description: string
8
+ parameters: Record<string, { type: string; description: string; required?: boolean }>
9
+ execute: (params: Record<string, any>, context: SkillContext) => Promise<SkillResult>
10
+ }
11
+
12
+ export interface SkillContext {
13
+ url: string // sootsim URL
14
+ projectDir: string // project root
15
+ outputDir: string // where to write artifacts
16
+ verbose: boolean
17
+ }
18
+
19
+ export interface SkillResult {
20
+ success: boolean
21
+ message: string
22
+ artifacts?: SkillArtifact[]
23
+ data?: Record<string, any>
24
+ }
25
+
26
+ export interface SkillArtifact {
27
+ type: 'screenshot' | 'video' | 'report' | 'flow' | 'json'
28
+ name: string
29
+ path: string
30
+ }
31
+
32
+ export interface RNXSkill {
33
+ name: string
34
+ description: string
35
+ type: SkillType
36
+ version: string
37
+ triggers: string[] // natural language patterns that activate this skill
38
+ tools: SkillTool[]
39
+ setup?: (context: SkillContext) => Promise<void>
40
+ teardown?: (context: SkillContext) => Promise<void>
41
+ }
@@ -0,0 +1,185 @@
1
+ /**
2
+ * swift-compile's caller half: ask the compile host for this project's wasm
3
+ * artifact, and poll until it is published.
4
+ *
5
+ * This is the `.swift` transform's one request path, shared by every host
6
+ * that renders a project's swift sources: the in-IDE bundler worker (posts
7
+ * its own origin's `/api/swift-compile`), the node bundle builder used by
8
+ * the test-drive CLI and the deploy publisher (posts an absolute endpoint),
9
+ * and the One/rolldown `.swift` transform (same, with a `ccdn_` credential).
10
+ * A caller never compiles in-process: the container is the one compiler, and
11
+ * no bundler is that instance.
12
+ *
13
+ * It lives here (rather than in the app's `src/bundler/`) because the One
14
+ * transform ships in this package and cannot import app code; the app's own
15
+ * callers import this subpath back. The route path and the outcome shape are
16
+ * the wire coupling to `src/compile/swiftCompileContract.ts`, which owns the
17
+ * server-side caps, parsers, and refusals and imports these back.
18
+ *
19
+ * Browser-safe: node-only submitters live beside their call sites.
20
+ */
21
+
22
+ export const SWIFT_COMPILE_PATH = '/api/swift-compile'
23
+
24
+ export interface SwiftImageUpload {
25
+ /** the raster file picked for the asset (has the extension). */
26
+ file: string
27
+ /** the raster bytes, base64: carried once so the service can publish them. */
28
+ data: string
29
+ }
30
+
31
+ export type SwiftCompileOutcome =
32
+ /**
33
+ * the artifact is published; the bundler mounts it by url and hash.
34
+ *
35
+ * `artifactUrl` is root-relative (`/compile/asset/<sha256>`), because the
36
+ * host that compiles has no browser origin in front of it: the local node
37
+ * dev server and the cf-build container would each have to guess one. The
38
+ * caller that renders the module resolves it against its own origin, which
39
+ * is the origin the artifact route is served from in dev and in prod alike.
40
+ */
41
+ | {
42
+ status: 'published'
43
+ artifactUrl: string
44
+ hash: string
45
+ /**
46
+ * the published photo rasters, bundle asset name to absolute url.
47
+ * root-relative like the artifact url; the caller resolves it against
48
+ * its own origin, and the entry embeds it as the image table. absent
49
+ * when the request packs no images.
50
+ */
51
+ imageUrls?: Record<string, string>
52
+ }
53
+ /**
54
+ * the build is running; poll the same source set again. One build is tens of
55
+ * seconds and a service-binding request is cancelled at about four, so the
56
+ * container answers this before the connection dies and the caller polls.
57
+ */
58
+ | { status: 'compiling'; hash: string }
59
+ /** refused before any work: no entry, too many files, over a cap, over a rate limit. */
60
+ | { status: 'refused'; detail: string }
61
+ /** the compiler ran and failed; detail carries its diagnostic verbatim. */
62
+ | { status: 'failed'; detail: string }
63
+
64
+ const POLL_INTERVAL_MS = 1500
65
+
66
+ export interface SwiftCompileContext {
67
+ /**
68
+ * the compile credential: the signed preview token `BundlerSessionRuntime`
69
+ * mints for a live project session, or a `ccdn_` API key. `compileCredential.server.ts`
70
+ * is the one verifier. absent means this build has no credential and a
71
+ * project with `.swift` sources cannot be compiled.
72
+ */
73
+ assetReadToken?: string
74
+ /**
75
+ * absolute origin of the app serving `/api/swift-compile`. The browser
76
+ * worker omits it and posts its own origin; a node caller that is not that
77
+ * app must pass one.
78
+ */
79
+ endpoint?: string
80
+ }
81
+
82
+ export type SwiftCompileSubmit = (work: {
83
+ files: Record<string, string>
84
+ /** the bundle pack; absent means the project packs none. */
85
+ resources?: Record<string, string>
86
+ /** the photo rasters to publish; absent means the project packs none. */
87
+ images?: Record<string, SwiftImageUpload>
88
+ entry: string
89
+ }) => Promise<SwiftCompileOutcome>
90
+
91
+ /** the HTTP submitter, shared by the browser worker and the node build. */
92
+ export function httpSwiftCompileSubmit(
93
+ context: SwiftCompileContext,
94
+ ): SwiftCompileSubmit | undefined {
95
+ const { assetReadToken, endpoint } = context
96
+ if (!assetReadToken) return undefined
97
+ const url = endpoint
98
+ ? `${endpoint.replace(/\/+$/, '')}${SWIFT_COMPILE_PATH}`
99
+ : SWIFT_COMPILE_PATH
100
+
101
+ return async (work) => {
102
+ let response: Response
103
+ try {
104
+ response = await fetch(url, {
105
+ method: 'POST',
106
+ headers: { 'content-type': 'application/json' },
107
+ body: JSON.stringify({ ...work, token: assetReadToken }),
108
+ })
109
+ } catch (error) {
110
+ throw new Error(
111
+ `contrast-bundler: fetch failed for ${url} while compiling ${work.entry}: ${error instanceof Error ? error.message : String(error)}`,
112
+ { cause: error },
113
+ )
114
+ }
115
+ if (!response.ok) {
116
+ const detail = (await response.text()).trim()
117
+ throw new Error(
118
+ `contrast-bundler: the swift compile for ${work.entry} answered ${response.status}${detail ? `: ${detail}` : ''}`,
119
+ )
120
+ }
121
+ return (await response.json()) as SwiftCompileOutcome
122
+ }
123
+ }
124
+
125
+ export interface SwiftModuleAddress {
126
+ /** absolute url the tenant fetches the wasm from. */
127
+ url: string
128
+ hash: string
129
+ /** bundle asset name to absolute photo url, when the pack publishes any. */
130
+ imageUrls?: Record<string, string>
131
+ }
132
+
133
+ /** the service answers root-relative; the caller that knows the origin resolves. */
134
+ function resolveImageUrls(
135
+ urls: Record<string, string>,
136
+ origin: string,
137
+ ): Record<string, string> {
138
+ const resolved: Record<string, string> = {}
139
+ for (const [name, url] of Object.entries(urls)) {
140
+ resolved[name] = new URL(url, origin).href
141
+ }
142
+ return resolved
143
+ }
144
+
145
+ /**
146
+ * one project's swift sources as a published artifact address.
147
+ *
148
+ * `origin` is the origin the artifact route answers on — the app's own origin
149
+ * for the browser worker, the caller's compile origin for a node build. The
150
+ * contract's url is root-relative because the compile host has no browser
151
+ * origin in front of it, so the resolution happens here, at the one caller
152
+ * that knows both.
153
+ */
154
+ export async function compileSwiftProject(
155
+ submit: SwiftCompileSubmit,
156
+ work: {
157
+ files: Record<string, string>
158
+ resources?: Record<string, string>
159
+ images?: Record<string, SwiftImageUpload>
160
+ entry: string
161
+ },
162
+ origin: string,
163
+ ): Promise<SwiftModuleAddress> {
164
+ while (true) {
165
+ const outcome = await submit(work)
166
+ switch (outcome.status) {
167
+ case 'published':
168
+ return {
169
+ url: new URL(outcome.artifactUrl, origin).href,
170
+ hash: outcome.hash,
171
+ ...(outcome.imageUrls === undefined
172
+ ? {}
173
+ : { imageUrls: resolveImageUrls(outcome.imageUrls, origin) }),
174
+ }
175
+ case 'compiling':
176
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
177
+ continue
178
+ case 'refused':
179
+ case 'failed':
180
+ throw new Error(
181
+ `contrast-bundler: the swift sources for ${work.entry} cannot be compiled: ${outcome.detail}`,
182
+ )
183
+ }
184
+ }
185
+ }
package/src/swift.ts ADDED
@@ -0,0 +1,7 @@
1
+ // the runtime the `.swift` vite transform emits its module against. the
2
+ // implementation lives beside the toolchain it drives, in sootsim-swift.
3
+ export {
4
+ createSwiftEntry,
5
+ type SwiftEntryOptions,
6
+ type SwiftModuleOptions,
7
+ } from '../../sootsim-swift/src/mount.tsx'
@@ -0,0 +1,73 @@
1
+ import { spawn } from 'node:child_process'
2
+ import {
3
+ isValidTeamMachineSessionId,
4
+ teamMachineSessionIdFromCliIdentity,
5
+ } from './agent-identity.ts'
6
+ import type { AgentPromptEnvelope } from './agent-prompt.ts'
7
+
8
+ export { teamMachineSessionIdFromCliIdentity } from './agent-identity.ts'
9
+
10
+ export function formatTeamMachinePromptText(prompt: AgentPromptEnvelope): string {
11
+ return typeof prompt.text === 'string' ? prompt.text.trim() : ''
12
+ }
13
+
14
+ function resolveTeamMachineCommand(explicit?: string): string {
15
+ const fromArg = explicit?.trim()
16
+ if (fromArg) return fromArg
17
+ return 'tm'
18
+ }
19
+
20
+ export async function sendPromptToTeamMachineSession(input: {
21
+ sessionId: string
22
+ prompt: AgentPromptEnvelope
23
+ command?: string
24
+ timeoutMs?: number
25
+ }): Promise<void> {
26
+ const sessionId = input.sessionId.trim()
27
+ if (!isValidTeamMachineSessionId(sessionId)) {
28
+ throw new Error(`invalid Team Machine session id: ${sessionId || '<empty>'}`)
29
+ }
30
+ const text = formatTeamMachinePromptText(input.prompt)
31
+ if (!text) {
32
+ throw new Error('prompt text is empty')
33
+ }
34
+
35
+ const command = resolveTeamMachineCommand(input.command)
36
+ const timeoutMs = input.timeoutMs ?? 15_000
37
+ await new Promise<void>((resolve, reject) => {
38
+ const child = spawn(command, ['send', sessionId, text], {
39
+ stdio: ['ignore', 'ignore', 'pipe'],
40
+ env: process.env,
41
+ })
42
+ let stderr = ''
43
+ const timer = setTimeout(() => {
44
+ try {
45
+ child.kill('SIGTERM')
46
+ } catch {}
47
+ reject(new Error(`tm send timed out after ${Math.round(timeoutMs / 1000)}s`))
48
+ }, timeoutMs)
49
+
50
+ child.stderr?.setEncoding('utf8')
51
+ child.stderr?.on('data', (chunk) => {
52
+ if (stderr.length < 4000) stderr += String(chunk)
53
+ })
54
+ child.on('error', (err) => {
55
+ clearTimeout(timer)
56
+ reject(err)
57
+ })
58
+ child.on('close', (code, signal) => {
59
+ clearTimeout(timer)
60
+ if (code === 0) {
61
+ resolve()
62
+ return
63
+ }
64
+ const detail = stderr.trim()
65
+ reject(
66
+ new Error(
67
+ detail ||
68
+ `tm send exited with ${signal ? `signal ${signal}` : `code ${code ?? 'unknown'}`}`,
69
+ ),
70
+ )
71
+ })
72
+ })
73
+ }
@@ -0,0 +1,264 @@
1
+ // sootsim plugin for One/Vite — serves the installed sootsim runtime at /__soot/
2
+ // from ~/.rnx/runtimes/<version>. version-owned localhost origins remain
3
+ // bound to that directory across an active-runtime update.
4
+ //
5
+ // usage in vite.config.ts:
6
+ // import { rnxPlugin } from 'rnxsim/vite'
7
+ // export default { plugins: [one(), rnxPlugin()] }
8
+
9
+ import fs from 'fs'
10
+ import { randomUUID } from 'node:crypto'
11
+ import path from 'path'
12
+ import { DEFAULT_SOOTSIM_BRIDGE_PORT } from './bridge-constants'
13
+ import {
14
+ launchRnxDesktop,
15
+ resolveRnxDesktopAppName,
16
+ resolveRnxDesktopLaunchTarget,
17
+ tagRnxBundleForPlugin,
18
+ type RnxDesktopOpenOption,
19
+ } from './dev-server-open'
20
+ import { isDaemonLockfileFresh, readDaemonLockfile } from './home-paths'
21
+ import { handleReplacementModuleRequest } from './host/replacement-module-handler'
22
+ import {
23
+ isRootRuntimeAssetPath,
24
+ resolveRuntimeFilePath,
25
+ resolveRuntimeRootForRequestHost,
26
+ serveRuntimeFile,
27
+ SOOTSIM_RUNTIME_MISSING_MESSAGE,
28
+ } from './runtime-assets'
29
+ import type { Plugin } from 'vite'
30
+
31
+ export interface RnxPluginOptions {
32
+ // custom bundle URL (default: auto-detect from One's metro)
33
+ bundleUrl?: string
34
+ // path prefix (default: '/__soot')
35
+ prefix?: string
36
+ // disable sootsim
37
+ enabled?: boolean
38
+ // launch the sootsim simulator loading this server's bundle once the dev
39
+ // server is listening. skipped when CI or RNX_NO_OPEN is set.
40
+ open?: RnxDesktopOpenOption
41
+ }
42
+
43
+ export function rnxPlugin(options: RnxPluginOptions = {}): Plugin {
44
+ const prefix = options.prefix || '/__soot'
45
+
46
+ return {
47
+ name: 'sootsim-one',
48
+
49
+ // use-latest-callback ships a CJS main (module.exports, no default) with
50
+ // an esm.mjs shim that re-imports it. react-native-bottom-tabs
51
+ // default-imports it from source served live, so vite hands the browser
52
+ // the raw CJS file and the import fails with 'does not provide an export
53
+ // named default' before anything mounts. forcing it through dep
54
+ // optimization lets esbuild's CJS interop answer the default import, and
55
+ // every bare import of it (including the nested copy's) resolves to the
56
+ // one pre-bundled instance.
57
+ config() {
58
+ return { optimizeDeps: { include: ['use-latest-callback'] } }
59
+ },
60
+
61
+ configureServer(server) {
62
+ if (options.enabled === false) return
63
+ const bundleUrl =
64
+ options.bundleUrl ||
65
+ '/node_modules/one/metro-entry.bundle?platform=ios&dev=true&minify=false'
66
+ const appName = resolveRnxDesktopAppName(options.open, server.config.root)
67
+ const replacementToken = randomUUID()
68
+ const configuredPort = server.config.server.port || 8081
69
+ const listeningPort = (): number => {
70
+ const address = server.httpServer?.address()
71
+ return address && typeof address === 'object' ? address.port : configuredPort
72
+ }
73
+ const bundleForPort = (port: number): string =>
74
+ tagRnxBundleForPlugin(
75
+ bundleUrl,
76
+ `http://localhost:${port}`,
77
+ replacementToken,
78
+ server.config.root,
79
+ appName,
80
+ )
81
+
82
+ // build the shell HTML, injecting the bundle URL (so main.tsx loads this
83
+ // app's bundle) AND window.__sootsimBridgePort. the bridge-port injection
84
+ // mirrors the dev-stack bridge-host: without it the engine's
85
+ // resolveBridgePort() falls back to a location-derived guess that mis-maps
86
+ // a non-Contrast app port (the mobile template's :4400 -> 9068) and the sim
87
+ // can't reach the bridge. resolved per-request from the daemon lockfile
88
+ // (the CLI's `open` writes/uses it before the shell loads) so the engine
89
+ // targets the SAME bridge the CLI does; default port otherwise.
90
+ const buildShellHtml = (runtimeRoot: string): string => {
91
+ const html = fs.readFileSync(path.join(runtimeRoot, 'index.html'), 'utf8')
92
+ const lock = readDaemonLockfile()
93
+ const bridgePort =
94
+ lock && isDaemonLockfileFresh(lock) && lock.bridgePort > 0
95
+ ? lock.bridgePort
96
+ : DEFAULT_SOOTSIM_BRIDGE_PORT
97
+ // inject the bridge port + a default bundle (only when the URL has none,
98
+ // so the CLI's resolved bundle wins), and PRESERVE the existing query.
99
+ // preserving the query is essential: `rnx open` stamps the open URL
100
+ // with `inspectOpen=<token>` and matches the registered sim by that
101
+ // token (waitForSimMatch). the old code forced `?bundle=` only and
102
+ // stripped inspectOpen, so the sim registered but never matched and
103
+ // `open` timed out after 60s.
104
+ const inject =
105
+ `<script>(function(){var u=new URL(location.href);` +
106
+ `if(!u.searchParams.has('bundle'))u.searchParams.set('bundle',${JSON.stringify(bundleForPort(listeningPort()))});` +
107
+ `window.__sootsimBridgePort=${bridgePort};` +
108
+ `history.replaceState(null,'','${prefix}/'+u.search)})()</script>`
109
+ return html.replace('</head>', inject + '</head>')
110
+ }
111
+
112
+ // mirror Set-Cookie into a readable header for sootsim's fetch wrapper
113
+ server.middlewares.use((req, res, next) => {
114
+ const origWriteHead = res.writeHead.bind(res)
115
+ res.writeHead = function (statusCode: number, ...args: unknown[]) {
116
+ const setCookie = res.getHeader('set-cookie')
117
+ if (setCookie) {
118
+ const value = Array.isArray(setCookie)
119
+ ? setCookie.join(', ')
120
+ : String(setCookie)
121
+ res.setHeader('x-sootsim-set-cookie', value)
122
+ res.setHeader('access-control-expose-headers', 'x-sootsim-set-cookie')
123
+ }
124
+ return (origWriteHead as (...args: unknown[]) => typeof res)(
125
+ statusCode,
126
+ ...args,
127
+ )
128
+ } as typeof res.writeHead
129
+ next()
130
+ })
131
+
132
+ // serve a minimal /__server-scan describing THIS vite dev server, so a
133
+ // sootsim shell loaded from <port>/__soot can resolve this app's native
134
+ // bundle. dev-bundle-resolution's resolvePortViaServerScan fetches
135
+ // `/__server-scan` RELATIVE to the shell origin; when the shell is loaded
136
+ // from this target origin, that hits here. without it the request SPA-
137
+ // falls-back to 404 and the bundle never resolves (rnx open hangs).
138
+ // we describe only this server (the shell drives THIS app) — no localhost-
139
+ // wide scan, so the published plugin pulls in no shell-only scanner
140
+ // internals. shape matches DiscoveredServer enough for the resolver.
141
+ server.middlewares.use((req, res, next) => {
142
+ if ((req.url || '').split('?')[0] !== '/__server-scan') return next()
143
+ const scanPort = listeningPort()
144
+ const pluginBundleUrl = bundleForPort(scanPort)
145
+ const absoluteBundleUrl = pluginBundleUrl.startsWith('http')
146
+ ? pluginBundleUrl
147
+ : `http://localhost:${scanPort}${pluginBundleUrl}`
148
+ res.setHeader('content-type', 'application/json')
149
+ res.end(
150
+ JSON.stringify([
151
+ {
152
+ port: scanPort,
153
+ framework: 'one',
154
+ bundleUrl: absoluteBundleUrl,
155
+ ...(appName ? { projectName: appName } : {}),
156
+ lastSeen: Date.now(),
157
+ },
158
+ ]),
159
+ )
160
+ })
161
+
162
+ server.middlewares.use((req, res, next) => {
163
+ void handleReplacementModuleRequest(req, res, {
164
+ projectRoot: server.config.root,
165
+ requestToken: replacementToken,
166
+ requireLoopbackOrigin: true,
167
+ }).then((handled) => {
168
+ if (!handled) next()
169
+ })
170
+ })
171
+
172
+ server.middlewares.use((req, res, next) => {
173
+ const url = req.url || ''
174
+ const pathname = url.split('?')[0]
175
+ const runtimeRoot = resolveRuntimeRootForRequestHost(req.headers.host)
176
+
177
+ if (!runtimeRoot) {
178
+ if (
179
+ pathname === prefix ||
180
+ pathname === prefix + '/' ||
181
+ pathname.startsWith(prefix + '/')
182
+ ) {
183
+ res.statusCode = 500
184
+ res.end(SOOTSIM_RUNTIME_MISSING_MESSAGE)
185
+ return
186
+ }
187
+ next()
188
+ return
189
+ }
190
+
191
+ // root-relative runtime assets emitted by the shell and engine vite
192
+ // builds. only intercept when the asset exists in the active runtime.
193
+ if (isRootRuntimeAssetPath(pathname)) {
194
+ const fullPath = resolveRuntimeFilePath(runtimeRoot, pathname)
195
+ if (fullPath) {
196
+ serveRuntimeFile(req, res, fullPath)
197
+ return
198
+ }
199
+ }
200
+
201
+ // serve the sootsim HTML shell — inject bundle URL + bridge port
202
+ if (pathname === prefix || pathname === prefix + '/') {
203
+ res.setHeader('content-type', 'text/html')
204
+ res.end(buildShellHtml(runtimeRoot))
205
+ return
206
+ }
207
+
208
+ // serve runtime files under /__soot/*.
209
+ if (pathname.startsWith(prefix + '/')) {
210
+ const fullPath = resolveRuntimeFilePath(
211
+ runtimeRoot,
212
+ pathname.slice(prefix.length),
213
+ )
214
+ if (fullPath) {
215
+ serveRuntimeFile(req, res, fullPath)
216
+ return
217
+ }
218
+
219
+ // extensionless in-shell routes should still load the shell.
220
+ const ext = path.extname(pathname)
221
+ if (!ext) {
222
+ res.setHeader('content-type', 'text/html')
223
+ res.end(buildShellHtml(runtimeRoot))
224
+ return
225
+ }
226
+ }
227
+
228
+ next()
229
+ })
230
+
231
+ const port = configuredPort
232
+ const sootsimUrl = `http://localhost:${port}${prefix}/`
233
+ console.log(`[rnx] serving at ${sootsimUrl}`)
234
+
235
+ if (appName && !process.env.CI && !process.env.RNX_NO_OPEN) {
236
+ server.httpServer?.once('listening', () => {
237
+ const openPort = listeningPort()
238
+ launchRnxDesktop(
239
+ resolveRnxDesktopLaunchTarget(openPort, bundleForPort(openPort)),
240
+ appName,
241
+ )
242
+ })
243
+ }
244
+ },
245
+ }
246
+ }
247
+
248
+ export const sootsimPlugin = rnxPlugin
249
+ export default rnxPlugin
250
+
251
+ // the `.swift` transform is opt-in per project: an app that never imports a
252
+ // `.swift` file has no reason to watch for one, and an app that ships a native
253
+ // ios/ tree (every swift file in it is a pod or an xcode target, not app
254
+ // source) would otherwise rebuild the wrong package on every edit. a local
255
+ // vite app registers `swiftPlugin` in both the bundler that builds its native
256
+ // bundle and the main dev server that serves the artifact; a One app on the
257
+ // rolldown native engine registers `swiftRemotePlugin` through
258
+ // `native.bundlerOptions.plugins` instead, which submits to
259
+ // `/api/swift-compile` and needs no local toolchain and no serving.
260
+ export { swiftPlugin, type SwiftPluginOptions } from './vite-plugin-swift.ts'
261
+ export {
262
+ swiftRemotePlugin,
263
+ type SwiftRemotePluginOptions,
264
+ } from './rolldown-plugin-swift.ts'