@reticlehq/server 2.7.0 → 2.9.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 (357) hide show
  1. package/README.md +14 -5
  2. package/SKILL.md +130 -778
  3. package/dist/bridge/bridge.d.ts +23 -0
  4. package/dist/bridge/bridge.js +80 -2
  5. package/dist/bridge/bridge.test-harness.d.ts +5 -0
  6. package/dist/bridge/bridge.test-harness.js +6 -4
  7. package/dist/capsule/causal-summary.d.ts +36 -1
  8. package/dist/capsule/causal-summary.js +33 -7
  9. package/dist/capsule/divergence.js +7 -1
  10. package/dist/cli/chromium-hint.d.ts +33 -5
  11. package/dist/cli/chromium-hint.js +82 -12
  12. package/dist/cli/cli-doctor.js +65 -34
  13. package/dist/cli/cli-flow-commands.js +8 -8
  14. package/dist/cli/cli-kill.d.ts +58 -0
  15. package/dist/cli/cli-kill.js +162 -0
  16. package/dist/cli/cli-parse.d.ts +16 -1
  17. package/dist/cli/cli-parse.js +32 -9
  18. package/dist/cli/cli-port.d.ts +32 -0
  19. package/dist/cli/cli-port.js +82 -35
  20. package/dist/cli/cli-verify.d.ts +21 -0
  21. package/dist/cli/cli-verify.js +47 -3
  22. package/dist/cli/config-discovery.d.ts +35 -0
  23. package/dist/cli/config-discovery.js +163 -0
  24. package/dist/cli/doctor-daemon-line.js +4 -1
  25. package/dist/cli/doctor-project-line.d.ts +37 -0
  26. package/dist/cli/doctor-project-line.js +35 -0
  27. package/dist/cli/doctor-rows.d.ts +51 -0
  28. package/dist/cli/doctor-rows.js +54 -0
  29. package/dist/cli/doctor-sessions-line.d.ts +12 -0
  30. package/dist/cli/doctor-sessions-line.js +69 -0
  31. package/dist/cli/drive-attach.d.ts +99 -0
  32. package/dist/cli/drive-attach.js +203 -0
  33. package/dist/cli/drive-command.d.ts +13 -0
  34. package/dist/cli/drive-command.js +103 -0
  35. package/dist/cli/open-note.d.ts +20 -0
  36. package/dist/cli/open-note.js +37 -0
  37. package/dist/cli/port-holder.d.ts +10 -0
  38. package/dist/cli/port-holder.js +26 -2
  39. package/dist/cli/status-next-action.d.ts +37 -0
  40. package/dist/cli/status-next-action.js +61 -0
  41. package/dist/cli.js +119 -39
  42. package/dist/crawl/crawl-tools.js +12 -2
  43. package/dist/crawl/crawl.d.ts +13 -0
  44. package/dist/crawl/crawl.js +50 -2
  45. package/dist/events/contradictions.d.ts +46 -0
  46. package/dist/events/contradictions.js +35 -22
  47. package/dist/events/declared.d.ts +45 -0
  48. package/dist/events/declared.js +73 -0
  49. package/dist/events/echo-mismatch.d.ts +8 -2
  50. package/dist/events/echo-mismatch.js +33 -5
  51. package/dist/events/event-filters.d.ts +1 -1
  52. package/dist/events/event-filters.js +7 -4
  53. package/dist/events/predicate-eval.d.ts +17 -72
  54. package/dist/events/predicate-eval.js +117 -236
  55. package/dist/events/predicate-parse.js +31 -3
  56. package/dist/events/predicate-route.d.ts +32 -0
  57. package/dist/events/predicate-route.js +102 -0
  58. package/dist/events/predicate-schema.d.ts +99 -0
  59. package/dist/events/predicate-schema.js +309 -0
  60. package/dist/events/predicate.d.ts +8 -0
  61. package/dist/events/predicate.js +296 -22
  62. package/dist/flows/annotate-tools.js +3 -0
  63. package/dist/flows/annotate.js +18 -4
  64. package/dist/flows/coverage.d.ts +38 -5
  65. package/dist/flows/coverage.js +30 -4
  66. package/dist/flows/decision.d.ts +15 -0
  67. package/dist/flows/decision.js +1 -1
  68. package/dist/flows/flow-classify.js +1 -1
  69. package/dist/flows/flow-replay-run.js +8 -1
  70. package/dist/flows/flow-tools.js +21 -5
  71. package/dist/flows/heal-run.js +1 -1
  72. package/dist/flows/replay.js +3 -0
  73. package/dist/honesty/accepted-write.d.ts +3 -0
  74. package/dist/honesty/accepted-write.js +8 -3
  75. package/dist/honesty/already-true.js +15 -0
  76. package/dist/honesty/blind-spots.js +10 -2
  77. package/dist/honesty/honesty.d.ts +11 -0
  78. package/dist/honesty/honesty.js +1 -0
  79. package/dist/honesty/uncaptured-bodies.d.ts +4 -2
  80. package/dist/honesty/uncaptured-bodies.js +9 -2
  81. package/dist/honesty/unread-outcome.d.ts +8 -0
  82. package/dist/honesty/unread-outcome.js +36 -9
  83. package/dist/honesty/unsettled.d.ts +49 -0
  84. package/dist/honesty/unsettled.js +82 -0
  85. package/dist/honesty/verified.d.ts +36 -3
  86. package/dist/honesty/verified.js +54 -11
  87. package/dist/http-server.d.ts +19 -0
  88. package/dist/http-server.js +202 -4
  89. package/dist/impact/impact-recorder.d.ts +23 -0
  90. package/dist/impact/impact-recorder.js +76 -0
  91. package/dist/impact/impact-store.d.ts +47 -0
  92. package/dist/impact/impact-store.js +171 -0
  93. package/dist/index.d.ts +7 -0
  94. package/dist/index.js +47 -10
  95. package/dist/init/agent-rules.d.ts +36 -0
  96. package/dist/init/agent-rules.js +132 -22
  97. package/dist/init/astro-patch.d.ts +2 -1
  98. package/dist/init/astro-patch.js +38 -6
  99. package/dist/init/capabilities.d.ts +22 -0
  100. package/dist/init/capabilities.js +76 -0
  101. package/dist/init/confirm.d.ts +114 -0
  102. package/dist/init/confirm.js +165 -0
  103. package/dist/init/connect-steps.d.ts +2 -0
  104. package/dist/init/connect-steps.js +50 -0
  105. package/dist/init/cra.js +3 -2
  106. package/dist/init/csp-check.d.ts +38 -0
  107. package/dist/init/csp-check.js +92 -0
  108. package/dist/init/csp-doctor.d.ts +25 -0
  109. package/dist/init/csp-doctor.js +49 -0
  110. package/dist/init/cursor.js +6 -9
  111. package/dist/init/detect.d.ts +8 -0
  112. package/dist/init/detect.js +33 -3
  113. package/dist/init/mcp-clients.d.ts +1 -0
  114. package/dist/init/mcp-clients.js +51 -7
  115. package/dist/init/mcp.d.ts +15 -0
  116. package/dist/init/mcp.js +19 -0
  117. package/dist/init/non-js-project.js +29 -5
  118. package/dist/init/plan-framework.d.ts +10 -0
  119. package/dist/init/plan-framework.js +78 -16
  120. package/dist/init/plan.d.ts +47 -6
  121. package/dist/init/plan.js +228 -69
  122. package/dist/init/run.d.ts +24 -2
  123. package/dist/init/run.js +157 -45
  124. package/dist/init/slash-command.d.ts +1 -1
  125. package/dist/init/slash-command.js +54 -6
  126. package/dist/init/snippets.d.ts +45 -5
  127. package/dist/init/snippets.js +194 -42
  128. package/dist/init/vite-config.js +53 -5
  129. package/dist/input/network-mock-tools.d.ts +19 -0
  130. package/dist/input/network-mock-tools.js +37 -5
  131. package/dist/input/scroll-find.d.ts +6 -0
  132. package/dist/input/scroll-find.js +17 -2
  133. package/dist/input/scroll-tools.js +4 -0
  134. package/dist/journal/attach-journal.d.ts +9 -1
  135. package/dist/journal/attach-journal.js +13 -2
  136. package/dist/journal/journal-query.d.ts +13 -0
  137. package/dist/journal/journal-query.js +28 -3
  138. package/dist/journal/workspace-gitignore.d.ts +10 -0
  139. package/dist/journal/workspace-gitignore.js +59 -0
  140. package/dist/license/license.js +1 -1
  141. package/dist/mcp/mcp-proxy.d.ts +35 -30
  142. package/dist/mcp/mcp-proxy.js +306 -104
  143. package/dist/mcp/mcp.d.ts +10 -1
  144. package/dist/mcp/mcp.js +70 -34
  145. package/dist/mcp/proxy-handshake.d.ts +82 -1
  146. package/dist/mcp/proxy-handshake.js +109 -2
  147. package/dist/mcp/proxy-lifecycle.d.ts +11 -2
  148. package/dist/mcp/proxy-lifecycle.js +12 -3
  149. package/dist/mcp/proxy-log.d.ts +63 -0
  150. package/dist/mcp/proxy-log.js +132 -0
  151. package/dist/mcp/server-instructions.d.ts +17 -0
  152. package/dist/mcp/server-instructions.js +56 -0
  153. package/dist/mcp/shared-params.d.ts +27 -0
  154. package/dist/mcp/shared-params.js +36 -0
  155. package/dist/pool/browser-pool.d.ts +22 -2
  156. package/dist/pool/browser-pool.js +44 -4
  157. package/dist/project/learned-routes.d.ts +24 -0
  158. package/dist/project/learned-routes.js +63 -0
  159. package/dist/project/project-store.d.ts +6 -0
  160. package/dist/project/project-store.js +25 -1
  161. package/dist/project/reticle-dir.d.ts +2 -0
  162. package/dist/project/reticle-dir.js +1 -0
  163. package/dist/session/connection-memory.d.ts +59 -0
  164. package/dist/session/connection-memory.js +108 -0
  165. package/dist/session/dev-command.d.ts +26 -0
  166. package/dist/session/dev-command.js +89 -0
  167. package/dist/session/dev-server-probe.d.ts +68 -0
  168. package/dist/session/dev-server-probe.js +102 -7
  169. package/dist/session/last-act.d.ts +26 -0
  170. package/dist/session/last-act.js +35 -1
  171. package/dist/session/live-control-tools.js +42 -5
  172. package/dist/session/no-session-diagnosis.d.ts +67 -2
  173. package/dist/session/no-session-diagnosis.js +236 -27
  174. package/dist/session/no-session-next-action.d.ts +46 -0
  175. package/dist/session/no-session-next-action.js +85 -0
  176. package/dist/session/no-session-watch.d.ts +40 -1
  177. package/dist/session/no-session-watch.js +174 -8
  178. package/dist/session/pending-commands.d.ts +12 -0
  179. package/dist/session/pending-commands.js +13 -1
  180. package/dist/session/ref-provenance.d.ts +54 -0
  181. package/dist/session/ref-provenance.js +61 -0
  182. package/dist/session/session-lease.js +1 -1
  183. package/dist/session/session-manager.d.ts +4 -0
  184. package/dist/session/session-manager.js +35 -5
  185. package/dist/session/session.d.ts +10 -1
  186. package/dist/session/session.js +146 -5
  187. package/dist/telemetry/app-instrumented.d.ts +8 -0
  188. package/dist/telemetry/app-instrumented.js +10 -0
  189. package/dist/telemetry/automation-hint.d.ts +17 -0
  190. package/dist/telemetry/automation-hint.js +71 -0
  191. package/dist/telemetry/bug-found.d.ts +15 -17
  192. package/dist/telemetry/bug-found.js +52 -21
  193. package/dist/telemetry/cli-telemetry.js +7 -1
  194. package/dist/telemetry/daemon-telemetry.js +24 -0
  195. package/dist/telemetry/feedback.js +1 -1
  196. package/dist/telemetry/init-telemetry.js +9 -1
  197. package/dist/telemetry/install-source.d.ts +56 -0
  198. package/dist/telemetry/install-source.js +74 -0
  199. package/dist/telemetry/instrumentation-stall.d.ts +50 -0
  200. package/dist/telemetry/instrumentation-stall.js +90 -0
  201. package/dist/telemetry/run-telemetry.js +4 -1
  202. package/dist/telemetry/session-metrics.d.ts +8 -0
  203. package/dist/telemetry/session-metrics.js +15 -0
  204. package/dist/telemetry/telemetry.d.ts +7 -1
  205. package/dist/telemetry/telemetry.js +26 -2
  206. package/dist/telemetry/tool-refused.d.ts +19 -0
  207. package/dist/telemetry/tool-refused.js +55 -0
  208. package/dist/telemetry/verification-of.js +46 -7
  209. package/dist/temp-dir.d.ts +27 -0
  210. package/dist/temp-dir.js +46 -0
  211. package/dist/tools/act-tools.js +209 -28
  212. package/dist/tools/assert-grade.d.ts +1 -1
  213. package/dist/tools/assert-grade.js +27 -5
  214. package/dist/tools/assert-verdict.js +49 -7
  215. package/dist/tools/browser-tools.js +10 -0
  216. package/dist/tools/contract-tools.js +4 -0
  217. package/dist/tools/dynamic-tools.js +16 -7
  218. package/dist/tools/error-recovery.d.ts +10 -0
  219. package/dist/tools/error-recovery.js +73 -9
  220. package/dist/tools/feedback-invite.js +1 -1
  221. package/dist/tools/invoke-tool.js +159 -26
  222. package/dist/tools/lease-hint.d.ts +30 -8
  223. package/dist/tools/lease-hint.js +65 -14
  224. package/dist/tools/lease-tools.d.ts +40 -1
  225. package/dist/tools/lease-tools.js +181 -83
  226. package/dist/tools/navigate-result.js +1 -1
  227. package/dist/tools/observe-tools.js +10 -4
  228. package/dist/tools/observed-nothing.js +1 -1
  229. package/dist/tools/react-grace.d.ts +52 -0
  230. package/dist/tools/react-grace.js +90 -0
  231. package/dist/tools/read-tools.js +67 -5
  232. package/dist/tools/resolve-target.d.ts +33 -0
  233. package/dist/tools/resolve-target.js +53 -0
  234. package/dist/tools/settle-in-flight.d.ts +94 -0
  235. package/dist/tools/settle-in-flight.js +146 -0
  236. package/dist/tools/snapshot-delta.d.ts +10 -0
  237. package/dist/tools/snapshot-delta.js +194 -9
  238. package/dist/tools/tool-kit.d.ts +8 -0
  239. package/dist/tools/tool-surface.d.ts +60 -0
  240. package/dist/tools/tool-surface.js +86 -1
  241. package/dist/tools/tools.js +61 -8
  242. package/dist/tools/unadvertised-help.js +9 -6
  243. package/docs/README.md +55 -11
  244. package/docs/actions.mdx +120 -0
  245. package/docs/agent-cheatsheet.md +95 -29
  246. package/docs/architecture.md +52 -35
  247. package/docs/benchmarks.md +127 -75
  248. package/docs/best-practices.mdx +216 -0
  249. package/docs/capabilities.mdx +534 -0
  250. package/docs/cli/affected.mdx +53 -0
  251. package/docs/cli/capsules.mdx +70 -0
  252. package/docs/cli/cloud.mdx +153 -0
  253. package/docs/cli/doctor.mdx +109 -0
  254. package/docs/cli/drive.mdx +74 -0
  255. package/docs/cli/feedback.mdx +67 -0
  256. package/docs/cli/gate.mdx +64 -0
  257. package/docs/cli/help.mdx +94 -0
  258. package/docs/cli/hunt.mdx +73 -0
  259. package/docs/cli/identify.mdx +76 -0
  260. package/docs/cli/init.mdx +121 -0
  261. package/docs/cli/kill.mdx +91 -0
  262. package/docs/cli/license.mdx +48 -0
  263. package/docs/cli/mcp.mdx +61 -0
  264. package/docs/cli/open.mdx +74 -0
  265. package/docs/cli/restart.mdx +60 -0
  266. package/docs/cli/rollback.mdx +35 -0
  267. package/docs/cli/serve.mdx +69 -0
  268. package/docs/cli/status.mdx +88 -0
  269. package/docs/cli/stop.mdx +64 -0
  270. package/docs/cli/telemetry.mdx +57 -0
  271. package/docs/cli/update.mdx +52 -0
  272. package/docs/cli/verify.mdx +76 -0
  273. package/docs/cli/version.mdx +39 -0
  274. package/docs/cli/watch.mdx +62 -0
  275. package/docs/cli.mdx +241 -0
  276. package/docs/debugging.md +16 -10
  277. package/docs/deploy-checks.md +45 -12
  278. package/docs/desktop.mdx +384 -0
  279. package/docs/docs.json +364 -0
  280. package/docs/enterprise.md +22 -16
  281. package/docs/faq.mdx +102 -0
  282. package/docs/fixtures.md +13 -7
  283. package/docs/flows.md +29 -23
  284. package/docs/for-agents.md +71 -0
  285. package/docs/frameworks.mdx +238 -0
  286. package/docs/gate-plan.md +48 -42
  287. package/docs/gates.md +28 -22
  288. package/docs/getting-started.md +129 -77
  289. package/docs/human-control.md +24 -18
  290. package/docs/index.mdx +143 -0
  291. package/docs/install-agentic.mdx +224 -0
  292. package/docs/install-manual.mdx +196 -0
  293. package/docs/instrumentation.mdx +238 -0
  294. package/docs/integration-patterns.md +41 -35
  295. package/docs/local-registry.md +19 -13
  296. package/docs/multi-agent-testing.md +19 -13
  297. package/docs/packages/babel-plugin.mdx +79 -0
  298. package/docs/packages/browser.mdx +111 -0
  299. package/docs/packages/core.mdx +116 -0
  300. package/docs/packages/electron.mdx +85 -0
  301. package/docs/packages/eslint-plugin.mdx +86 -0
  302. package/docs/packages/next.mdx +89 -0
  303. package/docs/packages/react.mdx +91 -0
  304. package/docs/packages/server.mdx +98 -0
  305. package/docs/packages/tauri.mdx +63 -0
  306. package/docs/packages/test.mdx +119 -0
  307. package/docs/packages/vite-plugin.mdx +94 -0
  308. package/docs/packages.mdx +218 -0
  309. package/docs/platform-integration.md +35 -26
  310. package/docs/predicates.mdx +248 -0
  311. package/docs/quickstart.mdx +257 -0
  312. package/docs/recipes.mdx +282 -0
  313. package/docs/skill-file.mdx +107 -0
  314. package/docs/state-management.mdx +199 -0
  315. package/docs/style.css +14 -0
  316. package/docs/system-map.md +50 -33
  317. package/docs/telemetry-contract.md +106 -52
  318. package/docs/telemetry-events.mdx +475 -0
  319. package/docs/telemetry.md +63 -55
  320. package/docs/testing.md +44 -6
  321. package/docs/token-efficiency.md +37 -27
  322. package/docs/tools-act-and-wait.mdx +173 -0
  323. package/docs/tools-act-sequence.mdx +137 -0
  324. package/docs/tools-act.mdx +95 -0
  325. package/docs/tools-assert.mdx +129 -0
  326. package/docs/tools-console.mdx +63 -0
  327. package/docs/tools-inspect.mdx +88 -0
  328. package/docs/tools-navigate.mdx +99 -0
  329. package/docs/tools-network.mdx +119 -0
  330. package/docs/tools-observe.mdx +145 -0
  331. package/docs/tools-overview.mdx +160 -0
  332. package/docs/tools-query.mdx +126 -0
  333. package/docs/tools-session-and-feedback.mdx +112 -0
  334. package/docs/tools-sessions.mdx +94 -0
  335. package/docs/tools-snapshot.mdx +129 -0
  336. package/docs/tools-state.mdx +104 -0
  337. package/docs/tools-tools-and-run.mdx +156 -0
  338. package/docs/tools-wait-for.mdx +85 -0
  339. package/docs/troubleshooting.mdx +263 -0
  340. package/docs/usage.md +209 -165
  341. package/docs/vs-chrome-devtools-mcp.mdx +123 -0
  342. package/docs/vs-playwright-mcp.mdx +125 -0
  343. package/docs/vs-screenshots.mdx +137 -0
  344. package/docs/what-is-reticle.mdx +63 -0
  345. package/docs/why-reticle.mdx +109 -0
  346. package/package.json +5 -5
  347. package/docs/desktop-apps.md +0 -256
  348. package/docs/matrix/2.5.0/claude-code-machine.json +0 -19
  349. package/docs/matrix/2.5.0/codex-machine.json +0 -20
  350. package/docs/matrix/2.5.0/cursor-machine.json +0 -22
  351. package/docs/matrix/2.5.0/gemini-machine.json +0 -22
  352. package/docs/matrix/2.5.0/opencode-machine.json +0 -22
  353. package/docs/matrix/2.5.0/vscode-machine.json +0 -22
  354. package/docs/matrix/2.5.0/windsurf-machine.json +0 -22
  355. package/docs/matrix/MATRIX.md +0 -26
  356. package/docs/matrix/README.md +0 -59
  357. package/docs/mint.json +0 -61
@@ -0,0 +1,98 @@
1
+ ---
2
+ title: '@reticlehq/server'
3
+ description: The Reticle bridge, MCP server, and the reticle CLI, all in one Node package.
4
+ icon: server
5
+ ---
6
+
7
+ `@reticlehq/server` is the Reticle bridge, MCP server and CLI in one Node package. It hosts the WebSocket your app dials into, exposes the MCP tools your agent calls, and ships the `reticle` binary. **You do not add it to your project**: your agent runs it with `npx @reticlehq/server mcp`.
8
+
9
+ **Licensed under `SEE LICENSE IN LICENSE`, not Apache 2.0 like the rest.** This is the package the enterprise terms apply to.
10
+
11
+ ## Why it exists
12
+
13
+ Agents speak MCP. Browsers speak WebSocket. Somebody has to be fluent in both, and own the `.reticle/` directory where flows, baselines, capsules and runs are stored. It never imports a DOM API.
14
+
15
+ ## Do you install it?
16
+
17
+ Not into your project. Your agent launches it:
18
+
19
+ ```bash
20
+ npx @reticlehq/server mcp
21
+ ```
22
+
23
+ The `bin` entry is `reticle`, so `npx @reticlehq/server <command>` works once it is on disk.
24
+
25
+ ## Dependencies
26
+
27
+ **Runtime:** `@modelcontextprotocol/sdk`, `@reticlehq/core`, `ws`, `zod`.
28
+
29
+ **Optional:** `playwright`, `pixelmatch`, `pngjs`. Optional on purpose: Reticle observes the browser you already have. You only need Playwright for the paths that launch or diff one, which is `reticle drive`, `reticle verify`, and visual baselines.
30
+
31
+ ## Exports map
32
+
33
+ | Subpath | What it is |
34
+ | ------- | -------------------------------------------------------------------------------------- |
35
+ | `.` | The programmatic API |
36
+ | `./cli` | The CLI entry, which also exports `parseCliArgs`, `CLI_USAGE` and the `CliResult` type |
37
+
38
+ ## Starting a server in process
39
+
40
+ ```ts
41
+ import { start, startDaemon, type StartOptions, type RunningServer } from '@reticlehq/server';
42
+
43
+ const server: RunningServer = await start({ port: 4400, headless: true });
44
+ await server.close();
45
+ ```
46
+
47
+ `start(options?: StartOptions): Promise<RunningServer>` boots the bridge plus the MCP stdio transport. `startDaemon(options?: StartOptions): Promise<RunningServer>` is what the detached daemon runs.
48
+
49
+ ### `StartOptions`
50
+
51
+ | Option | Type | Default |
52
+ | --- | --- | --- |
53
+ | `port` | `number` | `RETICLE_PORT`, else `4400` |
54
+ | `host` | `string` | `RETICLE_HOST`, else loopback. A non-loopback host requires a token |
55
+ | `token` | `string` | `RETICLE_TOKEN` |
56
+ | `allowedOrigins` | `string[]` | `RETICLE_ALLOWED_ORIGINS` |
57
+ | `mcp` | `boolean` | `true`. `false` skips the stdio transport |
58
+ | `cdpUrl` | `string` | `RETICLE_CDP_URL`. Attach to a running browser instead of launching one |
59
+ | `driveUrl` | `string` | unset |
60
+ | `headless` | `boolean` | `true` |
61
+ | `realInputFactory` | `(opts) => OwnedRealInputProvider` | built in |
62
+ | `injectConnect` | `InjectConnectOptions` | unset |
63
+ | `storageState` | `string` | unset |
64
+ | `reticleRoot` | `string` | `cwd()/.reticle` |
65
+ | `pairingTokenDir` | `string` | `~/.reticle` |
66
+ | `now` | `() => number` | `Date.now` |
67
+ | `toolProfile` | `string` | `RETICLE_TOOL_PROFILE`, else `full`. `core` serves the lean surface |
68
+ | `httpVerify` | `boolean` | `false` |
69
+ | `httpVerifyPort` | `number` | `RETICLE_VERIFY_DEFAULT_PORT` (`7331`) |
70
+ | `httpVerifyToken` | `string` | `RETICLE_VERIFY_TOKEN` |
71
+
72
+ ### `RunningServer`
73
+
74
+ `bridge: Bridge`, `close(): Promise<void>`, and the optional `realInput`, `verifyPort`, `isIdle()`, `agentAttached()`, `token`.
75
+
76
+ ## What else the barrel exports
77
+
78
+ A large surface, because the test runner and the CI paths are built on it. The families:
79
+
80
+ | Family | Representative exports |
81
+ | --- | --- |
82
+ | Tools | `TOOLS`, `ReticleTool`, `runTool`, `createToolInvoker`, `filterTools`, `resolveToolSurface`, `CORE_TOOL_NAMES`, `SESSION_BOUND_TOOLS`, `SESSION_EXEMPT_TOOLS` |
83
+ | Bridge and sessions | `Bridge`, `Session`, `SessionManager`, `RingBuffer`, `resolveBridgeSecurity`, `buildSessionRecommendation` |
84
+ | Stores on disk | `FlowStore`, `BaselineStore`, `VisualStore`, `RecordingStore`, `RunStore`, `ProjectStore`, `AnnotationStore`, `createNodeFileSystem`, `reticleDirPaths`, `readContract`, `writeContract` |
85
+ | Flow replay | `replayFlow`, `assertSuccess`, `successToPredicate`, `classifyFlowAssertions`, `FlowAssertionGrade`, `nearestTestid` |
86
+ | Runs and CI | `ReticleRunner`, `buildVerificationRun`, `computeVerdict`, `renderRunReport`, `buildRepairPacket`, `classifyChangedFiles`, `buildRisks`, `redactForProfile` |
87
+ | HTTP verify | `handleVerifyRequest`, `createVerifyRequestListener`, `startVerifyServer`, `VERIFY_PATH`, `TOKEN_HEADER`, `tokenOk` |
88
+ | Predicates | `evaluatePredicate`, `waitForPredicate`, `PredicateSchema`, `buildReactionReport` |
89
+ | Browser pool | `BrowserPool`, `playwrightLauncher`, `resolveMaxContexts`, `DEFAULT_LEASE_TTL_MS` |
90
+ | Real input | `CdpRealInputProvider`, `LaunchedRealInputProvider`, `performGesture`, `boxCenter`, `isPointerAction`, `DriveError` |
91
+ | Daemon lifecycle | `writePid`, `readPid`, `removePid`, `isRunning`, `isAlive`, `logPath`, `classifyDaemonLife`, `DAEMON_HEARTBEAT_MS` |
92
+ | Crawl and scroll | `crawl`, `scrollToFind` |
93
+ | Visual | `diffPng` |
94
+ | Domain model | `buildDomainModel` |
95
+
96
+ <Card title="Every CLI command" icon="terminal" href="/cli">
97
+ The commands this package installs, one page each.
98
+ </Card>
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: 'reticle-tauri'
3
+ description: The Rust crate that gives a Tauri app Reticle screenshots and headless mode.
4
+ icon: rust
5
+ ---
6
+
7
+ `reticle-tauri` is a Rust crate on crates.io, not an npm package. You need it only if your Tauri app should answer `reticle_screenshot`, or run headless in CI. Everything else about a Tauri app, including IPC observation, works without it.
8
+
9
+ It is versioned **independently** of the ten npm packages. **MIT licensed, unlike the Apache 2.0 npm packages. Edition 2021.**
10
+
11
+ ## Why it exists, and why it is small
12
+
13
+ Tauri IPC observation needs nothing on the Rust side. An `invoke('load_todos')` already reaches Reticle as `ipc://load_todos` through the SDK in the webview. You only need this crate for two things: screenshots, and headless mode.
14
+
15
+ <Warning>
16
+ Do not expect this to match the npm version. Doing so would imply a release cadence the crate does
17
+ not have, and it would make every npm release a crates.io release for no reason.
18
+ </Warning>
19
+
20
+ ## Install
21
+
22
+ ```toml
23
+ [dependencies]
24
+ reticle-tauri = "0.1"
25
+ ```
26
+
27
+ Its own dependencies are `tauri = "2"` plus the per-platform capture backends: `objc2` and friends on macOS, `webview2-com` and `windows` on Windows, `webkit2gtk` and `cairo-rs` on Linux and the BSDs.
28
+
29
+ ## Wiring
30
+
31
+ ```rust
32
+ tauri::Builder::default()
33
+ .invoke_handler(tauri::generate_handler![reticle_tauri::reticle_capture])
34
+ .on_page_load(reticle_tauri::on_page_load)
35
+ ```
36
+
37
+ Nothing is needed on the JavaScript side. Tauri has no preload stage, so the SDK reaches `reticle_capture` through Tauri's own internals.
38
+
39
+ ## The public API
40
+
41
+ | Item | Signature |
42
+ | --- | --- |
43
+ | `reticle_capture` | `#[tauri::command] pub async fn reticle_capture(window: tauri::WebviewWindow, full_page: Option<bool>) -> Result<String, String>` |
44
+ | `on_page_load` | `pub fn on_page_load<R: Runtime>(webview: &Webview<R>, payload: &tauri::webview::PageLoadPayload<'_>)` |
45
+ | `FULL_PAGE_UNSUPPORTED` | `pub const FULL_PAGE_UNSUPPORTED: &str = "full-page-unsupported"` |
46
+
47
+ There are no public traits and no macros.
48
+
49
+ ### `reticle_capture`
50
+
51
+ Runs on a blocking thread, writes a PNG into a per-process `0700` directory under the OS temp dir as `reticle-capture-<nanos>.png`, and returns the **path**, not the bytes. Full-page capture is supported on Linux only; elsewhere it returns `FULL_PAGE_UNSUPPORTED`, which is pinned to core's `VisualReason` value so the refusal is the same string everywhere.
52
+
53
+ ### `on_page_load`
54
+
55
+ Hides the window on `PageLoadEvent::Finished` when the environment variable `RETICLE_HEADLESS=1` is set. That ordering matters: the window exists and renders, then it is hidden, so the capture path still works.
56
+
57
+ ## The silent failure to know about
58
+
59
+ A Tauri app with the default CSP runs perfectly and never connects to Reticle, with nothing said anywhere. [`reticle doctor`](/cli/doctor) diagnoses this explicitly on a desktop project, because it is invisible otherwise.
60
+
61
+ <Card title="Desktop setup in full" icon="display" href="/desktop">
62
+ The CSP entry, the headless flag, and how capture differs from a browser screenshot.
63
+ </Card>
@@ -0,0 +1,119 @@
1
+ ---
2
+ title: '@reticlehq/test'
3
+ description: The Reticle spec runner for CI, driving the tools directly with no MCP or stdio in the loop.
4
+ icon: vial
5
+ ---
6
+
7
+ `@reticlehq/test` is Reticle's spec runner for CI. It turns an interactive session into a suite that runs on every pull request, without an agent and without paying model tokens to re-derive the same checks. Install it when you want unattended verification; skip it if you only ever drive Reticle interactively through MCP.
8
+
9
+ **Licensed under `SEE LICENSE IN LICENSE`. Depends on `@reticlehq/core` and `@reticlehq/server`. Optional peer dependency: `vitest ^3.2.6`.**
10
+
11
+ ```bash
12
+ npm i -D @reticlehq/test
13
+ ```
14
+
15
+ ## Why it exists
16
+
17
+ Driving interactively is reconnaissance. At some point you want the same checks to run unattended. This package invokes the tool layer directly, so a spec is the same evidence an agent would have gathered, minus the model.
18
+
19
+ ## Booting a session
20
+
21
+ ```ts
22
+ import { bootSession, createTestContext, runSpecs, printSummary } from '@reticlehq/test';
23
+
24
+ const run = await bootSession({ driveUrl: 'http://localhost:5173' });
25
+ const { results, summary } = await runSpecs({
26
+ invoke: run.invoke,
27
+ buildContext: (invoke) => createTestContext(invoke),
28
+ now: () => Date.now(),
29
+ });
30
+ printSummary(summary, results, (line) => process.stdout.write(`${line}\n`));
31
+ await run.close();
32
+ ```
33
+
34
+ ### `BootOptions`
35
+
36
+ | Option | Type | Default |
37
+ | ------------- | ------------------------------------- | ----------------------- |
38
+ | `driveUrl` | `string` | required |
39
+ | `headless` | `boolean` | `true` |
40
+ | `port` | `number` | the default bridge port |
41
+ | `reticleRoot` | `string` | `cwd()/.reticle` |
42
+ | `now` | `() => number` | `Date.now` |
43
+ | `buildDeps` | `(server: RunningServer) => ToolDeps` | built in |
44
+
45
+ `bootSession` resolves to `BootedRun`: `{ invoke: ToolInvoker; close: () => Promise<void> }`.
46
+
47
+ ## Writing specs
48
+
49
+ ```ts
50
+ import { reticleTest, type TestContext } from '@reticlehq/test';
51
+
52
+ reticleTest('login grants a session', async (spec) => {
53
+ const t = spec as TestContext;
54
+ await t.fill('email', 'user@example.com');
55
+ await t.fill('password', 'hunter2');
56
+ await t.actAndWait('login-submit', 'click', { kind: 'signal', name: 'auth:granted' });
57
+ await t.expectNet('POST', '/api/session', 200);
58
+ await t.expectNoConsoleErrors();
59
+ });
60
+ ```
61
+
62
+ `reticleTest(name: string, fn: SpecFn): void` registers into a module-level registry. `register`, `getRegistered` and `clearRegistry` are exported for anyone driving it themselves.
63
+
64
+ <Note>
65
+ `SpecFn` types its argument as `SpecContext`, which declares only `invoke`. The runner actually
66
+ hands the spec whatever `buildContext` returned, which is a `TestContext`. In plain JavaScript
67
+ this is invisible; in TypeScript you get `Property 'fill' does not exist on type 'SpecContext'`
68
+ unless you narrow it as above.
69
+ </Note>
70
+
71
+ ## The test context
72
+
73
+ `createTestContext(invoke: ToolInvoker, options?: TestContextOptions): TestContext`, where `TestContextOptions` is `{ sessionId?: string; defaultTimeoutMs?: number }` and the timeout defaults to `DEFAULT_ASSERT_TIMEOUT_MS`.
74
+
75
+ | Method | Signature |
76
+ | --- | --- |
77
+ | `act` | `(testid: string, action: ActionType, args?: Record<string, unknown>) => Promise<void>` |
78
+ | `fill` | `(testid: string, value: string) => Promise<void>` |
79
+ | `actAndWait` | `(testid: string, action: ActionType, until: Predicate) => Promise<void>` |
80
+ | `expectSignal` | `(name: string, dataMatches?: Record<string, unknown>) => Promise<void>` |
81
+ | `expectNet` | `(method: string, urlContains: string, status?: number) => Promise<void>` |
82
+ | `expectElement` | `(query: ElementQuery, state?: ElementState) => Promise<void>` |
83
+ | `expectText` | `(contains: string) => Promise<void>` |
84
+ | `expectAbsent` | `(query: ElementQuery) => Promise<void>` |
85
+ | `expectNoConsoleErrors` | `() => Promise<void>` |
86
+ | `state` | `(storeOrRef: string) => Promise<unknown>` |
87
+ | `expectInputModeReal` | `() => Promise<void>` |
88
+ | `invoke` | The raw `ToolInvoker` |
89
+ | `clock` | `TestClock` |
90
+
91
+ ## Running and reporting
92
+
93
+ | Export | Signature |
94
+ | --- | --- |
95
+ | `runOne` | `(spec: ReticleSpec, opts: RunnerOptions) => Promise<SpecResult>` |
96
+ | `runSpecs` | `(opts: RunnerOptions) => Promise<{ results: SpecResult[]; summary: RunSummary }>` |
97
+ | `summarize` | `(results: readonly SpecResult[]) => RunSummary` |
98
+ | `printSummary` | `(summary: RunSummary, results: readonly SpecResult[], print: (line: string) => void) => void`. The sink is injected, never `console` |
99
+ | `toJUnitXml` / `writeJUnit` | JUnit output for CI |
100
+
101
+ `RunnerOptions` is `{ invoke; buildContext; now; print?; specs? }`. `RunSummary` is `{ total, passed, failed, skipped, ok }`.
102
+
103
+ ## Saved flows as specs
104
+
105
+ A recorded flow becomes a spec without being rewritten:
106
+
107
+ `flowToSpec`, `flowsAsSpecs`, `registerFlowSpecs`, with `assertSuccess`, `successToPredicate`, and the `FlowSpec`, `FlowSpecOptions` and `FlowsAsSpecsOptions` types. Malformed flows raise `FlowMalformedError`.
108
+
109
+ ## Errors and control flow
110
+
111
+ `ReticleSkip` and `isSkip` for skipping, `ReticleAssertionError` with an `AssertionDetail`, `ReticleQueryEmptyError` when a query matched nothing.
112
+
113
+ Constants: `TestStatus`, `SpecKind`, `SpecOutcome`, `SpecMessage`, `PredicateKind`, `STATUS_GLYPH`, `SUMMARY_FOOTER_PREFIX`, `JUnit`, `DEFAULT_JUNIT_SUITE_NAME`, `SKIP_REASON_REAL_INPUT`, `PROBE_TESTID`, `FLOW_LOAD_ERROR_PREFIX`, `DEFAULT_ASSERT_TIMEOUT_MS`.
114
+
115
+ Also exported: `resolveTestid`, and the standalone `expectInputModeReal`, `InputModeTracker` and `readInputMode`.
116
+
117
+ <Card title="Turning a session into a suite" icon="flask" href="/testing">
118
+ Writing specs that bind to signals rather than DOM structure.
119
+ </Card>
@@ -0,0 +1,94 @@
1
+ ---
2
+ title: '@reticlehq/vite-plugin'
3
+ description: One line in vite.config.ts that stamps source locations on your JSX and auto-injects reticle.connect().
4
+ icon: bolt
5
+ ---
6
+
7
+ `@reticlehq/vite-plugin` is one line in `vite.config.ts` that does the two things everyone forgets: injecting `reticle.connect()` and enabling source mapping. Install it if your app builds with Vite. On Next.js use [`@reticlehq/next`](/packages/next) instead; on any other bundler, wire [`@reticlehq/browser`](/packages/browser) by hand.
8
+
9
+ **Apache 2.0. Depends on `@babel/core`, `@reticlehq/babel-plugin` and `@reticlehq/core`. Optional peer dependency: `vite >= 4`.**
10
+
11
+ ## Install and use
12
+
13
+ ```bash
14
+ npm i -D @reticlehq/vite-plugin @reticlehq/react
15
+ ```
16
+
17
+ ```ts
18
+ import { defineConfig } from 'vite';
19
+ import react from '@vitejs/plugin-react';
20
+ import { reticle } from '@reticlehq/vite-plugin';
21
+
22
+ export default defineConfig({
23
+ plugins: [reticle(), react()],
24
+ });
25
+ ```
26
+
27
+ <Warning>
28
+ The import specifier is `@reticlehq/vite-plugin` and the export is `reticle`. An old README
29
+ documented `@reticlehq/core/vite`; that subpath has never existed in core's exports map, and `npx
30
+ @reticlehq/core init` is not a command either. The binary is `reticle`, from
31
+ [`@reticlehq/server`](/packages/server).
32
+ </Warning>
33
+
34
+ ## Why it exists
35
+
36
+ `apply: 'serve'` means it never reaches a production build. That is the guarantee that lets you leave it in the config permanently: there is no way to ship Reticle to your users by forgetting to remove a line.
37
+
38
+ ## What it injects
39
+
40
+ A virtual module at `/@reticle-connect`, added to the HTML, whose contents are:
41
+
42
+ ```ts
43
+ import { reticle, install } from '@reticlehq/react';
44
+ install();
45
+ reticle.connect({/* resolved args */});
46
+ ```
47
+
48
+ Plus a dynamic import of your dev module if one exists. It looks for `src/reticle-dev.ts`, `.js`, `.tsx` or `.jsx`, in that order, and leaves the file alone if you have one: that file is yours to edit.
49
+
50
+ ## Options
51
+
52
+ `reticle(options?: ReticleVitePluginOptions): ReticleVitePlugin`. Every option is optional.
53
+
54
+ | Option | Type | Default |
55
+ | --- | --- | --- |
56
+ | `port` | `number` | Discovered from the daemon registry for this project, falling back to `4400` |
57
+ | `root` | `string` | Vite's `root`, else `process.cwd()` |
58
+ | `sdkVersion` | `string` | Read from the installed `@reticlehq/react` |
59
+ | `session` | `string` | Omitted, so the SDK generates one |
60
+ | `projectId` | `string` | Derived from the package name plus the root path |
61
+ | `token` | `string` | `readPairingToken()`, from `~/.reticle/pairing-token` |
62
+ | `sourceMapping` | `boolean` | `true`. Set `false` to skip the Babel pass |
63
+ | `inject` | `boolean` | `true`. Set `false` to call `connect()` yourself |
64
+ | `desktop` | `boolean` | `false`. When `true` the plugin also applies to `vite build` and passes `allowInProduction: true`, which is what an Electron or Tauri renderer needs |
65
+ | `captureNetworkBodies` | `boolean` | `false`. Also enabled by `VITE_RETICLE_CAPTURE_BODIES=1` |
66
+ | `onWarn` | `(message: string) => void` | `console.warn` |
67
+
68
+ ## Other exports
69
+
70
+ | Export | Type | What it is |
71
+ | --- | --- | --- |
72
+ | `RETICLE_VITE_PLUGIN_NAME` | `'reticle'` | The plugin name |
73
+ | `RETICLE_TOKEN_GLOBAL` | `'__RETICLE_TOKEN__'` | The global the token is stamped onto |
74
+ | `RETICLE_CONNECT_MODULE` | `'/@reticle-connect'` | The virtual module id |
75
+ | `RENDER_PREHOOK_SOURCE` | `string` | The inline render prehook snippet |
76
+ | `RETICLE_DEV_MODULE_CANDIDATES` | readonly tuple | The four dev-module paths it looks for |
77
+ | `readPairingToken` | `() => string \| undefined` | Read the pairing token from disk |
78
+ | `findDevModule` | `(root: string, exists: (p: string) => boolean) => string \| null` | Locate the dev module |
79
+ | `connectModuleSource` | `(options: ReticleVitePluginOptions, devModule?: string \| null) => string` | Build the injected module source |
80
+ | `cjsDepIncludes` | `(appRoot: string, canResolve?: (dep: string) => boolean) => string[]` | CommonJS deps to add to `optimizeDeps` |
81
+
82
+ Types: `ReticleVitePluginOptions`, `ReticleVitePlugin`, `ViteDevServerLike`.
83
+
84
+ ## Desktop
85
+
86
+ ```ts
87
+ reticle({ desktop: true });
88
+ ```
89
+
90
+ A packaged Electron or Tauri renderer is a production build loaded from a custom protocol, so the default guards would refuse. This one flag drops `apply: 'serve'` and opts the connect call into production.
91
+
92
+ <Card title="Desktop wiring in full" icon="display" href="/desktop">
93
+ Including the Tauri CSP whose failure is completely silent.
94
+ </Card>
@@ -0,0 +1,218 @@
1
+ ---
2
+ title: 'Packages: what is in the box'
3
+ sidebarTitle: Packages
4
+ description: Every Reticle package. What it does, why it exists, when you actually need it, and what it depends on.
5
+ icon: cubes
6
+ ---
7
+
8
+ Reticle is eleven packages, and most people install two. This page exists so you can tell which two, and so that the ones you skip stop looking mysterious.
9
+
10
+ <Note>
11
+ The ten npm packages ship together at one version: whatever `npm view @reticlehq/core version`
12
+ says, every other `@reticlehq/*` package says too. The Rust crate `reticle-tauri` is versioned
13
+ **independently**. That is deliberate, not drift.
14
+ </Note>
15
+
16
+ ## Which ones do I need?
17
+
18
+ <CardGroup cols={2}>
19
+ <Card title="A React app on Vite" icon="bolt">
20
+ `@reticlehq/react` + `@reticlehq/vite-plugin`. That's it, two dev dependencies.
21
+ </Card>
22
+ <Card title="A React app on Next.js" icon="n">
23
+ `@reticlehq/react` + `@reticlehq/next`. Keeps SWC; no Babel migration.
24
+ </Card>
25
+ <Card title="Not React, or no bundler plugin" icon="code">
26
+ `@reticlehq/browser` alone, and call `connect()` yourself.
27
+ </Card>
28
+ <Card title="Electron or Tauri" icon="display">
29
+ The web packages, plus `@reticlehq/electron` or the `reticle-tauri` crate.
30
+ </Card>
31
+ </CardGroup>
32
+
33
+ You never install `@reticlehq/server`. Your agent runs it with `npx`.
34
+
35
+ ## The architecture in one rule
36
+
37
+ The package split is not cosmetic. Each boundary enforces something:
38
+
39
+ | Package | Runs in | Hard rule |
40
+ | --------- | ----------- | ------------------------------------------------------ |
41
+ | `core` | both | Depends only on `zod`. Sits at the bottom of the graph |
42
+ | `browser` | the browser | Never imports a Node API |
43
+ | `server` | Node | Never imports a DOM API |
44
+ | `react` | the browser | Optional. Core must work without it |
45
+
46
+ Those rules are why the browser SDK cannot accidentally pull in a filesystem call, and why the server cannot accidentally depend on `window`. They are enforced by the dependency graph, not by discipline.
47
+
48
+ ---
49
+
50
+ ## @reticlehq/core
51
+
52
+ **The wire contract.** Every constant and zod schema that crosses a boundary. Browser to bridge, bridge to agent, is defined here.
53
+
54
+ **Why it exists:** without one shared definition, the browser and the server drift. One renames a field, the other keeps reading the old one, and the failure is silent. A verdict that quietly stops carrying evidence. Core makes that a type error instead.
55
+
56
+ **Depends on:** `zod`, and nothing else. That is the whole point; it sits at the bottom of the graph so everything can depend on it without cycles.
57
+
58
+ **Do you install it?** No. It arrives as a dependency of whatever you did install.
59
+
60
+ <Note>
61
+ Before 2.0, `@reticlehq/core` was an umbrella package re-exporting everything under subpaths. That
62
+ was retired: the umbrella meant every consumer pulled the whole world to get one constant.
63
+ </Note>
64
+
65
+ ---
66
+
67
+ ## @reticlehq/browser
68
+
69
+ **The SDK that lives in your page.** It installs the observers (DOM, network, console, routing, animations), builds semantic snapshots, executes actions, and talks to the bridge.
70
+
71
+ **Why it exists:** this is the part that makes Reticle different from a browser-automation tool. Because it runs _inside_ the app rather than driving it from outside, it can see a state mutation and a fired signal, not just a rendered pixel.
72
+
73
+ **Depends on:** `@reticlehq/core`, `@testing-library/dom`. The latter is why [`reticle_query`](/tools-query) speaks role, label and testid rather than CSS selectors.
74
+
75
+ **Install it directly when** you are not on React, or you want `connect()` under your own control:
76
+
77
+ ```ts
78
+ import { reticle } from '@reticlehq/browser';
79
+ if (import.meta.env.DEV) reticle.connect();
80
+ ```
81
+
82
+ ---
83
+
84
+ ## @reticlehq/server
85
+
86
+ **The bridge, the MCP server, and the `reticle` CLI.** Hosts the WebSocket your app dials into and exposes the tools your agent calls.
87
+
88
+ **Why it exists:** agents speak MCP; browsers speak WebSocket; somebody has to be fluent in both and own the `.reticle/` directory where flows, baselines and runs are stored.
89
+
90
+ **Depends on:** `@modelcontextprotocol/sdk`, `@reticlehq/core`, `ws`, `zod`.
91
+
92
+ **Do you install it?** Not into your project. Your agent launches it:
93
+
94
+ ```bash
95
+ npx @reticlehq/server mcp
96
+ ```
97
+
98
+ ---
99
+
100
+ ## @reticlehq/react
101
+
102
+ **The kit most React users install.** It re-exports the browser sensor, so one install gives you `reticle`, `registerCapabilities` and everything else, and it maps a DOM node to its React component and source file through the fiber tree.
103
+
104
+ **Why it exists:** this is the package that turns "the button is broken" into `src/components/Login.tsx:81`. Finding a bug is half the job. Reticle's answer to the other half lives here.
105
+
106
+ **Depends on:** `@reticlehq/browser`, `@reticlehq/core`. **Peer:** `react`.
107
+
108
+ ```bash
109
+ npm i -D @reticlehq/react
110
+ ```
111
+
112
+ ---
113
+
114
+ ## @reticlehq/vite-plugin
115
+
116
+ **One line in `vite.config.ts`, two jobs.** It stamps source locations onto your JSX and injects `connect()` so you cannot forget to.
117
+
118
+ **Why it exists:** the two things everyone forgets are wiring the SDK and enabling source mapping. This does both, and `apply: 'serve'` guarantees it never reaches a production build.
119
+
120
+ **Depends on:** `@babel/core`, `@reticlehq/babel-plugin`, `@reticlehq/core`. **Peer:** `vite`.
121
+
122
+ ```ts
123
+ import { defineConfig } from 'vite';
124
+ import react from '@vitejs/plugin-react';
125
+ import { reticle } from '@reticlehq/vite-plugin';
126
+
127
+ export default defineConfig({ plugins: [reticle(), react()] });
128
+ ```
129
+
130
+ ---
131
+
132
+ ## @reticlehq/babel-plugin
133
+
134
+ **Stamps `data-reticle-source="file:line:col"` onto JSX host elements.**
135
+
136
+ **Why it exists:** React 19 dropped `_debugSource`, which is what source mapping used to rely on. This plugin puts the information back, at build time, in dev only. Without it, `reticle_inspect` can still tell you the component name but not the file.
137
+
138
+ **Depends on:** nothing. **Peer:** `@babel/core`.
139
+
140
+ **Do you install it?** Only directly if you are wiring Babel yourself. The Vite and Next packages both pull it in.
141
+
142
+ ---
143
+
144
+ ## @reticlehq/next
145
+
146
+ **Next.js source mapping without giving up SWC.**
147
+
148
+ **Why it exists:** Next users are on SWC, and telling them to switch to Babel for a dev tool would be a rude trade. This adds a dev-only webpack pre-loader that stamps the same attribute, and leaves your build pipeline alone.
149
+
150
+ **Depends on:** `@babel/core`, `@reticlehq/babel-plugin`. **Peer:** `next`.
151
+
152
+ ```js
153
+ const { withReticle } = require('@reticlehq/next');
154
+ module.exports = withReticle({/* your config */});
155
+ ```
156
+
157
+ <Note>
158
+ This one is CommonJS on purpose. `next.config.js` is loaded by Node before any ESM transform, so
159
+ an ESM-only helper would fail at the least helpful moment.
160
+ </Note>
161
+
162
+ ---
163
+
164
+ ## @reticlehq/test
165
+
166
+ **The spec runner for CI.** `reticleTest` registers declarative specs and runs them against Reticle's tools directly, with no MCP or stdio in the loop.
167
+
168
+ **Why it exists:** driving interactively is reconnaissance. At some point you want the same checks to run on every pull request without an agent. And without paying model tokens to re-derive them.
169
+
170
+ **Depends on:** `@reticlehq/core`, `@reticlehq/server`. **Peer:** `vitest`.
171
+
172
+ <Card title="Turn a session into a suite" icon="vial" href="/testing">
173
+ Writing specs that bind to signals rather than DOM structure.
174
+ </Card>
175
+
176
+ ---
177
+
178
+ ## @reticlehq/eslint-plugin
179
+
180
+ **Two rules, the main one being: state changed, so a signal must fire.**
181
+
182
+ **Why it exists:** signals are the strongest evidence Reticle can use, and they rot the way all conventions rot. Someone adds a mutation, forgets the signal, and every verdict for that flow quietly drops a grade. Nothing breaks. The tests still pass. The evidence just gets weaker.
183
+
184
+ A lint rule makes the signal layer self-enforcing, which is the only way a convention survives contact with a deadline.
185
+
186
+ **Depends on:** `@typescript-eslint/utils`. **Peer:** `eslint`.
187
+
188
+ ---
189
+
190
+ ## @reticlehq/electron
191
+
192
+ **Reaches the two places the renderer cannot.**
193
+
194
+ **Why it exists:** in Electron, the interesting failures often happen across the IPC boundary. The renderer asks the main process for something and the main process quietly fails. The renderer-side SDK cannot see that. This package makes main-process IPC observable and the window screenshottable.
195
+
196
+ **Depends on:** `@reticlehq/core`. **Peer:** `electron`.
197
+
198
+ ---
199
+
200
+ ## reticle-tauri
201
+
202
+ **The Rust crate**, on crates.io. Versioned independently of the npm packages.
203
+
204
+ **Why it exists:** Tauri IPC observation needs nothing on the Rust side; an `invoke('load_todos')` already reaches Reticle as `ipc://load_todos`. You only need this crate for screenshots and headless mode.
205
+
206
+ ```toml
207
+ [dependencies]
208
+ reticle-tauri = "0.1"
209
+ ```
210
+
211
+ <Warning>
212
+ Do not expect this to match the npm version. Doing so would imply a release cadence the crate does
213
+ not have, and it would make every npm release a crates.io release for no reason.
214
+ </Warning>
215
+
216
+ <Card title="Desktop setup in full" icon="display" href="/desktop">
217
+ Electron and Tauri wiring, including the Tauri CSP whose failure is silent.
218
+ </Card>