@blario/react-native 0.0.0-stage → 0.1.0

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 (313) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +377 -2
  3. package/dist/BlarProvider.d.ts +74 -0
  4. package/dist/actions/batched.d.ts +1 -0
  5. package/dist/actions/click.d.ts +4 -0
  6. package/dist/actions/commit-watch.d.ts +15 -0
  7. package/dist/actions/events.d.ts +35 -0
  8. package/dist/actions/executor.d.ts +29 -0
  9. package/dist/actions/highlight.d.ts +4 -0
  10. package/dist/actions/interaction-guards.d.ts +9 -0
  11. package/dist/actions/landing.d.ts +11 -0
  12. package/dist/actions/navigation-driver.d.ts +22 -0
  13. package/dist/actions/parse.d.ts +4 -0
  14. package/dist/actions/result.d.ts +4 -0
  15. package/dist/actions/scrolling.d.ts +12 -0
  16. package/dist/actions/services.d.ts +20 -0
  17. package/dist/actions/settle.d.ts +13 -0
  18. package/dist/actions/switch.d.ts +3 -0
  19. package/dist/actions/target.d.ts +25 -0
  20. package/dist/actions/text-input.d.ts +9 -0
  21. package/dist/actions/types.d.ts +59 -0
  22. package/dist/agent/batch-commands.d.ts +17 -0
  23. package/dist/agent/compose.d.ts +23 -0
  24. package/dist/agent/controller.d.ts +28 -0
  25. package/dist/agent/frame-runner.d.ts +9 -0
  26. package/dist/agent/frames.d.ts +180 -0
  27. package/dist/agent/handlers/agent-command.d.ts +5 -0
  28. package/dist/agent/handlers/batch.d.ts +5 -0
  29. package/dist/agent/handlers/consent-screenshot.d.ts +4 -0
  30. package/dist/agent/handlers/context.d.ts +16 -0
  31. package/dist/agent/handlers/dom-state.d.ts +4 -0
  32. package/dist/agent/handlers/element-context.d.ts +2 -0
  33. package/dist/agent/handlers/screenshot.d.ts +3 -0
  34. package/dist/agent/handlers/text-dom.d.ts +5 -0
  35. package/dist/agent/stage.d.ts +13 -0
  36. package/dist/agent-mode/action-description.d.ts +3 -0
  37. package/dist/agent-mode/bubbles.d.ts +10 -0
  38. package/dist/agent-mode/colors.d.ts +12 -0
  39. package/dist/agent-mode/controller.d.ts +92 -0
  40. package/dist/agent-mode/cursor-follow.d.ts +12 -0
  41. package/dist/agent-mode/cursor.d.ts +37 -0
  42. package/dist/agent-mode/frames.d.ts +36 -0
  43. package/dist/agent-mode/haptics.d.ts +6 -0
  44. package/dist/agent-mode/keep-awake.d.ts +19 -0
  45. package/dist/agent-mode/layer-stacking.d.ts +7 -0
  46. package/dist/agent-mode/markdown.d.ts +19 -0
  47. package/dist/agent-mode/panel-geometry.d.ts +6 -0
  48. package/dist/agent-mode/resume.d.ts +13 -0
  49. package/dist/agent-mode/run-memory.d.ts +19 -0
  50. package/dist/agent-mode/spotlight-controller.d.ts +68 -0
  51. package/dist/agent-mode/spotlight.d.ts +6 -0
  52. package/dist/agent-mode/state.d.ts +9 -0
  53. package/dist/agent-mode/status.d.ts +11 -0
  54. package/dist/agent-mode/timers.d.ts +6 -0
  55. package/dist/agent-mode/ui/AgentDock.d.ts +37 -0
  56. package/dist/agent-mode/ui/AgentLayer.d.ts +19 -0
  57. package/dist/agent-mode/ui/AgentLayerHost.d.ts +8 -0
  58. package/dist/agent-mode/ui/AgentPanel.d.ts +19 -0
  59. package/dist/agent-mode/ui/AgentTap.d.ts +10 -0
  60. package/dist/agent-mode/ui/MarkdownText.d.ts +8 -0
  61. package/dist/agent-mode/ui/MessageBubbles.d.ts +9 -0
  62. package/dist/agent-mode/ui/PendingOverlay.d.ts +5 -0
  63. package/dist/agent-mode/ui/SpotlightLayer.d.ts +9 -0
  64. package/dist/agent-mode/ui/SpotlightOverlay.d.ts +7 -0
  65. package/dist/agent-mode/ui/StatusCard.d.ts +14 -0
  66. package/dist/agent-mode/ui/TargetPulse.d.ts +9 -0
  67. package/dist/agent-mode/ui/TouchShield.d.ts +5 -0
  68. package/dist/agent-mode/ui/WarningIcon.d.ts +6 -0
  69. package/dist/agent-mode/ui/full-window-overlay.d.ts +5 -0
  70. package/dist/agent-mode/ui/layer-host.d.ts +2 -0
  71. package/dist/backend/api-client.d.ts +38 -0
  72. package/dist/backend/api-types.d.ts +25 -0
  73. package/dist/backend/app-info.d.ts +14 -0
  74. package/dist/backend/backend-transport.d.ts +70 -0
  75. package/dist/backend/backoff.d.ts +9 -0
  76. package/dist/backend/base64.d.ts +1 -0
  77. package/dist/backend/errors.d.ts +17 -0
  78. package/dist/backend/foreground.d.ts +1 -0
  79. package/dist/backend/health.d.ts +17 -0
  80. package/dist/backend/identity-proof.d.ts +23 -0
  81. package/dist/backend/identity.d.ts +27 -0
  82. package/dist/backend/message-metadata.d.ts +19 -0
  83. package/dist/backend/presence.d.ts +20 -0
  84. package/dist/backend/response-cache.d.ts +9 -0
  85. package/dist/backend/session-change.d.ts +2 -0
  86. package/dist/backend/session-socket.d.ts +49 -0
  87. package/dist/backend/session.d.ts +39 -0
  88. package/dist/backend/socket-url.d.ts +9 -0
  89. package/dist/backend/storage.d.ts +13 -0
  90. package/dist/backend/tab-id.d.ts +2 -0
  91. package/dist/blar.d.ts +37 -0
  92. package/dist/chat/ChatLayer.d.ts +29 -0
  93. package/dist/chat/ChatSheet.d.ts +11 -0
  94. package/dist/chat/ChatView.d.ts +19 -0
  95. package/dist/chat/Launcher.d.ts +14 -0
  96. package/dist/chat/bridge.d.ts +22 -0
  97. package/dist/chat/chat-coordinator.d.ts +57 -0
  98. package/dist/chat/chat-state.d.ts +20 -0
  99. package/dist/chat/navigation.d.ts +5 -0
  100. package/dist/chat/options.d.ts +22 -0
  101. package/dist/chat/webview.d.ts +10 -0
  102. package/dist/chat/widget-bundle.generated.d.ts +2 -0
  103. package/dist/chat/widget-shell.d.ts +24 -0
  104. package/dist/confirmation/port.d.ts +12 -0
  105. package/dist/fiber/locate.d.ts +7 -0
  106. package/dist/fiber/narrow.d.ts +5 -0
  107. package/dist/fiber/reader.d.ts +10 -0
  108. package/dist/fiber/text.d.ts +4 -0
  109. package/dist/fiber/types.d.ts +21 -0
  110. package/dist/host/border-radius.d.ts +1 -0
  111. package/dist/host/instance.d.ts +9 -0
  112. package/dist/host/measure.d.ts +3 -0
  113. package/dist/host/rect.d.ts +22 -0
  114. package/dist/host/visible-area.d.ts +2 -0
  115. package/dist/index.d.ts +10 -0
  116. package/dist/nudge/NudgeBubble.d.ts +15 -0
  117. package/dist/nudge/nudge.d.ts +23 -0
  118. package/dist/optional/expo-haptics.d.ts +1 -0
  119. package/dist/optional/expo-keep-awake.d.ts +1 -0
  120. package/dist/optional/react-native-haptic-feedback.d.ts +1 -0
  121. package/dist/optional/react-native-keep-awake.d.ts +1 -0
  122. package/dist/overlay/AgentOverlay.d.ts +5 -0
  123. package/dist/screenshot/capture-backend.d.ts +6 -0
  124. package/dist/screenshot/screenshotter.d.ts +18 -0
  125. package/dist/screenshot/skia.d.ts +35 -0
  126. package/dist/screenshot/view-shot.d.ts +2 -0
  127. package/dist/snapshot/capture.d.ts +36 -0
  128. package/dist/snapshot/classify.d.ts +11 -0
  129. package/dist/snapshot/collect.d.ts +27 -0
  130. package/dist/snapshot/element-context.d.ts +9 -0
  131. package/dist/snapshot/icon.d.ts +2 -0
  132. package/dist/snapshot/kinds.d.ts +3 -0
  133. package/dist/snapshot/modals.d.ts +2 -0
  134. package/dist/snapshot/navigation.d.ts +14 -0
  135. package/dist/snapshot/ordering.d.ts +2 -0
  136. package/dist/snapshot/properties.d.ts +14 -0
  137. package/dist/snapshot/registry.d.ts +16 -0
  138. package/dist/snapshot/render.d.ts +10 -0
  139. package/dist/snapshot/route-summary.d.ts +3 -0
  140. package/dist/snapshot/scroll.d.ts +15 -0
  141. package/dist/snapshot/text-layout.d.ts +8 -0
  142. package/dist/snapshot/view.d.ts +30 -0
  143. package/dist/snapshot/visibility.d.ts +17 -0
  144. package/dist/snapshot/wrappers.d.ts +11 -0
  145. package/dist/telemetry/SdkErrorBoundary.d.ts +15 -0
  146. package/dist/telemetry/build-info.generated.d.ts +2 -0
  147. package/dist/telemetry/envelope.d.ts +53 -0
  148. package/dist/telemetry/reporter.d.ts +33 -0
  149. package/dist/telemetry/scrub.d.ts +1 -0
  150. package/dist/telemetry/sdk-reporter.d.ts +5 -0
  151. package/dist/transport/connection-options.d.ts +18 -0
  152. package/dist/transport/relay-transport.d.ts +17 -0
  153. package/dist/transport/transport.d.ts +7 -0
  154. package/dist/ui/insets.d.ts +8 -0
  155. package/dist/ui/strings.d.ts +33 -0
  156. package/dist/ui/useInsets.d.ts +2 -0
  157. package/dist/version.d.ts +1 -0
  158. package/package.json +85 -4
  159. package/src/BlarProvider.tsx +462 -0
  160. package/src/actions/batched.ts +16 -0
  161. package/src/actions/click.ts +54 -0
  162. package/src/actions/commit-watch.ts +86 -0
  163. package/src/actions/events.ts +58 -0
  164. package/src/actions/executor.ts +147 -0
  165. package/src/actions/highlight.ts +13 -0
  166. package/src/actions/interaction-guards.ts +44 -0
  167. package/src/actions/landing.ts +26 -0
  168. package/src/actions/navigation-driver.ts +131 -0
  169. package/src/actions/parse.ts +82 -0
  170. package/src/actions/result.ts +14 -0
  171. package/src/actions/scrolling.ts +112 -0
  172. package/src/actions/services.ts +24 -0
  173. package/src/actions/settle.ts +40 -0
  174. package/src/actions/switch.ts +31 -0
  175. package/src/actions/target.ts +77 -0
  176. package/src/actions/text-input.ts +82 -0
  177. package/src/actions/types.ts +52 -0
  178. package/src/agent/batch-commands.ts +33 -0
  179. package/src/agent/compose.ts +67 -0
  180. package/src/agent/controller.ts +106 -0
  181. package/src/agent/frame-runner.ts +27 -0
  182. package/src/agent/frames.ts +193 -0
  183. package/src/agent/handlers/agent-command.ts +74 -0
  184. package/src/agent/handlers/batch.ts +72 -0
  185. package/src/agent/handlers/consent-screenshot.ts +44 -0
  186. package/src/agent/handlers/context.ts +17 -0
  187. package/src/agent/handlers/dom-state.ts +19 -0
  188. package/src/agent/handlers/element-context.ts +9 -0
  189. package/src/agent/handlers/screenshot.ts +24 -0
  190. package/src/agent/handlers/text-dom.ts +17 -0
  191. package/src/agent/stage.ts +22 -0
  192. package/src/agent-mode/action-description.ts +25 -0
  193. package/src/agent-mode/bubbles.ts +31 -0
  194. package/src/agent-mode/colors.ts +40 -0
  195. package/src/agent-mode/controller.ts +459 -0
  196. package/src/agent-mode/cursor-follow.ts +43 -0
  197. package/src/agent-mode/cursor.ts +118 -0
  198. package/src/agent-mode/frames.ts +70 -0
  199. package/src/agent-mode/haptics.ts +49 -0
  200. package/src/agent-mode/keep-awake.ts +107 -0
  201. package/src/agent-mode/layer-stacking.ts +16 -0
  202. package/src/agent-mode/markdown.ts +84 -0
  203. package/src/agent-mode/panel-geometry.ts +27 -0
  204. package/src/agent-mode/resume.ts +16 -0
  205. package/src/agent-mode/run-memory.ts +65 -0
  206. package/src/agent-mode/spotlight-controller.ts +255 -0
  207. package/src/agent-mode/spotlight.ts +14 -0
  208. package/src/agent-mode/state.ts +36 -0
  209. package/src/agent-mode/status.ts +13 -0
  210. package/src/agent-mode/timers.ts +11 -0
  211. package/src/agent-mode/ui/AgentDock.tsx +285 -0
  212. package/src/agent-mode/ui/AgentLayer.tsx +123 -0
  213. package/src/agent-mode/ui/AgentLayerHost.tsx +37 -0
  214. package/src/agent-mode/ui/AgentPanel.tsx +187 -0
  215. package/src/agent-mode/ui/AgentTap.tsx +190 -0
  216. package/src/agent-mode/ui/MarkdownText.tsx +55 -0
  217. package/src/agent-mode/ui/MessageBubbles.tsx +58 -0
  218. package/src/agent-mode/ui/PendingOverlay.tsx +32 -0
  219. package/src/agent-mode/ui/SpotlightLayer.tsx +60 -0
  220. package/src/agent-mode/ui/SpotlightOverlay.tsx +35 -0
  221. package/src/agent-mode/ui/StatusCard.tsx +137 -0
  222. package/src/agent-mode/ui/TargetPulse.tsx +74 -0
  223. package/src/agent-mode/ui/TouchShield.tsx +22 -0
  224. package/src/agent-mode/ui/WarningIcon.tsx +32 -0
  225. package/src/agent-mode/ui/full-window-overlay.ts +16 -0
  226. package/src/agent-mode/ui/layer-host.ts +11 -0
  227. package/src/backend/api-client.ts +210 -0
  228. package/src/backend/api-types.ts +56 -0
  229. package/src/backend/app-info.ts +40 -0
  230. package/src/backend/backend-transport.ts +338 -0
  231. package/src/backend/backoff.ts +16 -0
  232. package/src/backend/base64.ts +25 -0
  233. package/src/backend/errors.ts +32 -0
  234. package/src/backend/foreground.ts +10 -0
  235. package/src/backend/health.ts +64 -0
  236. package/src/backend/identity-proof.ts +151 -0
  237. package/src/backend/identity.ts +31 -0
  238. package/src/backend/message-metadata.ts +28 -0
  239. package/src/backend/presence.ts +95 -0
  240. package/src/backend/response-cache.ts +45 -0
  241. package/src/backend/session-change.ts +14 -0
  242. package/src/backend/session-socket.ts +292 -0
  243. package/src/backend/session.ts +188 -0
  244. package/src/backend/socket-url.ts +25 -0
  245. package/src/backend/storage.ts +49 -0
  246. package/src/backend/tab-id.ts +24 -0
  247. package/src/blar.ts +100 -0
  248. package/src/chat/ChatLayer.tsx +109 -0
  249. package/src/chat/ChatSheet.tsx +82 -0
  250. package/src/chat/ChatView.tsx +127 -0
  251. package/src/chat/Launcher.tsx +72 -0
  252. package/src/chat/bridge.ts +56 -0
  253. package/src/chat/chat-coordinator.ts +189 -0
  254. package/src/chat/chat-state.ts +35 -0
  255. package/src/chat/navigation.ts +15 -0
  256. package/src/chat/options.ts +39 -0
  257. package/src/chat/webview.ts +23 -0
  258. package/src/chat/widget-bundle.generated.ts +2 -0
  259. package/src/chat/widget-shell.ts +170 -0
  260. package/src/confirmation/port.ts +15 -0
  261. package/src/fiber/locate.ts +41 -0
  262. package/src/fiber/narrow.ts +15 -0
  263. package/src/fiber/reader.ts +98 -0
  264. package/src/fiber/text.ts +52 -0
  265. package/src/fiber/types.ts +24 -0
  266. package/src/host/border-radius.ts +11 -0
  267. package/src/host/instance.ts +30 -0
  268. package/src/host/measure.ts +25 -0
  269. package/src/host/rect.ts +45 -0
  270. package/src/host/visible-area.ts +5 -0
  271. package/src/index.ts +10 -0
  272. package/src/nudge/NudgeBubble.tsx +117 -0
  273. package/src/nudge/nudge.ts +100 -0
  274. package/src/optional/expo-haptics.ts +11 -0
  275. package/src/optional/expo-keep-awake.ts +11 -0
  276. package/src/optional/react-native-haptic-feedback.ts +11 -0
  277. package/src/optional/react-native-keep-awake.ts +11 -0
  278. package/src/overlay/AgentOverlay.tsx +16 -0
  279. package/src/screenshot/capture-backend.ts +7 -0
  280. package/src/screenshot/screenshotter.ts +39 -0
  281. package/src/screenshot/skia.ts +107 -0
  282. package/src/screenshot/view-shot.ts +41 -0
  283. package/src/snapshot/capture.ts +163 -0
  284. package/src/snapshot/classify.ts +40 -0
  285. package/src/snapshot/collect.ts +136 -0
  286. package/src/snapshot/element-context.ts +66 -0
  287. package/src/snapshot/icon.ts +21 -0
  288. package/src/snapshot/kinds.ts +10 -0
  289. package/src/snapshot/modals.ts +21 -0
  290. package/src/snapshot/navigation.ts +47 -0
  291. package/src/snapshot/ordering.ts +26 -0
  292. package/src/snapshot/properties.ts +71 -0
  293. package/src/snapshot/registry.ts +33 -0
  294. package/src/snapshot/render.ts +140 -0
  295. package/src/snapshot/route-summary.ts +15 -0
  296. package/src/snapshot/scroll.ts +90 -0
  297. package/src/snapshot/text-layout.ts +59 -0
  298. package/src/snapshot/view.ts +87 -0
  299. package/src/snapshot/visibility.ts +63 -0
  300. package/src/snapshot/wrappers.ts +69 -0
  301. package/src/telemetry/SdkErrorBoundary.tsx +28 -0
  302. package/src/telemetry/build-info.generated.ts +2 -0
  303. package/src/telemetry/envelope.ts +83 -0
  304. package/src/telemetry/reporter.ts +170 -0
  305. package/src/telemetry/scrub.ts +10 -0
  306. package/src/telemetry/sdk-reporter.ts +37 -0
  307. package/src/transport/connection-options.ts +65 -0
  308. package/src/transport/relay-transport.ts +82 -0
  309. package/src/transport/transport.ts +8 -0
  310. package/src/ui/insets.ts +31 -0
  311. package/src/ui/strings.ts +102 -0
  312. package/src/ui/useInsets.ts +10 -0
  313. package/src/version.ts +1 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Blar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,378 @@
1
- # Temporary Holding Version
1
+ # @blario/react-native
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Blar agent SDK for React Native. It mirrors the web widget's agent: it parses the React component tree into the
4
+ web `dom_state` v3 snapshot, hands out its own per-capture ids (`btn-N`, `inp-N`, `scr-N`) and resolves an id back
5
+ to its component to act on it.
6
+
7
+ Pure JS/TS, no native code. Works on the old architecture and on the New Architecture.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @blario/react-native react-native-webview
13
+ ```
14
+
15
+ With Expo, let it pick the versions that match your SDK:
16
+
17
+ ```bash
18
+ npx expo install @blario/react-native react-native-webview @react-native-async-storage/async-storage react-native-safe-area-context
19
+ ```
20
+
21
+ Needs `react` >= 18.2 and `react-native` >= 0.74. `react-native-webview` runs the chat (the web widget) and is the
22
+ only peer you need to get started; the rest are optional and the SDK works without them:
23
+
24
+ | Peer | Without it |
25
+ | --- | --- |
26
+ | `@react-native-async-storage/async-storage` | the contact is kept in memory, so every launch is a new anonymous contact |
27
+ | `react-native-safe-area-context` | fixed fallback insets are used instead of the device's |
28
+ | `react-native-view-shot` (or `@shopify/react-native-skia` on iOS) | a screenshot request answers `sdk_error` |
29
+ | `react-native-screens` | on iOS the agent layer is drawn in the root tree instead of its own window |
30
+ | `expo-haptics` or `react-native-haptic-feedback` | no buzz when a confirmation appears |
31
+ | `expo-keep-awake` or `react-native-keep-awake` | the screen may sleep during an agent run |
32
+
33
+ Native peers need a rebuild of the app (`npx expo prebuild` / `pod install`) unless Expo Go already ships them. The
34
+ package ships its TypeScript source, which Metro compiles with the rest of your app, plus type declarations in `dist/`.
35
+ Then wrap the app as shown in [Connect to the Blar backend](#connect-to-the-blar-backend).
36
+
37
+ ### Versions
38
+
39
+ Versions follow semver and each one is published to npm when it reaches `main`. While the major is `0` a minor release
40
+ may change the API, and the `^0.2.0` range npm writes by default stays within one minor. The `latest` dist-tag is the
41
+ newest stable release and `next` the newest prerelease (`0.3.0-beta.0`), installed with
42
+ `npm install @blario/react-native@next`. `SDK_VERSION` is the installed version, and it is what the SDK reports to the
43
+ backend.
44
+
45
+ ## Integrate
46
+
47
+ ```tsx
48
+ import { BlarProvider } from '@blario/react-native';
49
+ import { createNavigationContainerRef, NavigationContainer } from '@react-navigation/native';
50
+
51
+ const navigationRef = createNavigationContainerRef();
52
+
53
+ export default function App() {
54
+ return (
55
+ <BlarProvider navigationRef={navigationRef} relayUrl="ws://localhost:8790">
56
+ <NavigationContainer ref={navigationRef}>{/* app */}</NavigationContainer>
57
+ </BlarProvider>
58
+ );
59
+ }
60
+ ```
61
+
62
+ `navigationRef` is optional. Without it `navigate` only reaches routes of the navigators on the focused path.
63
+ Screenshots use `react-native-view-shot` when it is installed, otherwise `@shopify/react-native-skia`
64
+ (`makeImageFromView`) on iOS. Android requires view-shot: Skia's Android capture can raise a fatal native error
65
+ when a view unmounts during capture. With no supported capture module, a screenshot answers `sdk_error`.
66
+ Each module is resolved once when the SDK loads:
67
+
68
+ - view-shot leaves a host `Modal` out (it is a separate window), so the response carries `partial: true` and
69
+ `omitted: ['modal']` while one is open.
70
+ - Skia on iOS walks the view tree. A host `Modal` is presented by its own view controller, outside the captured
71
+ view, so it is reported as omitted, as with view-shot. A capture narrower than `maxWidth` is sent at its own width,
72
+ never upscaled.
73
+
74
+ Neither includes the status bar, the chat or the agent layer.
75
+
76
+ The implicit `ws://localhost:8790` relay is available only in development when no backend settings are provided.
77
+ Production requires both `publishableKey` and `apiBaseUrl`, or an explicit `relayUrl`. Invalid or partial backend
78
+ settings disable the SDK while the host app keeps rendering. API URLs must use HTTP(S); relay URLs must use WS(S).
79
+ Surrounding whitespace and scheme/host casing are normalized, and API base URLs must have no query or fragment.
80
+
81
+ Installed from npm, Metro needs no configuration. Only a linked checkout (the example app's `file:..` dependency) needs
82
+ the SDK folder watched and a single copy of `react`/`react-native` (see its `metro.config.js`).
83
+
84
+ ## Connect to the Blar backend
85
+
86
+ ```tsx
87
+ <BlarProvider
88
+ publishableKey="<publishable-key>"
89
+ apiBaseUrl="https://api.blar.io"
90
+ user={{ externalId: 'u-1', email: 'ana@x.cl', name: 'Ana', country: 'CL', getIdentityToken: () => fetchToken() }}
91
+ language="es"
92
+ debug
93
+ >
94
+ ```
95
+
96
+ `language` is `'es'` or `'en'` and defaults to `'es'`; unsupported runtime values also fall back to `'es'` for the
97
+ SDK's own texts and the chat's language. With `publishableKey` and `apiBaseUrl` the provider uses the backend
98
+ transport. It mirrors the web widget: `contacts/load/` then `contacts/identify/` with `X-Publishable-Key`,
99
+ `X-Source-Id` and the identity proof (`X-Identity-Token` / `X-Identity-Signature`, refreshed once through
100
+ `getProof` / `getIdentityToken`), the session socket `/sessions/chat/<id>/?publishable_key&source_id&tab_id` with the
101
+ proof as a subprotocol, ping/pong with `{visibility, hidden_ms, lag_ms, sdk_version}`, reconnect with backoff,
102
+ response replay after a reconnect, and a presence heartbeat every 30 s while the app is active and touched in the last
103
+ 3 minutes. `source_id` persists in AsyncStorage when installed, otherwise in memory. `enabled={false}` keeps the SDK
104
+ off; changing it on a mounted provider starts or stops the socket, the agent and the chat.
105
+
106
+ Identity tokens must have three nonempty base64url JWT segments; identity signatures must be hexadecimal.
107
+ Malformed static values or provider results are treated as proof failures and never sent in native headers.
108
+
109
+ ```ts
110
+ import { Blar } from '@blario/react-native';
111
+
112
+ await Blar.setUser({ externalId: 'u-1', email: 'ana@x.cl' });
113
+ await Blar.logout();
114
+ Blar.isConnected();
115
+ await Blar.getMessageMetadata({ includeTextDom: true });
116
+ ```
117
+
118
+ Risky actions (`irreversible`, `destructive`, or `confirmation_required`) ask for confirmation in a native panel on the
119
+ status card; a decline or a 60 s timeout answers `user_cancelled`.
120
+
121
+ ### Drive the app with the real on-site agent
122
+
123
+ ```bash
124
+ npm run harness -- --key <publishable-key> --external-id <id> --email <email> --base http://localhost:55180 "crea un cliente llamado Ana Díaz"
125
+ harness/tap-confirm.sh Confirmar 240 # approves the confirmation on the emulator (adb + uiautomator)
126
+ ```
127
+
128
+ The harness identifies the same contact as the app (`--external-id` and `--email`, or `BLAR_EXTERNAL_ID` and `BLAR_EMAIL`;
129
+ `--name` and `--country` are optional), posts the message through
130
+ `/api/ai/contact-sessions/<id>/widget/messages/create/` without a `tab_id`, so the app's socket answers as the holder,
131
+ and prints the conversation as it grows.
132
+
133
+ ## Chat and nudges
134
+
135
+ With the backend transport the provider also renders the chat. It needs `react-native-webview` (a peer dependency)
136
+ and optionally `react-native-safe-area-context` for insets.
137
+
138
+ ```tsx
139
+ <BlarProvider
140
+ publishableKey="<publishable-key>"
141
+ apiBaseUrl="https://api.blar.io"
142
+ user={user}
143
+ language="es"
144
+ strings={{ agentThinking: 'Pensando…' }}
145
+ chat={{ launcher: { visible: true, side: 'left', offsetY: 88 }, primaryColor: '#7C3AED' }}
146
+ >
147
+ ```
148
+
149
+ ```ts
150
+ Blar.open();
151
+ Blar.close();
152
+ Blar.getUnreadCount();
153
+ Blar.isChatOpen();
154
+ ```
155
+
156
+ - The web support widget runs inside a `react-native-webview` in `messagesOnly` mode, served from a generated HTML
157
+ shell on the API origin. The bundle is generated, not committed (`src/chat/widget-bundle.generated.ts` is git-ignored): build
158
+ `support-widget.min.js` in `web-sdk/`, then run `npm run embed-widget` before `npm run typecheck` or the example
159
+ app (the unit tests do not need it). Or pass `chat.scriptUrl` to load it from a CDN instead.
160
+ - One contact, one session, one executor: the page seeds the widget with the native `tab_id`, identifies with the same
161
+ identity and source, and boots it with `agentExecution: false`, so it ignores every agent command and only the native
162
+ runtime executes. Messages the user sends carry `Blar.getMessageMetadata()` (platform, screen path, text tree). The
163
+ widget's `onSessionChange` reports a new conversation and the native socket follows it. When the page leaves its
164
+ session (an escalation, a new or an ended conversation), native ends any run there and drops the socket until the
165
+ page reports the next one. Its `onClose` closes the sheet, and the chat reopens when the sheet does.
166
+ - The chat page never navigates away: a link it opens (a message link, an attachment, "Powered by Blar") goes to the
167
+ system browser through `Linking`, and frames inside the page load as usual.
168
+ - Replying works as in WhatsApp: drag a message to the right and let go, or hold it, and the composer quotes it. This is
169
+ the widget's own touch gesture, so it needs no native code.
170
+ - Assistant messages that arrive while the sheet is not open raise the unread badge.
171
+ - Nudges arrive as native bubbles with the same sender, message, progress and actions as the web widget. Accepting
172
+ calls `POST /api/activation/nudges/open/` and opens the chat on the nudge session (`openSession`, without reloading
173
+ the page); dismissing and snoozing call the `dismiss` and `snooze` endpoints. A heartbeat that reports a pending
174
+ nudge refreshes the session so the bubble shows without waiting for a restart.
175
+ - `strings` overrides any of the confirmation, chat, nudge and agent mode texts; `es` and `en` defaults ship in the
176
+ package.
177
+
178
+ ## Agent mode
179
+
180
+ A run looks and behaves like the web widget's agent mode (`web-sdk/src/managers/agent-mode-state.ts`,
181
+ `web-sdk/src/agent/agent-mode-ui.ts`), driven by `AgentModeController`:
182
+
183
+ - The first `agent_command` or `agent_command_batch` of a run starts a 2 s pending phase ("La IA va a tomar el
184
+ control"); its commands are acknowledged at once and run when it ends. Reads (`dom_state`, text tree, screenshots)
185
+ never start a run. A `history` frame with `agent_mode_active` restores a run without the pending phase.
186
+ - A run survives the app being killed, like the web's per-tab resume flag. The session id and the time of the last
187
+ agent frame are kept in AsyncStorage while the run is active; connecting to that session again within 120 s (the
188
+ backend's longest wait on an SDK answer) brings the layer back without the pending phase. It then waits 30 s for an
189
+ agent frame, absorbing one completion meant for the killed app. Every exit, a session change and a logout clear it.
190
+ - While active the chat sheet collapses, the launcher hides, a status card shows the state ("Pensando", "Ejecutando
191
+ acción...", or the backend's progress label) with a Stop button, and each step's sentence shows as a message bubble
192
+ (markdown, deduplicated, read for 6 to 18 s). A queued message shows a chip on the card for 5 s.
193
+ - There is no cursor. Each `click`, `check` and `type` shows a fingertip ring on its target (40 dp, white with a dark
194
+ hairline, filled with the primary colour): it appears on the target, stays pinned to it while it moves, presses and
195
+ sends out one ripple once it settles, and is gone 450 ms later. Scrolls, keys, navigation and highlights draw
196
+ nothing. A click or a switch waits for the landing, at most 1.8 s, before the gesture. The status card fades while a
197
+ tap lands on something underneath it. Reduced motion keeps only fades.
198
+ - Readings and confirmations live in a white panel attached to the top of the status card, the two reading as one
199
+ surface. Before it shows, the panel is laid out unseen and its target is scrolled so that it sits in the middle of
200
+ the free area above the stack (the nearest scroll container, by an offset); when the target still sits under the
201
+ stack (a tab bar, a sticky button), the whole stack docks at the top of the screen. The dock is decided once per
202
+ panel. The message is capped at 40 % of the free area and scrolls inside the panel beyond that.
203
+ - A `highlight` dims the screen 60 % around a rounded hole over the target (padding 8, tracked while it moves) and
204
+ shows a reading panel: the step's sentence (markdown), a bar filling over the reading time (6 to 18 s at 120 wpm,
205
+ counted from when the panel is on screen) and "Omitir". The status card keeps its text and its Stop. The action is
206
+ answered when the reading ends, so the agent waits for the user; Omitir or the app going to the background ends it
207
+ early, Stop or Back answers `user_cancelled`. The `duration_ms` the backend sends is ignored, as on the web. Step
208
+ bubbles are hidden while the panel is up.
209
+ - An action that needs confirmation (`confirmation_required`, or an irreversible or destructive risk; never a
210
+ `highlight` or `scroll_to`) dims around its target, outlined and pulsing with a white edge, and asks in the panel:
211
+ the step's sentence, or the action's own description, then **Detener** and **Confirmar** (48 dp, the confirm text in
212
+ the colour that reads on the primary). The status card says "Confirmación pendiente" and hides its own Stop. A
213
+ destructive action adds "Esta acción no se puede deshacer" and turns the button into a red **Sí, continuar**.
214
+ Detener or Back stops the whole run, as on the web; a tap on the dim backdrop only nudges the panel. 60 s without an
215
+ answer declines it. Both answer `user_cancelled`, with a message that tells a decline from silence. The confirmation
216
+ buzzes once when it appears if `react-native-haptic-feedback` or `expo-haptics` is installed (both optional peers).
217
+ Once approved, what the user saw is captured (JPEG 0.6, before the action runs) and sent on
218
+ `{command_id}:screenshot` as the consent evidence the backend keeps; a failed capture is reported there as
219
+ `CAPTURE_FAILED`, and nothing is sent without a capture module or after a Stop.
220
+ - Touches on the app are swallowed by a shield that shows "Toca Detener para tomar el control" and pulses Stop. The
221
+ agent never goes through touches, so its actions are unaffected.
222
+ - Stop, or the Android back button, sends `agent_cancel` and ends the run; an action not yet dispatched and the rest
223
+ of a batch stand down. The run also ends on `agent_execution_complete`, `agent_acknowledged`, `agent_cancelled`,
224
+ `session_closed`, a message that waits for the user, a conversation replaced by an objective or any other session
225
+ change, a socket that gave up, or 120 s without agent activity. The chat opens again when it ends.
226
+ - The layer lives in its own window: a transparent `Modal` on Android (re-raised when the agent opens a host `Modal`
227
+ on top of it), `FullWindowOverlay` from `react-native-screens` on iOS when installed, the root tree otherwise. It is
228
+ excluded from snapshots and screenshots.
229
+ - The screen stays on from the AI turn through the run when `expo-keep-awake` or `react-native-keep-awake` is
230
+ installed (both optional peers); without one this is a no-op, reported once with `debug`.
231
+
232
+ Known differences from the web: the pending dim covers the whole screen (the web dims only the chat window); the
233
+ layer takes window focus, so an open keyboard closes when a run starts; `session_closed` ends the run (the web only
234
+ tears it down). Visual effects (dot grid, glow, slime) come in a later milestone.
235
+
236
+ ### Test nudges without a real delivery
237
+
238
+ ```bash
239
+ npm run proxy -- --log proxy.log # :55181 -> the local backend (HTTP and the session socket)
240
+ # EXPO_PUBLIC_BLAR_API_BASE_URL=http://localhost:55181, adb reverse tcp:55181 tcp:55181, restart Metro with --clear
241
+ npm run inject -- history --milestone 9001 # a nudge as the history frame the backend sends on connect
242
+ npm run inject -- live --milestone 9002 # the same nudge as a live message frame
243
+ npm run inject -- continuation --cta "Continuar" --milestone 9003
244
+ ```
245
+
246
+ The proxy forwards everything to the backend untouched, tags the app's own session socket (user agent without
247
+ "Mozilla") as native, and `inject` pushes the frame only to that socket. Every request to
248
+ `/api/activation/nudges/*` is logged with its headers, body and the backend's answer. `GET /__proxy/state` lists the
249
+ open sockets and the last requests.
250
+
251
+ ## Run the example app
252
+
253
+ `example/` is an Expo SDK 51 app (AgendaPro-like screens, React Navigation) that depends on the SDK through `file:..`
254
+ and runs in Expo Go on an Android emulator. Build and embed the widget first (see Develop).
255
+
256
+ ```bash
257
+ cd example
258
+ cp .env.example .env.local # local backend URL, publishable key and test contact; never committed
259
+ npm ci
260
+ adb reverse tcp:8081 tcp:8081 && adb reverse tcp:55180 tcp:55180
261
+ npx expo start --clear # open it in Expo Go
262
+ ```
263
+
264
+ `EXPO_PUBLIC_*` values are inlined when Metro bundles, so restart it with `--clear` after editing `.env.local`. Without a
265
+ publishable key the provider talks to the dev relay instead.
266
+
267
+ ## Run the dev relay
268
+
269
+ ```bash
270
+ npm run relay # app socket ws://localhost:8790, HTTP http://localhost:8791
271
+ adb reverse tcp:8790 tcp:8790 # Android emulator/device reaches the relay on localhost
272
+ relay/ctl.sh snap # POST /dom_state?text=1
273
+ relay/ctl.sh act "Guardar" click # find the id by text in a fresh snapshot, then POST /command
274
+ relay/ctl.sh shot # POST /screenshot, saved under relay/shots/
275
+ ```
276
+
277
+ | Request | Body | Reply |
278
+ | --- | --- | --- |
279
+ | `POST /dom_state[?text=1]` | none | `{schema_version, platform, screen, routes, html_snapshot}` or the snapshot text |
280
+ | `POST /command` | `{action: {type, ...}, target?: {agent_id}}` | `{success, no_op, error?, message?}` |
281
+ | `POST /screenshot` | `{options?: {quality, maxWidth}}` | `{path, bytes, screen}` |
282
+ | `GET /health` | none | `{app_connected}` |
283
+
284
+ Wire envelope (mirrors the backend): `agent_command` / `request_dom_state` / `request_screenshot` in,
285
+ `command_ack` then `sdk_response` (`agent_command_response`, `dom_state_response`, `screenshot_response`) or
286
+ `sdk_error` out.
287
+
288
+ ## Actions
289
+
290
+ | `action.type` | Fields | Target |
291
+ | --- | --- | --- |
292
+ | `click` | | `btn-N` (a switch toggles, an input is focused) |
293
+ | `type` | `value`, `clear_first` (default true) | `inp-N` text input |
294
+ | `check` | `checked` (omit to toggle) | `inp-N` switch |
295
+ | `press_key` | `key` (`Enter` only) | `inp-N`, or the last input used |
296
+ | `scroll` | `direction` up/down/left/right, `amount` px | `scr-N` |
297
+ | `scroll_to` | | any element, uses its nearest scroll container |
298
+ | `navigate` | `route` (`Name` or `Parent/Child`), `params` | none |
299
+ | `highlight` | `duration_ms` (default 3000) | any element |
300
+
301
+ `click`, `type`, `check` and `highlight` scroll the target into view first. Elements that sit beyond their scroll
302
+ viewport are listed with `offscreen=above|below|left|right` (at most 30, nearest first).
303
+
304
+ ## Develop
305
+
306
+ The chat embeds this repo's widget build, which is generated and git-ignored, so build it before the typecheck or the
307
+ example app (the unit tests do not need it).
308
+
309
+ ```bash
310
+ (cd ../web-sdk && pnpm install && pnpm build) # the widget
311
+ npm ci
312
+ npm run embed-widget # src/chat/widget-bundle.generated.ts from ../web-sdk/dist/support-widget.min.js
313
+ npm run telemetry-config # src/telemetry/build-info.generated.ts from SENTRY_DSN / SENTRY_ENVIRONMENT (empty by default: no reporting)
314
+ npm run typecheck
315
+ npm test
316
+ ```
317
+
318
+ CI (`.github/workflows/react-native-sdk-ci.yaml`) runs the same steps on every change under `react-native-sdk/`, plus
319
+ `npm run build`, which emits the type declarations into `dist/` (git-ignored; `prepack` runs it). The widget deploy
320
+ workflows ignore those changes.
321
+
322
+ ## Release
323
+
324
+ A release is a version bump that reaches `main`, like a widget deploy. npm never takes the same version twice, so a push
325
+ to `main` publishes only when `package.json` carries a version npm does not have yet; without a bump nothing is
326
+ published.
327
+
328
+ ```bash
329
+ cd react-native-sdk
330
+ npm version minor --no-git-tag-version # patch | minor | major; rewrites package.json, the lockfile and src/version.ts
331
+ git commit -am "Release @blario/react-native 0.2.0"
332
+ ```
333
+
334
+ Merge that to `dev`, then `dev` to `main` as usual. For a prerelease use
335
+ `npm version preminor --preid beta --no-git-tag-version` (`0.3.0-beta.0`); a version with a `-` is published under the
336
+ `next` dist-tag, so `latest` never moves to it.
337
+
338
+ `.github/workflows/react-native-sdk-release.yaml` runs on pushes to `main` that change `react-native-sdk/package.json`
339
+ and stops there when npm already has that version. Otherwise it builds the widget with
340
+ `API_BASE_URL=https://api.blar.io` and the repo's Sentry secrets, uploads its source maps and injects the debug IDs (the
341
+ same steps as `deplot.yaml`), embeds it, runs the typecheck and the tests, writes the Sentry DSN into the package
342
+ (`npm run telemetry-config`), packs the tarball, checks that it holds the embedded widget, `dist/index.d.ts` and the
343
+ DSN, and publishes that exact tarball. It uses the `SENTRY_DSN`, `SENTRY_AUTH_TOKEN`, `SENTRY_ORG` and `SENTRY_PROJECT`
344
+ repository secrets, and a release fails if any is missing. A failed release is retried with "Re-run jobs" on its run. A
345
+ published version can never be replaced, so fix a bad release with the next patch and deprecate the bad one
346
+ (`npm deprecate @blario/react-native@0.2.0 "use 0.2.1"`).
347
+
348
+ ### First release, once
349
+
350
+ There is no npm token: the workflow publishes with npm's trusted publishing (OIDC), which needs the package to exist
351
+ before it can be configured. The repository is private, so npm does not attach provenance to what it publishes.
352
+
353
+ 1. Reserve the name by hand from a throwaway directory, signed in to npm as a maintainer of `@blario/core` (`berrazuriz1` or `josem7`):
354
+ `npm publish --access public` with a `package.json` of `{ "name": "@blario/react-native", "version": "0.0.0", "license": "MIT" }`.
355
+ 2. On npmjs.com, open the package, Settings, Trusted Publisher, GitHub Actions: organisation `blarApp`, repository
356
+ `support-web-component`, workflow `react-native-sdk-release.yaml`, no environment, and allow `npm publish`. Save
357
+ (npm does not validate it until the first publish) and publish the first real version within 2 days or the setting
358
+ expires.
359
+ 3. Optional hardening under Settings, Publishing access: require 2FA and disallow tokens. It does not affect OIDC.
360
+ 4. Merge `dev` into `main`. `package.json` is at `0.1.0`, which npm does not have, so that push publishes it.
361
+
362
+ If trusted publishing is not wanted, a granular npm token (Read and write, scoped to `@blario`, 2FA bypass) stored as the
363
+ `NODE_AUTH_TOKEN` of the publish step works too, but npm is retiring direct publishing with 2FA-bypass tokens in January
364
+ 2027.
365
+
366
+ ## Error reporting
367
+
368
+ Like the web widget, the SDK reports its own contained failures to Blar's Sentry, through a client that is isolated from
369
+ the host app: it installs no global error handler and no native crash hook, never touches the app's own Sentry, and
370
+ only sees errors the SDK catches itself (the agent runtime, the backend transport and a boundary around the SDK's own
371
+ UI, never the app's components). Events carry the SDK version, platform, publishable key, `source_id`, session id and
372
+ the user's external id; emails, bearer tokens and identity tokens are scrubbed from messages. Network failures and
373
+ refused credentials only become breadcrumbs, and at most 50 events are sent per launch. Without a DSN (the repo
374
+ default, set only by the release job) nothing is sent. `enabled={false}` stops the SDK, and its reporting with it.
375
+
376
+ Stack traces from the app's own bundle cannot be symbolicated on Blar's side, so events group by context and error type
377
+ rather than by stack. The embedded chat widget reports as the web widget does, with its source maps uploaded by the
378
+ release job. Both use the `production-react-native` Sentry environment.
@@ -0,0 +1,74 @@
1
+ import React, { Component, type ReactNode } from 'react';
2
+ import { type AgentModeSnapshot } from './agent-mode/controller.ts';
3
+ import { type CursorSnapshot } from './agent-mode/cursor.ts';
4
+ import { type SpotlightSnapshot } from './agent-mode/spotlight-controller.ts';
5
+ import type { BlarIdentity } from './backend/identity.ts';
6
+ import type { NavigationRefLike } from './actions/navigation-driver.ts';
7
+ import { type ChatSnapshot } from './chat/chat-coordinator.ts';
8
+ import { type ChatOptions } from './chat/options.ts';
9
+ import { type Language, type UiStringOverrides } from './ui/strings.ts';
10
+ export interface BlarProviderProps {
11
+ children: ReactNode;
12
+ publishableKey?: string;
13
+ apiBaseUrl?: string;
14
+ user?: BlarIdentity | null;
15
+ relayUrl?: string;
16
+ navigationRef?: NavigationRefLike | null;
17
+ language?: Language;
18
+ strings?: UiStringOverrides;
19
+ chat?: ChatOptions;
20
+ enabled?: boolean;
21
+ debug?: boolean;
22
+ }
23
+ interface BlarProviderState {
24
+ spotlight: SpotlightSnapshot;
25
+ chat: ChatSnapshot | null;
26
+ agentMode: AgentModeSnapshot | null;
27
+ cursor: CursorSnapshot;
28
+ reduceMotion: boolean;
29
+ layerGeneration: number;
30
+ }
31
+ export declare class BlarProvider extends Component<BlarProviderProps, BlarProviderState> {
32
+ private connection;
33
+ private readonly cursor;
34
+ private readonly spotlight;
35
+ state: BlarProviderState;
36
+ private readonly contentRef;
37
+ private controller;
38
+ private agentMode;
39
+ private transport;
40
+ private backend;
41
+ private coordinator;
42
+ private chatControls;
43
+ private shownNudge;
44
+ private readonly releases;
45
+ private stackingCheckQueued;
46
+ private loggedPhase;
47
+ private readonly stacking;
48
+ private readonly attachCursor;
49
+ private readonly detachCursor;
50
+ componentDidMount(): void;
51
+ componentDidUpdate(previous: BlarProviderProps): void;
52
+ componentWillUnmount(): void;
53
+ private startSdk;
54
+ private stopSdk;
55
+ render(): React.JSX.Element;
56
+ private renderAgentLayer;
57
+ private renderChat;
58
+ private chatOptions;
59
+ private watchForeground;
60
+ private watchMotionPreference;
61
+ private createAgentMode;
62
+ private createTransport;
63
+ private createChat;
64
+ private attachBackend;
65
+ private queueStackingCheck;
66
+ private keepLayerOnTop;
67
+ private countHostModals;
68
+ private noteNudge;
69
+ private debug;
70
+ private followWidgetSession;
71
+ private readChatMetadata;
72
+ private readChatProof;
73
+ }
74
+ export {};
@@ -0,0 +1 @@
1
+ export declare function runBatched(callback: () => void): void;
@@ -0,0 +1,4 @@
1
+ import type { ActionServices } from './services.ts';
2
+ import type { ResolvedTarget } from './target.ts';
3
+ import type { HandlerResult } from './types.ts';
4
+ export declare function click(target: ResolvedTarget, services: ActionServices): Promise<HandlerResult>;
@@ -0,0 +1,15 @@
1
+ import type { Fiber } from '../fiber/types.ts';
2
+ export declare class CommitWatch {
3
+ private readonly getAnchorFiber;
4
+ private readonly onCommit?;
5
+ private watchedRoot;
6
+ private originalDescriptor;
7
+ private watchedSetter;
8
+ private commits;
9
+ private baseline;
10
+ constructor(getAnchorFiber: () => Fiber | null, onCommit?: (() => void) | undefined);
11
+ begin(): void;
12
+ hasCommitted(): boolean;
13
+ release(): void;
14
+ private install;
15
+ }
@@ -0,0 +1,35 @@
1
+ import { type Rect } from '../host/rect.ts';
2
+ export interface SyntheticPressEvent {
3
+ nativeEvent: {
4
+ pageX: number;
5
+ pageY: number;
6
+ locationX: number;
7
+ locationY: number;
8
+ timestamp: number;
9
+ target: number;
10
+ touches: never[];
11
+ changedTouches: never[];
12
+ };
13
+ persist: () => void;
14
+ preventDefault: () => void;
15
+ stopPropagation: () => void;
16
+ isPropagationStopped: () => boolean;
17
+ isDefaultPrevented: () => boolean;
18
+ }
19
+ export interface SyntheticTextChangeEvent {
20
+ nativeEvent: {
21
+ text: string;
22
+ eventCount: number;
23
+ target: number;
24
+ };
25
+ }
26
+ export interface SyntheticSubmitEvent {
27
+ nativeEvent: {
28
+ text: string;
29
+ eventCount: number;
30
+ target: number;
31
+ };
32
+ }
33
+ export declare function buildPressEvent(rect: Rect): SyntheticPressEvent;
34
+ export declare function buildTextChangeEvent(text: string): SyntheticTextChangeEvent;
35
+ export declare function buildSubmitEvent(text: string): SyntheticSubmitEvent;
@@ -0,0 +1,29 @@
1
+ import { SnapshotCapturer } from '../snapshot/capture.ts';
2
+ import type { CommitWatch } from './commit-watch.ts';
3
+ import type { ActionServices } from './services.ts';
4
+ import { type ResolvedTarget } from './target.ts';
5
+ import type { ActionOutcome, AgentCommandData } from './types.ts';
6
+ export interface ExecutionOptions {
7
+ isCancelled: () => boolean;
8
+ }
9
+ export type Preparation = {
10
+ ok: true;
11
+ target: ResolvedTarget | null;
12
+ } | {
13
+ ok: false;
14
+ outcome: ActionOutcome;
15
+ };
16
+ export declare class ActionExecutor {
17
+ private readonly capturer;
18
+ private readonly services;
19
+ private readonly commitWatch;
20
+ constructor(capturer: SnapshotCapturer, services: ActionServices, commitWatch: CommitWatch);
21
+ prepare(command: AgentCommandData): Promise<Preparation>;
22
+ execute(command: AgentCommandData, target: ResolvedTarget | null, options: ExecutionOptions): Promise<ActionOutcome>;
23
+ private perform;
24
+ private revealTarget;
25
+ private pointAt;
26
+ private resolveTarget;
27
+ private missingTarget;
28
+ private dispatch;
29
+ }
@@ -0,0 +1,4 @@
1
+ import type { ActionServices } from './services.ts';
2
+ import { type ResolvedTarget } from './target.ts';
3
+ import type { HandlerResult } from './types.ts';
4
+ export declare function highlight(target: ResolvedTarget, text: string | null, services: ActionServices): Promise<HandlerResult>;
@@ -0,0 +1,9 @@
1
+ import type { Fiber } from '../fiber/types.ts';
2
+ export type GuardVerdict = {
3
+ allowed: true;
4
+ } | {
5
+ allowed: false;
6
+ reason: string;
7
+ };
8
+ export declare function checkInteractable(fiber: Fiber, ancestors: Fiber[]): GuardVerdict;
9
+ export declare function checkEditable(fiber: Fiber, ancestors: Fiber[]): GuardVerdict;
@@ -0,0 +1,11 @@
1
+ import type { Rect } from '../host/rect.ts';
2
+ import type { Clock } from './settle.ts';
3
+ import type { AgentAction } from './types.ts';
4
+ export interface CursorPort {
5
+ moveTo: (measure: () => Promise<Rect | null>) => void;
6
+ whenLanded: () => Promise<void>;
7
+ }
8
+ export declare const LANDING_MAX_MS = 1800;
9
+ export declare function tapsTarget(action: AgentAction): boolean;
10
+ export declare function waitsForLanding(action: AgentAction): boolean;
11
+ export declare function waitForLanding(cursor: CursorPort, clock: Clock): Promise<void>;
@@ -0,0 +1,22 @@
1
+ import { type UnknownRecord } from '../fiber/narrow.ts';
2
+ import { type ScreenRef } from '../snapshot/navigation.ts';
3
+ import type { HandlerResult } from './types.ts';
4
+ export interface NavigationRefLike {
5
+ isReady: () => boolean;
6
+ navigate(...args: unknown[]): void;
7
+ getRootState: () => unknown;
8
+ }
9
+ export interface NavigationSources {
10
+ readFocusedScreens: () => ScreenRef[];
11
+ getNavigationRef: () => NavigationRefLike | null;
12
+ }
13
+ export declare class NavigationDriver {
14
+ private readonly sources;
15
+ constructor(sources: NavigationSources);
16
+ listRefRoutePaths(): string[];
17
+ navigateTo(route: string, params: UnknownRecord | null): HandlerResult;
18
+ private navigateAlongPath;
19
+ private collectRoutePaths;
20
+ private navigateThroughFocusedScreens;
21
+ private navigateThroughRef;
22
+ }
@@ -0,0 +1,4 @@
1
+ import { type AgentCommandData, type PageContentRequest } from './types.ts';
2
+ export declare function parsePageContentRequest(options: unknown): PageContentRequest;
3
+ export declare function parseAgentCommand(data: unknown): AgentCommandData | null;
4
+ export declare function describeUnparsedAction(data: unknown): string;
@@ -0,0 +1,4 @@
1
+ import type { ActionErrorCode, FailedResult, HandlerResult } from './types.ts';
2
+ export declare function succeeded(message?: string): HandlerResult;
3
+ export declare function failed(error: ActionErrorCode, message: string): FailedResult;
4
+ export declare function failedFromException(error: unknown): FailedResult;
@@ -0,0 +1,12 @@
1
+ import { type Band } from '../host/rect.ts';
2
+ import type { ResolvedTarget } from './target.ts';
3
+ import type { AgentAction, HandlerResult } from './types.ts';
4
+ type ScrollAction = Extract<AgentAction, {
5
+ type: 'scroll';
6
+ }>;
7
+ export declare function scrollContainer(target: ResolvedTarget, action: ScrollAction): Promise<HandlerResult>;
8
+ export declare function scrollIntoView(target: ResolvedTarget, options?: {
9
+ animated: boolean;
10
+ }): Promise<HandlerResult>;
11
+ export declare function scrollIntoBand(target: ResolvedTarget, band: Band): Promise<HandlerResult>;
12
+ export {};