@reticlehq/server 2.13.1 → 2.14.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 (449) hide show
  1. package/SKILL.md +8 -18
  2. package/bin/reticle.js +3 -0
  3. package/dist/bridge/auth-failure-reason.js +12 -1
  4. package/dist/bridge/bridge-security.d.ts +8 -0
  5. package/dist/bridge/bridge-security.js +6 -1
  6. package/dist/bridge/bridge.d.ts +3 -0
  7. package/dist/bridge/bridge.js +23 -1
  8. package/dist/bridge/bridge.test-harness.d.ts +10 -1
  9. package/dist/bridge/bridge.test-harness.js +7 -1
  10. package/dist/bridge/pairing-token.d.ts +17 -0
  11. package/dist/bridge/pairing-token.js +26 -0
  12. package/dist/bridge/token-auth.d.ts +7 -0
  13. package/dist/bridge/token-auth.js +7 -1
  14. package/dist/capsule/capsule-store.d.ts +4 -4
  15. package/dist/capsule/capsule.d.ts +1 -1
  16. package/dist/capsule/capsule.js +3 -3
  17. package/dist/capsule/causal-summary.d.ts +21 -1
  18. package/dist/capsule/causal-summary.js +8 -6
  19. package/dist/capsule/divergence.d.ts +1 -1
  20. package/dist/capsule/divergence.js +26 -10
  21. package/dist/chromium-launch-options.d.ts +2 -1
  22. package/dist/cli/adhoc-verdict.d.ts +58 -0
  23. package/dist/cli/adhoc-verdict.js +115 -0
  24. package/dist/cli/chromium-hint.d.ts +18 -4
  25. package/dist/cli/chromium-hint.js +54 -6
  26. package/dist/cli/cli-doctor.js +1 -2
  27. package/dist/cli/cli-flow-commands.d.ts +16 -2
  28. package/dist/cli/cli-flow-commands.js +28 -9
  29. package/dist/cli/cli-parse-feedback.js +1 -1
  30. package/dist/cli/cli-parse.d.ts +2 -1
  31. package/dist/cli/cli-parse.js +38 -0
  32. package/dist/cli/cli-port.d.ts +5 -13
  33. package/dist/cli/cli-port.js +5 -38
  34. package/dist/cli/cli-update-commands.js +4 -4
  35. package/dist/cli/cli-verify.d.ts +24 -7
  36. package/dist/cli/cli-verify.js +87 -13
  37. package/dist/cli/cloud-keystore.d.ts +2 -1
  38. package/dist/cli/cloud-login.d.ts +2 -1
  39. package/dist/cli/cloud-session.d.ts +2 -1
  40. package/dist/cli/cloud-session.js +1 -1
  41. package/dist/cli/daemon-start-options.d.ts +2 -1
  42. package/dist/cli/device-flow.d.ts +2 -2
  43. package/dist/cli/doctor-daemon-line.d.ts +2 -1
  44. package/dist/cli/doctor-project-line.d.ts +2 -1
  45. package/dist/cli/doctor-rows.d.ts +2 -1
  46. package/dist/cli/drive-attach.d.ts +4 -3
  47. package/dist/cli/gate-hook-message.d.ts +2 -1
  48. package/dist/cli/status-next-action.js +10 -11
  49. package/dist/cli.d.ts +1 -0
  50. package/dist/cli.js +21 -9
  51. package/dist/cloud/account-state.d.ts +20 -0
  52. package/dist/cloud/account-state.js +65 -0
  53. package/dist/cloud/cloud-sync.d.ts +46 -3
  54. package/dist/cloud/cloud-sync.js +116 -0
  55. package/dist/cloud/sync-cycle.d.ts +5 -4
  56. package/dist/cloud/sync-cycle.js +1 -1
  57. package/dist/cloud/sync-daemon.d.ts +3 -19
  58. package/dist/cloud/sync-daemon.js +2 -2
  59. package/dist/crawl/crawl-tools.js +1 -1
  60. package/dist/crawl/crawl.d.ts +5 -5
  61. package/dist/crawl/crawl.js +138 -4
  62. package/dist/daemon/daemon-resilience.d.ts +3 -2
  63. package/dist/daemon/daemon-resilience.js +43 -4
  64. package/dist/daemon/daemon-resolve.d.ts +0 -9
  65. package/dist/daemon/daemon-resolve.js +2 -2
  66. package/dist/daemon/dev-servers.d.ts +1 -1
  67. package/dist/daemon/dev-servers.js +1 -1
  68. package/dist/daemon/loopback-alias.d.ts +2 -1
  69. package/dist/daemon/startup-failure.d.ts +11 -0
  70. package/dist/daemon/startup-failure.js +46 -0
  71. package/dist/events/contradictions.d.ts +10 -16
  72. package/dist/events/contradictions.js +149 -17
  73. package/dist/events/declared.d.ts +13 -1
  74. package/dist/events/declared.js +59 -3
  75. package/dist/events/echo-mismatch.js +75 -6
  76. package/dist/events/lineage.d.ts +52 -0
  77. package/dist/events/lineage.js +122 -0
  78. package/dist/events/net-evidence.d.ts +21 -0
  79. package/dist/events/net-evidence.js +81 -0
  80. package/dist/events/predicate-console.d.ts +13 -0
  81. package/dist/events/predicate-console.js +138 -0
  82. package/dist/events/predicate-element.d.ts +13 -0
  83. package/dist/events/predicate-element.js +214 -0
  84. package/dist/events/predicate-eval.d.ts +15 -3
  85. package/dist/events/predicate-eval.js +128 -110
  86. package/dist/events/predicate-parse.js +34 -1
  87. package/dist/events/predicate-request-body.d.ts +50 -0
  88. package/dist/events/predicate-request-body.js +120 -0
  89. package/dist/events/predicate-route.d.ts +21 -1
  90. package/dist/events/predicate-route.js +149 -21
  91. package/dist/events/predicate-schema.d.ts +8 -1
  92. package/dist/events/predicate-schema.js +34 -0
  93. package/dist/events/predicate.d.ts +2 -0
  94. package/dist/events/predicate.js +52 -159
  95. package/dist/events/split-text-miss.d.ts +6 -4
  96. package/dist/events/split-text-miss.js +12 -5
  97. package/dist/flows/affected-tools.js +22 -9
  98. package/dist/flows/annotate.d.ts +2 -1
  99. package/dist/flows/annotate.js +19 -1
  100. package/dist/flows/coverage.d.ts +2 -2
  101. package/dist/flows/flake.d.ts +3 -3
  102. package/dist/flows/flow-expect-grammar.d.ts +33 -0
  103. package/dist/flows/flow-expect-grammar.js +155 -0
  104. package/dist/flows/flow-replay-run.d.ts +1 -1
  105. package/dist/flows/flow-replay-run.js +28 -15
  106. package/dist/flows/flow-replay.d.ts +10 -0
  107. package/dist/flows/flow-replay.js +57 -22
  108. package/dist/flows/flow-secret-field.d.ts +14 -0
  109. package/dist/flows/flow-secret-field.js +22 -0
  110. package/dist/flows/flow-step-runners.d.ts +1 -0
  111. package/dist/flows/flow-step-runners.js +91 -34
  112. package/dist/flows/flow-success.js +22 -0
  113. package/dist/flows/flow-tools.js +27 -8
  114. package/dist/flows/flow-upload-resolve.d.ts +23 -0
  115. package/dist/flows/flow-upload-resolve.js +46 -0
  116. package/dist/flows/flows.d.ts +15 -0
  117. package/dist/flows/flows.js +17 -14
  118. package/dist/flows/git-changed.d.ts +23 -4
  119. package/dist/flows/git-changed.js +32 -6
  120. package/dist/flows/heal-run.js +2 -2
  121. package/dist/flows/predicate-to-expect.d.ts +3 -2
  122. package/dist/flows/predicate-to-expect.js +11 -5
  123. package/dist/flows/recording-backtrack.d.ts +24 -0
  124. package/dist/flows/recording-backtrack.js +73 -0
  125. package/dist/flows/recordings.d.ts +6 -0
  126. package/dist/flows/replay-halt.d.ts +26 -0
  127. package/dist/flows/replay-halt.js +30 -0
  128. package/dist/flows/replay.d.ts +0 -8
  129. package/dist/flows/replay.js +15 -3
  130. package/dist/flows/suite-flakes.d.ts +2 -1
  131. package/dist/flows/verify-change-tools.js +16 -4
  132. package/dist/honesty/already-true.d.ts +14 -0
  133. package/dist/honesty/already-true.js +47 -4
  134. package/dist/honesty/blind-spots.d.ts +3 -1
  135. package/dist/honesty/blind-spots.js +24 -1
  136. package/dist/honesty/body-capture-remedy.d.ts +42 -0
  137. package/dist/honesty/body-capture-remedy.js +95 -0
  138. package/dist/honesty/feature-capture.d.ts +3 -2
  139. package/dist/honesty/feature-capture.js +1 -1
  140. package/dist/honesty/gap-ledger.d.ts +1 -1
  141. package/dist/honesty/gap-ledger.js +1 -1
  142. package/dist/honesty/instrumentation-gaps.d.ts +8 -1
  143. package/dist/honesty/instrumentation-gaps.js +12 -2
  144. package/dist/honesty/observability.d.ts +4 -3
  145. package/dist/honesty/tool-hit-rate.d.ts +3 -2
  146. package/dist/honesty/uncaptured-bodies.d.ts +3 -1
  147. package/dist/honesty/uncaptured-bodies.js +6 -2
  148. package/dist/honesty/unsettled.d.ts +9 -0
  149. package/dist/honesty/unsettled.js +45 -0
  150. package/dist/honesty/verified.d.ts +32 -1
  151. package/dist/honesty/verified.js +37 -10
  152. package/dist/impact/impact-store.d.ts +5 -14
  153. package/dist/impact/impact-store.js +49 -6
  154. package/dist/index.js +1 -1
  155. package/dist/input/network-detail.d.ts +26 -1
  156. package/dist/input/network-detail.js +44 -12
  157. package/dist/input/network-mock-tools.js +24 -17
  158. package/dist/input/real-input.js +1 -1
  159. package/dist/input/viewport-tools.js +25 -13
  160. package/dist/intent/inline-intent.d.ts +0 -10
  161. package/dist/intent/inline-intent.js +1 -1
  162. package/dist/intent/intent-shard-store.d.ts +3 -2
  163. package/dist/intent/intent-shard-store.js +1 -1
  164. package/dist/intent/intent-shard.d.ts +14 -14
  165. package/dist/intent/intent-shard.js +4 -4
  166. package/dist/intent/intent-store.d.ts +1 -1
  167. package/dist/intent/intent-store.js +1 -1
  168. package/dist/intent/intent-subject.d.ts +2 -1
  169. package/dist/intent/open-intents.d.ts +3 -2
  170. package/dist/license/license.d.ts +4 -4
  171. package/dist/license/license.js +1 -1
  172. package/dist/mcp/attach-memory.d.ts +2 -1
  173. package/dist/mcp/client-identity.d.ts +2 -1
  174. package/dist/mcp/mcp-outage.d.ts +1 -1
  175. package/dist/mcp/mcp-outage.js +1 -1
  176. package/dist/mcp/mcp-proxy.d.ts +3 -1
  177. package/dist/mcp/mcp-proxy.js +32 -7
  178. package/dist/mcp/mcp.js +3 -1
  179. package/dist/mcp/proxy-handshake.d.ts +2 -1
  180. package/dist/mcp/proxy-idle-exit.d.ts +45 -0
  181. package/dist/mcp/proxy-idle-exit.js +94 -0
  182. package/dist/mcp/server-instructions.d.ts +2 -1
  183. package/dist/memory/project-memory.d.ts +2 -3
  184. package/dist/memory/project-memory.js +1 -1
  185. package/dist/oracles/propose-consequences.js +5 -5
  186. package/dist/oracles/self-instrument.d.ts +2 -2
  187. package/dist/oracles/self-instrument.js +1 -1
  188. package/dist/platform.d.ts +3 -5
  189. package/dist/platform.js +3 -5
  190. package/dist/pool/browser-pool.d.ts +92 -0
  191. package/dist/pool/browser-pool.js +119 -5
  192. package/dist/pool/playwright-launcher.js +29 -2
  193. package/dist/pool/storage-seed.d.ts +23 -0
  194. package/dist/pool/storage-seed.js +198 -0
  195. package/dist/project/artifact-root.d.ts +2 -1
  196. package/dist/project/memory-fs.d.ts +2 -1
  197. package/dist/project/reticle-dir.js +1 -1
  198. package/dist/project/session-root.d.ts +8 -0
  199. package/dist/project/session-root.js +9 -2
  200. package/dist/runs/reticle-runner.d.ts +14 -1
  201. package/dist/runs/reticle-runner.js +39 -2
  202. package/dist/session/attachment-history.d.ts +2 -1
  203. package/dist/session/fake-session.d.ts +37 -0
  204. package/dist/session/fake-session.js +81 -0
  205. package/dist/session/lease-visibility.d.ts +2 -1
  206. package/dist/session/live-control-tools.js +6 -0
  207. package/dist/session/no-session-diagnosis.d.ts +17 -1
  208. package/dist/session/no-session-diagnosis.js +32 -6
  209. package/dist/session/no-session-next-action.d.ts +14 -0
  210. package/dist/session/no-session-next-action.js +18 -0
  211. package/dist/session/no-session-watch.js +46 -3
  212. package/dist/session/registered-projects.d.ts +54 -0
  213. package/dist/session/registered-projects.js +73 -0
  214. package/dist/session/review-store.d.ts +2 -1
  215. package/dist/session/session-health.d.ts +62 -1
  216. package/dist/session/session-health.js +82 -2
  217. package/dist/session/session-manager.d.ts +11 -1
  218. package/dist/session/session-manager.js +18 -3
  219. package/dist/session/session-replaced.d.ts +24 -0
  220. package/dist/session/session-replaced.js +29 -0
  221. package/dist/session/session-successor.js +20 -4
  222. package/dist/session/session.d.ts +13 -5
  223. package/dist/session/session.js +31 -23
  224. package/dist/setup/agent-configs.d.ts +3 -2
  225. package/dist/setup/agent-writer.d.ts +3 -2
  226. package/dist/setup/approval-migration.d.ts +2 -1
  227. package/dist/setup/approval-migration.js +1 -1
  228. package/dist/setup/auto-approve.d.ts +11 -19
  229. package/dist/setup/auto-approve.js +15 -12
  230. package/dist/{init → setup}/confirm.js +1 -1
  231. package/dist/setup/desktop-shape.d.ts +3 -2
  232. package/dist/setup/drive-agent.d.ts +2 -3
  233. package/dist/setup/drive-agent.js +1 -1
  234. package/dist/setup/drive-plan.d.ts +3 -2
  235. package/dist/setup/ensure-daemon.d.ts +2 -1
  236. package/dist/setup/existing-app.d.ts +12 -0
  237. package/dist/setup/existing-app.js +13 -0
  238. package/dist/setup/init-host.d.ts +11 -0
  239. package/dist/setup/init-host.js +26 -0
  240. package/dist/setup/init-runtime.d.ts +4 -10
  241. package/dist/setup/init-runtime.js +23 -16
  242. package/dist/setup/license-key.d.ts +2 -1
  243. package/dist/setup/listeners.d.ts +2 -1
  244. package/dist/setup/loopback-probe-urls.d.ts +18 -0
  245. package/dist/setup/loopback-probe-urls.js +52 -0
  246. package/dist/setup/node-effects.d.ts +3 -0
  247. package/dist/setup/node-effects.js +26 -11
  248. package/dist/setup/page-probe.d.ts +5 -0
  249. package/dist/setup/relaunch.d.ts +2 -1
  250. package/dist/setup/run-setup.d.ts +5 -1
  251. package/dist/setup/run-setup.js +141 -50
  252. package/dist/setup/setup-command.d.ts +3 -2
  253. package/dist/setup/setup-command.js +8 -0
  254. package/dist/setup/setup-options.d.ts +5 -3
  255. package/dist/setup/setup-options.js +3 -2
  256. package/dist/setup/wait-progress.d.ts +28 -0
  257. package/dist/setup/wait-progress.js +43 -0
  258. package/dist/telemetry/app-instrumented.d.ts +2 -1
  259. package/dist/telemetry/app-instrumented.js +1 -1
  260. package/dist/telemetry/automation-hint.d.ts +1 -1
  261. package/dist/telemetry/automation-hint.js +1 -1
  262. package/dist/telemetry/cli-telemetry.js +1 -1
  263. package/dist/telemetry/connect-failure.d.ts +1 -1
  264. package/dist/telemetry/connect-failure.js +1 -1
  265. package/dist/telemetry/crash-cause.d.ts +3 -2
  266. package/dist/telemetry/crash-cause.js +1 -1
  267. package/dist/telemetry/daemon-telemetry.d.ts +3 -2
  268. package/dist/telemetry/daemon-telemetry.js +1 -1
  269. package/dist/telemetry/error-class.d.ts +3 -2
  270. package/dist/telemetry/error-class.js +1 -1
  271. package/dist/telemetry/feedback-cli.js +1 -1
  272. package/dist/telemetry/feedback-context.d.ts +3 -2
  273. package/dist/telemetry/feedback-context.js +5 -4
  274. package/dist/telemetry/feedback-local.d.ts +3 -2
  275. package/dist/telemetry/feedback.d.ts +4 -3
  276. package/dist/telemetry/feedback.js +1 -1
  277. package/dist/telemetry/git-facts.d.ts +2 -2
  278. package/dist/telemetry/git-facts.js +1 -1
  279. package/dist/telemetry/identify.d.ts +1 -1
  280. package/dist/telemetry/identify.js +1 -1
  281. package/dist/telemetry/init-telemetry.d.ts +2 -14
  282. package/dist/telemetry/init-telemetry.js +4 -13
  283. package/dist/telemetry/install-source.d.ts +7 -13
  284. package/dist/telemetry/install-source.js +7 -29
  285. package/dist/telemetry/license-activation.d.ts +3 -2
  286. package/dist/telemetry/license-activation.js +1 -1
  287. package/dist/telemetry/machine-snapshot.d.ts +1 -1
  288. package/dist/telemetry/mcp-connection.js +1 -1
  289. package/dist/telemetry/project-profile.d.ts +0 -14
  290. package/dist/telemetry/project-profile.js +1 -1
  291. package/dist/telemetry/proxy-telemetry.js +1 -1
  292. package/dist/telemetry/session-metrics.d.ts +1 -1
  293. package/dist/telemetry/session-metrics.js +1 -1
  294. package/dist/telemetry/telemetry.d.ts +1 -17
  295. package/dist/telemetry/telemetry.js +4 -4
  296. package/dist/telemetry/tool-refused.d.ts +1 -1
  297. package/dist/telemetry/tool-refused.js +1 -1
  298. package/dist/tools/act-observation.d.ts +3 -2
  299. package/dist/tools/act-preflight.js +8 -3
  300. package/dist/tools/act-target.d.ts +4 -0
  301. package/dist/tools/act-target.js +14 -5
  302. package/dist/tools/act-tools.d.ts +0 -2
  303. package/dist/tools/act-tools.js +45 -15
  304. package/dist/tools/assert-source.d.ts +30 -0
  305. package/dist/tools/assert-source.js +21 -0
  306. package/dist/tools/assert-verdict.d.ts +1 -1
  307. package/dist/tools/assert-verdict.js +14 -4
  308. package/dist/tools/browser-tools.js +28 -8
  309. package/dist/tools/complete-snapshot.d.ts +3 -2
  310. package/dist/tools/dynamic-tools.js +8 -0
  311. package/dist/tools/error-recovery.d.ts +10 -0
  312. package/dist/tools/error-recovery.js +23 -0
  313. package/dist/tools/feedback-tools.js +1 -1
  314. package/dist/tools/invoke-tool.js +2 -0
  315. package/dist/tools/lease-tools.d.ts +48 -20
  316. package/dist/tools/lease-tools.js +311 -76
  317. package/dist/tools/lineage-tools.d.ts +14 -0
  318. package/dist/tools/lineage-tools.js +64 -0
  319. package/dist/tools/merge-tools.js +1 -3
  320. package/dist/tools/navigate-arrival.d.ts +45 -1
  321. package/dist/tools/navigate-arrival.js +39 -6
  322. package/dist/tools/navigate-result.d.ts +8 -1
  323. package/dist/tools/navigate-result.js +14 -4
  324. package/dist/tools/numeric-bounds.d.ts +0 -11
  325. package/dist/tools/numeric-bounds.js +4 -4
  326. package/dist/tools/observe-tools.js +22 -26
  327. package/dist/tools/observed-nothing.d.ts +9 -0
  328. package/dist/tools/observed-nothing.js +2 -1
  329. package/dist/tools/read-tools.js +12 -17
  330. package/dist/tools/real-input-attempt.d.ts +14 -6
  331. package/dist/tools/real-input-attempt.js +75 -18
  332. package/dist/tools/reconcile-tools.js +2 -1
  333. package/dist/tools/reload-result.d.ts +6 -1
  334. package/dist/tools/reload-result.js +7 -2
  335. package/dist/tools/resolve-target.d.ts +7 -1
  336. package/dist/tools/resolve-target.js +72 -9
  337. package/dist/tools/settle-in-flight.d.ts +1 -1
  338. package/dist/tools/settle-in-flight.js +9 -2
  339. package/dist/tools/snapshot-delta.d.ts +24 -1
  340. package/dist/tools/snapshot-delta.js +66 -7
  341. package/dist/tools/tool-names.d.ts +1 -0
  342. package/dist/tools/tool-names.js +1 -0
  343. package/dist/tools/tool-surface.js +20 -2
  344. package/dist/tools/tools.js +120 -11
  345. package/dist/tools/verify-next-baton.d.ts +2 -1
  346. package/dist/update/sdk-sync.d.ts +1 -1
  347. package/dist/update/sdk-sync.js +1 -1
  348. package/dist/update/updater.js +1 -1
  349. package/dist/version/sdk-fix.d.ts +2 -1
  350. package/dist/version/version-skew.d.ts +0 -8
  351. package/dist/version/version-skew.js +1 -1
  352. package/docs/README.md +8 -6
  353. package/docs/actions.mdx +1 -1
  354. package/docs/agent-cheatsheet.md +4 -2
  355. package/docs/architecture.md +1 -1
  356. package/docs/cli/mcp.mdx +3 -1
  357. package/docs/cli/watch.mdx +1 -1
  358. package/docs/cli.mdx +1 -1
  359. package/docs/desktop.mdx +1 -1
  360. package/docs/docs.json +8 -3
  361. package/docs/faq.mdx +9 -0
  362. package/docs/first-drive.md +136 -0
  363. package/docs/frameworks.mdx +29 -7
  364. package/docs/gate-plan.md +2 -2
  365. package/docs/gates.md +19 -11
  366. package/docs/getting-started.md +7 -1
  367. package/docs/http-transport.md +164 -0
  368. package/docs/index.mdx +5 -3
  369. package/docs/install-manual.mdx +1 -1
  370. package/docs/packages/tauri.mdx +1 -1
  371. package/docs/packages.mdx +15 -3
  372. package/docs/platform-integration.md +1 -1
  373. package/docs/predicates.mdx +2 -0
  374. package/docs/system-map.md +2 -2
  375. package/docs/telemetry-contract.md +4 -4
  376. package/docs/telemetry-events.mdx +1 -1
  377. package/docs/telemetry.md +3 -3
  378. package/docs/tools-navigate.mdx +14 -6
  379. package/docs/usage.md +4 -4
  380. package/package.json +7 -4
  381. package/dist/init/agent-rules.d.ts +0 -116
  382. package/dist/init/agent-rules.js +0 -279
  383. package/dist/init/app-choice.d.ts +0 -20
  384. package/dist/init/app-choice.js +0 -25
  385. package/dist/init/astro-host.d.ts +0 -21
  386. package/dist/init/astro-host.js +0 -27
  387. package/dist/init/astro-patch.d.ts +0 -33
  388. package/dist/init/astro-patch.js +0 -300
  389. package/dist/init/capabilities.d.ts +0 -40
  390. package/dist/init/capabilities.js +0 -150
  391. package/dist/init/closing-hint.d.ts +0 -36
  392. package/dist/init/closing-hint.js +0 -120
  393. package/dist/init/connect-steps.d.ts +0 -2
  394. package/dist/init/connect-steps.js +0 -50
  395. package/dist/init/cra.d.ts +0 -79
  396. package/dist/init/cra.js +0 -178
  397. package/dist/init/csp-check.d.ts +0 -38
  398. package/dist/init/csp-check.js +0 -107
  399. package/dist/init/csp-doctor.d.ts +0 -32
  400. package/dist/init/csp-doctor.js +0 -54
  401. package/dist/init/desktop-doctor.d.ts +0 -41
  402. package/dist/init/desktop-doctor.js +0 -198
  403. package/dist/init/detect.d.ts +0 -96
  404. package/dist/init/detect.js +0 -209
  405. package/dist/init/dev-script.d.ts +0 -50
  406. package/dist/init/dev-script.js +0 -66
  407. package/dist/init/format-generated.d.ts +0 -18
  408. package/dist/init/format-generated.js +0 -39
  409. package/dist/init/install-hint.d.ts +0 -9
  410. package/dist/init/install-hint.js +0 -29
  411. package/dist/init/mcp-clients.d.ts +0 -89
  412. package/dist/init/mcp-clients.js +0 -299
  413. package/dist/init/mcp-registered.d.ts +0 -12
  414. package/dist/init/mcp-registered.js +0 -14
  415. package/dist/init/mcp.d.ts +0 -89
  416. package/dist/init/mcp.js +0 -129
  417. package/dist/init/next-patch.d.ts +0 -39
  418. package/dist/init/next-patch.js +0 -196
  419. package/dist/init/node-io.d.ts +0 -7
  420. package/dist/init/node-io.js +0 -117
  421. package/dist/init/non-js-project.d.ts +0 -27
  422. package/dist/init/non-js-project.js +0 -84
  423. package/dist/init/patch-kind.d.ts +0 -20
  424. package/dist/init/patch-kind.js +0 -10
  425. package/dist/init/plan-framework.d.ts +0 -64
  426. package/dist/init/plan-framework.js +0 -565
  427. package/dist/init/plan.d.ts +0 -242
  428. package/dist/init/plan.js +0 -703
  429. package/dist/init/preflight.d.ts +0 -28
  430. package/dist/init/preflight.js +0 -38
  431. package/dist/init/project-id.d.ts +0 -12
  432. package/dist/init/project-id.js +0 -25
  433. package/dist/init/refresh-rules.d.ts +0 -39
  434. package/dist/init/refresh-rules.js +0 -51
  435. package/dist/init/run.d.ts +0 -117
  436. package/dist/init/run.js +0 -806
  437. package/dist/init/slash-command.d.ts +0 -27
  438. package/dist/init/slash-command.js +0 -132
  439. package/dist/init/snippets.d.ts +0 -134
  440. package/dist/init/snippets.js +0 -572
  441. package/dist/init/vite-config.d.ts +0 -18
  442. package/dist/init/vite-config.js +0 -114
  443. package/dist/init/windows-quote.d.ts +0 -38
  444. package/dist/init/windows-quote.js +0 -70
  445. package/dist/init/workspace-apps.d.ts +0 -30
  446. package/dist/init/workspace-apps.js +0 -178
  447. package/dist/project/remember-project.d.ts +0 -24
  448. package/dist/project/remember-project.js +0 -40
  449. /package/dist/{init → setup}/confirm.d.ts +0 -0
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: 'HTTP transport'
3
+ description: 'Drive the full reticle_* tool surface over plain HTTP and SSE, from a client that cannot hot-reload MCP tools or that is not an MCP client at all.'
4
+ icon: 'plug'
5
+ ---
6
+
7
+ Most clients reach Reticle over stdio: they spawn `reticle mcp`, and the tools appear in the agent's surface. That has one property you cannot always live with. **Many clients read their MCP tool list once, at startup**. If the daemon was not running when the client launched, the `reticle_*` tools are absent for the rest of that session, and the fix is to restart the client.
8
+
9
+ The daemon also speaks MCP over HTTP, on the same port as everything else. Nothing has to reload for a client to reach it, so this is the transport for scripted runs, CI, a language with no MCP client library, and any editor that will not pick up tools mid-session.
10
+
11
+ It is the same tool surface. Not a subset, not a simplified one. `reticle_snapshot`, `reticle_act_and_wait`, `reticle_assert` and the rest behave exactly as they do over stdio, because they are the same server behind a different transport.
12
+
13
+ ## The two endpoints
14
+
15
+ | Method | Path | What it does |
16
+ | --- | --- | --- |
17
+ | `GET` | `/mcp/sse` | Opens a session. The response is an SSE stream that stays open, and every reply the server sends comes back on it. |
18
+ | `POST` | `/mcp/message?sessionId=<id>` | Sends one JSON-RPC message into an open session. |
19
+
20
+ The daemon listens on port **4400** by default (`RETICLE_PORT`, or `reticle serve --port N`). Run `reticle status` to confirm which port is live.
21
+
22
+ ## The handshake
23
+
24
+ The one shape worth reading before you write any code: **the POST does not answer your request.** It replies `202 Accepted` with no result in it, and the actual JSON-RPC reply arrives on the SSE stream you opened first. A client that waits on the POST body waits forever.
25
+
26
+ 1. `GET /mcp/sse`. Hold the response open.
27
+ 2. The first frame is the endpoint announcement, and it carries the session id:
28
+
29
+ ```
30
+ event: endpoint
31
+ data: /mcp/message?sessionId=6f1c2b7e-1f4a-4a8e-9d5f-3f7a1b2c3d4e
32
+ ```
33
+
34
+ Use that `data` value verbatim as the path you POST to. Do not build it yourself: the session id is minted per connection.
35
+
36
+ 3. `POST` the `initialize` request there, then the `notifications/initialized` notification.
37
+ 4. `POST` `tools/list`, `tools/call`, and anything else. Match each reply to its request by the JSON-RPC `id`, off the SSE stream.
38
+
39
+ When the daemon shuts down it writes a shutdown frame on the stream before the socket closes, so a client can tell a planned stop from a dropped connection.
40
+
41
+ ## Errors
42
+
43
+ | Status | Meaning | What to do |
44
+ | --- | --- | --- |
45
+ | `400 missing sessionId` | The POST had no `sessionId` query parameter. | Use the path from the `endpoint` frame. |
46
+ | `404 session not found` | That session is not open, usually because the SSE stream dropped. | Reconnect to `/mcp/sse` and handshake again. |
47
+ | `503 MCP server not ready` | The daemon is up but the MCP server is not attached yet. | Retry. Unlike a `404`, the endpoint is real and coming. |
48
+
49
+ `404` and `400` are kept apart on purpose: reconnecting fixes one and nothing about the other.
50
+
51
+ ## Authorization
52
+
53
+ Two tiers, the same ones the WebSocket bridge uses.
54
+
55
+ **Local clients need no token.** A request is trusted when its peer address, its `Host` header, and its `Origin`/`Referer` (when present) are all loopback. All three are required, because a DNS-rebound page reaches the daemon _as_ a loopback peer while carrying the attacker's `Host`, so peer address alone would not be a check.
56
+
57
+ **Anything else must present the pairing token**, which is required whenever you bind beyond loopback with `RETICLE_HOST`. Either form works:
58
+
59
+ ```
60
+ Authorization: Bearer <token>
61
+ ```
62
+
63
+ ```
64
+ /mcp/sse?token=<token>
65
+ ```
66
+
67
+ Set it with `RETICLE_TOKEN`. With no token configured, the daemon binds loopback-only and non-local requests are refused outright rather than falling back to trust.
68
+
69
+ ## A minimal client
70
+
71
+ No MCP library. Node's standard library is enough. This opens a session, lists the tools, and takes a snapshot.
72
+
73
+ ```js
74
+ import http from 'node:http';
75
+
76
+ const PORT = 4400;
77
+ let endpoint = null;
78
+ let next = 1;
79
+ const pending = new Map();
80
+
81
+ // 1. Open the stream and keep it open. Every reply arrives here.
82
+ http.get({ port: PORT, path: '/mcp/sse', agent: false }, (res) => {
83
+ let buffer = '';
84
+ res.setEncoding('utf8');
85
+ res.on('data', (chunk) => {
86
+ buffer += chunk;
87
+ const frames = buffer.split('\n\n');
88
+ buffer = frames.pop();
89
+ for (const frame of frames) {
90
+ const event = /^event: (.*)$/m.exec(frame)?.[1] ?? 'message';
91
+ const data = /^data: (.*)$/m.exec(frame)?.[1] ?? '';
92
+ if (event === 'endpoint') {
93
+ endpoint = data; // "/mcp/message?sessionId=…", used verbatim
94
+ start();
95
+ continue;
96
+ }
97
+ const message = JSON.parse(data);
98
+ pending.get(message.id)?.(message); // match the reply to its request by id
99
+ pending.delete(message.id);
100
+ }
101
+ });
102
+ });
103
+
104
+ // 2. POST a request; resolve when its reply comes back on the stream.
105
+ function send(method, params) {
106
+ const id = next++;
107
+ const body = JSON.stringify({ jsonrpc: '2.0', id, method, params });
108
+ return new Promise((resolve) => {
109
+ pending.set(id, resolve);
110
+ const req = http.request(
111
+ {
112
+ port: PORT,
113
+ path: endpoint,
114
+ method: 'POST',
115
+ headers: { 'Content-Type': 'application/json' },
116
+ },
117
+ (res) => res.resume(), // 202 Accepted; the answer is on the SSE stream
118
+ );
119
+ req.end(body);
120
+ });
121
+ }
122
+
123
+ async function start() {
124
+ await send('initialize', {
125
+ protocolVersion: '2024-11-05',
126
+ capabilities: {},
127
+ clientInfo: { name: 'my-client', version: '1.0.0' },
128
+ });
129
+
130
+ const notify = http.request(
131
+ { port: PORT, path: endpoint, method: 'POST', headers: { 'Content-Type': 'application/json' } },
132
+ (res) => res.resume(),
133
+ );
134
+ notify.end(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' }));
135
+
136
+ const listed = await send('tools/list', {});
137
+ console.log(listed.result.tools.map((t) => t.name).join(', '));
138
+
139
+ const snapshot = await send('tools/call', { name: 'reticle_snapshot', arguments: {} });
140
+ console.log(snapshot.result.content[0].text);
141
+ }
142
+ ```
143
+
144
+ To watch the raw frames instead, `curl` is enough for the first half:
145
+
146
+ ```bash
147
+ curl -N http://127.0.0.1:4400/mcp/sse
148
+ ```
149
+
150
+ Then, from a second shell, POST to the path that stream printed:
151
+
152
+ ```bash
153
+ curl -X POST 'http://127.0.0.1:4400/mcp/message?sessionId=<id>' \
154
+ -H 'Content-Type: application/json' \
155
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
156
+ ```
157
+
158
+ The `202` comes back here; the tool list appears in the first shell.
159
+
160
+ ## What this does not change
161
+
162
+ The transport carries the tools. It does not replace the rest of the setup. The app still has to be instrumented and connected, and `reticle_sessions` is still what tells you whether a session is there to drive. A verdict reached over HTTP is a verdict reached the usual way: only `verified: "yes"` is a pass.
163
+
164
+ The endpoints, the handshake, the three status codes and the `202`-then-SSE shape are pinned by `packages/server/src/mcp-http-transport.test.ts`, which drives them over raw HTTP with no client library, so the contract this page describes fails the build if it changes.
package/docs/index.mdx CHANGED
@@ -44,9 +44,11 @@ Afterwards, use it whenever you change any user-facing behaviour.
44
44
  ```
45
45
 
46
46
  <Tip>
47
- On Claude Code the plugin is shorter still: `/plugin marketplace add reticlehq/reticle` then
48
- `/plugin install reticle@reticlehq`, which registers the MCP server and the skills in one step. On
49
- most other agents, `npx skills add reticlehq/reticle`.
47
+ The plugin and the skills CLI are alternatives to the *registration* half only, not to `init`:
48
+ neither one touches your app, so you still run the command above afterwards to instrument it. On
49
+ Claude Code, `/plugin marketplace add reticlehq/reticle` then `/plugin install reticle@reticlehq`
50
+ registers the MCP server and the skills in one step; on most other agents, `npx skills add
51
+ reticlehq/reticle`.
50
52
  </Tip>
51
53
 
52
54
  <Card title="What that command actually changes" icon="wand-magic-sparkles" href="/install-agentic">
@@ -159,7 +159,7 @@ Screenshots and headless mode need the Rust crate, which is versioned independen
159
159
 
160
160
  ```toml
161
161
  [dependencies]
162
- reticle-tauri = "2.13"
162
+ reticle-tauri = "2.14"
163
163
  ```
164
164
 
165
165
  ```rust
@@ -21,7 +21,7 @@ Tauri IPC observation needs nothing on the Rust side. An `invoke('load_todos')`
21
21
 
22
22
  ```toml
23
23
  [dependencies]
24
- reticle-tauri = "0.1"
24
+ reticle-tauri = "2.14"
25
25
  ```
26
26
 
27
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.
package/docs/packages.mdx CHANGED
@@ -5,7 +5,7 @@ description: Every Reticle package. What it does, why it exists, when you actual
5
5
  icon: cubes
6
6
  ---
7
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.
8
+ Reticle is twelve 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
9
 
10
10
  <Note>
11
11
  Everything ships together at one version: whatever `npm view @reticlehq/core version` says, every
@@ -89,7 +89,7 @@ if (import.meta.env.DEV) reticle.connect();
89
89
 
90
90
  **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.
91
91
 
92
- **Depends on:** `@modelcontextprotocol/sdk`, `@reticlehq/core`, `ws`, `zod`.
92
+ **Depends on:** `@modelcontextprotocol/sdk`, `@reticlehq/core`, `@reticlehq/init`, `ws`, `zod`.
93
93
 
94
94
  **Do you install it?** Not into your project. Your agent launches it:
95
95
 
@@ -99,6 +99,18 @@ npx @reticlehq/server mcp
99
99
 
100
100
  ---
101
101
 
102
+ ## @reticlehq/init
103
+
104
+ **The project scaffolder behind `reticle init`.** Detects the framework and package manager, writes `.reticle.json`, patches the build config, generates the connect snippet and the agent rules, and registers the MCP server with whichever clients are on the machine.
105
+
106
+ **Why it exists:** nothing in it observes a running app. It is a build-time codemod that runs once. While it lived inside `@reticlehq/server`, a typo in a generated snippet forced a republish of the MCP server, and every MCP user downloaded a scaffolder they run once or never. It reaches back into the daemon for nothing: the version it stamps, the tracer, the outcome reporter and the bridge pairing token all arrive through one injected `InitHost`.
107
+
108
+ **Depends on:** `@reticlehq/core`, and nothing else.
109
+
110
+ **Do you install it?** No. `@reticlehq/server` depends on it at the same version, and the `reticle` CLI drives it.
111
+
112
+ ---
113
+
102
114
  ## @reticlehq/react
103
115
 
104
116
  **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.
@@ -207,7 +219,7 @@ A lint rule makes the signal layer self-enforcing, which is the only way a conve
207
219
 
208
220
  ```toml
209
221
  [dependencies]
210
- reticle-tauri = "2.13"
222
+ reticle-tauri = "2.14"
211
223
  ```
212
224
 
213
225
  <Warning>
@@ -133,7 +133,7 @@ The shape is identical (in-app SDK in the template → verify in the sandbox →
133
133
  2. Since the runtime is in-browser, drive via the connected session (the SDK dials the bridge) rather than `--drive`; call verify from the Bolt agent after a build.
134
134
  3. Same act-on-verdict: gate + self-heal with the repair packets. (Bolt already detects terminal/compile errors; Reticle adds the _runtime program-truth_ layer it's blind to.)
135
135
 
136
- > Honest note: a platform can build a verification step itself. Reticle's case is the depth (program-state and source mapping), the determinism (0% flake, no LLM in the loop), the un-hallucinatable verdict, and a stable drop-in artifact. The reproducible benchmark in [`bench/`](../bench/README.md) measures the observation-cost and detection differences against other browser-automation MCPs.
136
+ > Honest note: a platform can build a verification step itself. Reticle's case is the depth (program-state and source mapping), the determinism (0% flake, no LLM in the loop), the un-hallucinatable verdict, and a stable drop-in artifact. The reproducible benchmark in [`bench/`](https://github.com/reticlehq/reticle/blob/main/bench/README.md) measures the observation-cost and detection differences against other browser-automation MCPs.
137
137
 
138
138
  ---
139
139
 
@@ -60,6 +60,8 @@ Add `"absent": true` to assert something is **gone**. The predicate for a remova
60
60
 
61
61
  `contains` is the field the published schema declares. `value` and `text` are accepted as aliases and rewritten to it. `absent: true` asserts the text is not present, and `visible: true` requires it to be on screen rather than merely in the DOM.
62
62
 
63
+ Use `scope` to restrict the search to a CSS selector or element ref. If Reticle reports that the text is split across the scope's children, retry its generated predicate with `"self": true`; that checks the scope root's combined subtree text while still enforcing `contains`.
64
+
63
65
  ### net
64
66
 
65
67
  ```json
@@ -8,7 +8,7 @@ A tool call crosses five processes and four hops: coding agent → `reticle mcp`
8
8
 
9
9
  > How a tool call gets from a coding agent to your app and back, what each hop can do wrong, and which of those failures are **silent**. Written for anyone touching the transport, the daemon, the bridge, or a gate, and for contributors trying to work out where their change lives.
10
10
  >
11
- > Companion pages: [`harness-rules.md`](../apps/e2e/harness-rules.md) (what a gate must do about all this) and [`telemetry-contract.md`](./telemetry-contract.md) (the rules for anything that emits).
11
+ > Companion pages: [`harness-rules.md`](https://github.com/reticlehq/reticle/blob/main/apps/e2e/harness-rules.md) (what a gate must do about all this) and [`telemetry-contract.md`](./telemetry-contract.md) (the rules for anything that emits).
12
12
 
13
13
  ## 1. Topology: 5 processes, 4 hops
14
14
 
@@ -87,7 +87,7 @@ Two structural facts:
87
87
 
88
88
  | Failure | Silent | Guarded by |
89
89
  | --- | --- | --- |
90
- | proxy killed externally (the `lsof -ti` recipe) | **yes, total** | `reticle kill` frees the port and leaves the agent's own proxy alone. See [harness rule 1](../apps/e2e/harness-rules.md) |
90
+ | proxy killed externally (the `lsof -ti` recipe) | **yes, total** | `reticle kill` frees the port and leaves the agent's own proxy alone. See [harness rule 1](https://github.com/reticlehq/reticle/blob/main/apps/e2e/harness-rules.md) |
91
91
  | proxy uncaught exception | no | `installProxyResilience` + `proxyLog` |
92
92
  | proxy exits when the reconnect budget is spent | _was the worst bug in the product_ | `onReconnectBudgetSpent` → DORMANT, never exit |
93
93
  | client closes stdin with calls in flight | no | `SHUTDOWN_DRAIN_MS` (5s) |
@@ -152,7 +152,7 @@ Two questions get asked of `verification_completed` constantly and both have exa
152
152
  **"A large share of verdicts come back `unknown`."** `verified` has three values and the rule that produces it has eleven clauses, so `unknown` on its own is seven different situations belonging to three different owners. **Always break `unknown` down by `verification.reason`** before treating it as a quality number:
153
153
 
154
154
  - `inconclusive`, `nothing_declared`, `vacuous_grade` -- the agent's own call. Teach the agent; the product worked.
155
- - `outcome_pending`, `outcome_unread`, `unsettled`, `evidence_incomplete` -- the app had not finished. Wait and re-check; often a budget that ended early.
155
+ - `outcome_pending`, `outcome_unread`, `unsettled`, `evidence_incomplete`, `window_closed_early` -- the app had not finished. Wait and re-check; often a budget that ended early.
156
156
  - `observation_lost`, `unclean_capture`, `absence_blind_spot` -- **ours**. Ship a fix. `uncleanLoss` names which of the three owners inside that one.
157
157
 
158
158
  An `unknown` rate quoted without this split is a number about all three at once and actionable by none of them.
@@ -188,7 +188,7 @@ Four counters and one flag were added because the data could not answer question
188
188
  | `endedWithVerdict` | session summary (final only) | did this session ever produce a verdict. The headline metric, and previously the only thing in the payload that had to be COMPUTED, from lifetime counters sitting next to windowed ones, which is a subtraction that gets read wrong. Sent as `false` rather than omitted: a session that drove an app and never asked whether it worked is the finding. |
189
189
  | `verification.browser` | `verification_completed` | `headless` \| `headed` \| `attached`: who DROVE the browser. `attached` (Reticle launched nothing, the SDK connected from a browser somebody else opened) is the common case in production, so on its own this is mostly "somebody's own browser". |
190
190
  | `verification.brand` | `verification_completed` | WHICH browser it was: `chrome` \| `edge` \| `arc` \| `dia` \| `brave` \| `opera` \| `firefox` \| `safari` \| `other`, the closed `BrowserBrand` list in core. The axis `engine` cannot answer, since Chrome, Edge, Arc, Dia and Brave are all `blink`. The SDK reads `navigator.userAgentData.brands` (and the UA string on Firefox/Safari, which expose no `userAgentData`) and normalises IN THE PAGE: a raw brand or UA string is unbounded and fingerprintable and never leaves. Anything unrecognised is `other`. **Omitted rather than `"unknown"`** when the page did not say. A desktop webview has no brand and an older SDK does not report one, and a guess is indistinguishable from a measurement on a dashboard. |
191
- | `verification.reason` | `verification_completed` | WHICH clause of `decideVerified` produced the verdict, from core's closed `VerifiedReason`: `inconclusive` \| `observation_lost` \| `assertion_failed` \| `contradicted` \| `already_true` \| `unclean_capture` \| `vacuous_grade` \| `outcome_pending` \| `outcome_unread` \| `unsettled` (the page never went idle and no consequence was declared) \| `evidence_incomplete` (the assertion held, but a channel's outcome had not arrived when the window closed) \| `proved`. See below. |
191
+ | `verification.reason` | `verification_completed` | WHICH clause of `decideVerified` produced the verdict, from core's closed `VerifiedReason`: `inconclusive` \| `observation_lost` \| `window_closed_early` \| `assertion_failed` \| `contradicted` \| `already_true` \| `unclean_capture` \| `vacuous_grade` \| `outcome_pending` \| `outcome_unread` \| `unsettled` (the page never went idle and no consequence was declared) \| `evidence_incomplete` (the assertion held, but a channel's outcome had not arrived when the window closed) \| `proved`. See below. |
192
192
  | `verification.uncleanLoss` | `verification_completed` | WHAT was lost when `reason` is `unclean_capture`, from core's closed `CaptureLoss`: `buffer_loss` (our server ring buffer evicted evidence from the window) \| `transport_gap` (our browser queue overflowed) \| `blind_spot` (a boundary in the page, such as a cross-origin frame or a closed shadow root) \| `other`. Three owners, three fixes, and one bar on a dashboard until this existed. ONE value, not a list: a multi-value property is not something a breakdown can group by, so the first is sent, ours before the page's. **Absent whenever the capture was clean**, so its presence is itself the signal. Reported as `other` rather than omitted when the block says dirty and names nothing: a gap there would read as "no unclean verdicts happened". |
193
193
  | `project.stackUnknownReason` | `project_profiled` | WHY there is no `stack`, from core's closed `StackUnknownReason`: `no_app_found` \| `manifest_unrecognised` (we READ an app's manifest and knew nothing in it, which one line in `STACK_BY_DEP` fixes) \| `workspace_apps_unrecognised` \| `workspace_root_no_apps` (a monorepo root where discovery surfaced no app at all) \| `discovery_failed`. `stack` unknown is one of the largest buckets and an empty field is not a cause: it collapsed four facts with four different fixes. **Absent whenever a stack WAS found**, so its presence marks the unknown bucket. Note `workspace_root_no_apps` is expected to dominate over `workspace_apps_unrecognised`: `findWorkspaceApps` admits a directory only on a Vite/Next config file or a literal `next`/`vite` dependency, so a workspace app on any other framework is never surfaced and its manifest is never read. |
194
194
  | `bug.attribution` | `bug_found` | `app` \| `request` \| `reticle`: whose fault the defect was. **Absent means unclassified**, never `app`. See below. |
@@ -361,8 +361,8 @@ One deliberate exception to the rules above: `RETICLE_TELEMETRY_FILE` keeps tele
361
361
 
362
362
  | You are adding | Do this | Enforced by |
363
363
  | --- | --- | --- |
364
- | **A tool** | Add it to `TOOLS`. Nothing else. If its name implies a verdict (`assert`/`verify`), also add it to `VERIFICATION_TOOLS` | `telemetry-contract.test.ts` |
365
- | **A verdict-producing tool** | Add it to `VERIFICATION_TOOLS`. Otherwise it emits no `verification_completed` and stops counting toward the product's headline metric | ✓ |
364
+ | **A tool** | Add it to `TOOLS`. Nothing else. If its name implies a verdict (`assert`/`verify`), also add it to `VERDICT_TOOLS` | `telemetry-contract.test.ts` |
365
+ | **A verdict-producing tool** | Add it to `VERDICT_TOOLS` (`packages/server/src/tools/feedback-tools.ts`). Otherwise it emits no `verification_completed` and stops counting toward the product's headline metric | ✓ |
366
366
  | **A contradiction / anomaly kind** | Add it to core's enum only. `bug-found.ts` derives from it | ✓ |
367
367
  | **A new finding shape** in a tool result | Teach `bugsInResult` the field. Add a case to the contract test | ✓ |
368
368
  | **A failure path** (connect, install, crash) | Classify it into an enum with an explicit `OTHER` bucket; a classifier that cannot say "I don't know" lies instead | ✓ |
@@ -427,7 +427,7 @@ Read [`docs/telemetry-contract.md`](/telemetry-contract) before you touch anythi
427
427
  3. Add the payload key to `TelemetryEventSchema`.
428
428
  4. Add it to the emitter's key allowlist, or it will be silently dropped.
429
429
  5. Decide whether it is session-scoped and add it to `SESSION_SCOPED` if so.
430
- 6. If it produces a verdict, add the tool to `VERIFICATION_TOOLS`. If it introduces a finding kind, add that to core's enum and never re-list it locally.
430
+ 6. If it produces a verdict, add the tool to `VERDICT_TOOLS` (`packages/server/src/tools/feedback-tools.ts`). If it introduces a finding kind, add that to core's enum and never re-list it locally.
431
431
 
432
432
  `telemetry-contract.test.ts` enforces the parts that can be enforced, and `pnpm test:e2e` runs a spec that fires every event kind against a real capture endpoint and asserts each one lands.
433
433
 
package/docs/telemetry.md CHANGED
@@ -45,7 +45,7 @@ Eighteen kinds of events, each a single small JSON object. This is the whole lis
45
45
 
46
46
  **There is no per-tool-call event.** Tool usage is counted in memory and leaves once, inside `daemon_stopped`, as a histogram like `{"reticle_act": 40, "reticle_assert": 12}`. That is counts of tool NAMES from a fixed list we define, never arguments, results, selectors, or URLs.
47
47
 
48
- **Parameter and flag NAMES are collected; their VALUES are not.** We record that `reticle_act` was called with `ref` and `action`, and that you ran `reticle serve --headed --port`. We do not record what you set them to. This distinction is the whole safety property, and it is absolute for CLI flags: `--http-token` holds a secret, `--drive` holds a URL, `--storage-state` holds a file path, so no flag value is ever sent. For tool parameters there is one narrow exception: a short, explicit allowlist of parameters whose values are enums _we_ defined (`action: "click"`), listed in [`argument-shape.ts`](../packages/server/src/telemetry/argument-shape.ts). A value outside that allowlist reports as `other`, so a future schema change cannot quietly start forwarding free text. `reticle_act`'s `args` (the text being typed into your app, which on a login form is a password) is **never** in that allowlist.
48
+ **Parameter and flag NAMES are collected; their VALUES are not.** We record that `reticle_act` was called with `ref` and `action`, and that you ran `reticle serve --headed --port`. We do not record what you set them to. This distinction is the whole safety property, and it is absolute for CLI flags: `--http-token` holds a secret, `--drive` holds a URL, `--storage-state` holds a file path, so no flag value is ever sent. For tool parameters there is one narrow exception: a short, explicit allowlist of parameters whose values are enums _we_ defined (`action: "click"`), listed in [`argument-shape.ts`](https://github.com/reticlehq/reticle/blob/main/packages/server/src/telemetry/argument-shape.ts). A value outside that allowlist reports as `other`, so a future schema change cannot quietly start forwarding free text. `reticle_act`'s `args` (the text being typed into your app, which on a login form is a password) is **never** in that allowlist.
49
49
 
50
50
  `daemon_stopped` carries: how long the session ran, how many tool calls and of which tools, how long each tool took (total and worst case), how many failed, how many verifications ran, browser/lease connection attempts with their failure causes, and which MCP clients connected (`claude-code`, `cursor`).
51
51
 
@@ -53,7 +53,7 @@ It also carries a snapshot of the **machine's** state (our own process's memory,
53
53
 
54
54
  ### Why a verdict came out that way
55
55
 
56
- `verification_completed` carries the **clause** that decided the verdict, from a fixed list we define: `proved`, `contradicted`, `assertion_failed`, `already_true`, `unclean_capture`, `vacuous_grade`, `outcome_pending`, `outcome_unread`, `unsettled`, `evidence_incomplete`, `observation_lost`, `inconclusive`.
56
+ `verification_completed` carries the **clause** that decided the verdict, from a fixed list we define: `proved`, `contradicted`, `assertion_failed`, `already_true`, `unclean_capture`, `vacuous_grade`, `outcome_pending`, `outcome_unread`, `unsettled`, `evidence_incomplete`, `observation_lost`, `window_closed_early`, `inconclusive`.
57
57
 
58
58
  It exists because `verified: "unknown"` covered seven different situations belonging to three different owners (your app, your agent, and Reticle's own blind spots), and they arrived as one value. It is a **name from our own vocabulary**, never a description of your app: `contradicted` says two channels disagreed, not which ones, about what, or on which page.
59
59
 
@@ -127,7 +127,7 @@ Reticle verifies apps for AI agents, and for a long time it had no way to hear w
127
127
 
128
128
  Agents are instructed, in the tool description itself, never to include app source, secrets, or user data, and to describe the failure in their own words instead.
129
129
 
130
- **It is redacted before it leaves your machine.** Emails, credentials in URLs, `Authorization` headers and API-key assignments, recognizable vendor tokens (`sk-…`, `ghp_…`, `AKIA…`, `xoxb-…`, JWTs), and home-directory paths are stripped and replaced with `[redacted]`. This runs client-side, in [`feedback.ts`](../packages/server/src/telemetry/feedback.ts), so you can read exactly what it removes rather than take our word for it. It is a safety net, not a guarantee: it cannot catch a secret that looks like an ordinary sentence, which is why the instruction above comes first.
130
+ **It is redacted before it leaves your machine.** Emails, credentials in URLs, `Authorization` headers and API-key assignments, recognizable vendor tokens (`sk-…`, `ghp_…`, `AKIA…`, `xoxb-…`, JWTs), and home-directory paths are stripped and replaced with `[redacted]`. This runs client-side, in [`feedback.ts`](https://github.com/reticlehq/reticle/blob/main/packages/server/src/telemetry/feedback.ts), so you can read exactly what it removes rather than take our word for it. It is a safety net, not a guarantee: it cannot catch a secret that looks like an ordinary sentence, which is why the instruction above comes first.
131
131
 
132
132
  **It shows you what it sends.** `reticle feedback` prints the exact payload before transmitting, and names any redaction rule that fired.
133
133
 
@@ -17,13 +17,14 @@ Real response, with the throttled-tab `session` and `warning` fields trimmed off
17
17
  "ok": true,
18
18
  "url": "http://localhost:4310/deployments",
19
19
  "confirmed": false,
20
- "note": "ok means the navigation was DISPATCHED, not that the page arrived. The SDK is torn down by the navigation itself, so nothing here can see the new document. Call reticle_sessions to confirm a session reconnected at the new URL before acting; if none appears, the page did not load or is not instrumented."
20
+ "waitedMs": 5000,
21
+ "note": "ok means the navigation was DISPATCHED, not that the page arrived. The SDK is torn down by the navigation itself, so nothing here can see the new document, and no session reconnected at the new URL within 5000ms. A slow app may still be on its way (an SPA reattaching under HMR can take 30-60s): navigate again with a larger timeout_ms, or call reticle_sessions to confirm a session reconnected before acting; if none appears, the page did not load or is not instrumented."
21
22
  }
22
23
  ```
23
24
 
24
25
  ## `confirmed: true` when the page comes back in time
25
26
 
26
- The daemon waits briefly for the SDK to re-announce itself. When it does, you are told so and can act immediately without a `reticle_sessions` round trip. This is a real reload response:
27
+ The daemon waits up to `timeout_ms` (default 5000) for the SDK to re-announce itself. When it does, you are told so and can act immediately without a `reticle_sessions` round trip. This is a real reload response:
27
28
 
28
29
  ```json
29
30
  {
@@ -41,6 +42,12 @@ A full navigation destroys the document the SDK was living in. Reticle cannot re
41
42
 
42
43
  Most tools would return `ok: true` and let you assume arrival. When the page then fails to load, or loads without instrumentation, you get a confusing cascade of "element not found" errors several calls later, with nothing pointing at the real cause.
43
44
 
45
+ `waitedMs` says which of two things you are looking at. Reticle stopped waiting at the budget it had, or the page never came back. The first is fixed by asking for more: a single-page app reattaching under HMR has been measured at 30–60s, which no default should wait for on every call, but which the caller who knows the app can grant.
46
+
47
+ ```json
48
+ { "url": "/deployments", "timeout_ms": 45000 }
49
+ ```
50
+
44
51
  ## The pattern after navigating
45
52
 
46
53
  ```json
@@ -64,11 +71,12 @@ with [`reticle_sessions`](/tools-sessions), and only then snapshot. If no sessio
64
71
 
65
72
  ## Arguments
66
73
 
67
- | Argument | What it does |
68
- | -------- | ------------------------------------- |
69
- | `url` | Where to go. Relative paths work |
74
+ | Argument | What it does |
75
+ | --- | --- |
76
+ | `url` | Where to go. Relative paths work |
70
77
  | `reload` | Reload in place instead of navigating |
71
- | `hard` | With `reload`, bypass the cache |
78
+ | `hard` | With `reload`, bypass the cache |
79
+ | `timeout_ms` | How long to wait for the page to come back before `confirmed: false`. Default 5000; 0 looks once |
72
80
 
73
81
  ## Client-side routing is different
74
82
 
package/docs/usage.md CHANGED
@@ -310,9 +310,9 @@ reticle_session {action:"review"}({ sessionId })
310
310
 
311
311
  Each pending mark carries the human note, the element label, the source **`file:line`** (when the framework stamped one), and a ready-to-act `fix` hint. Open the file, apply the fix, then `reticle_session {action:"review"}({ resolve: "m1" })`. The human watching the panel sees **"✓ fixed: …"** land. Reading never consumes a mark, so you can list → fix → verify → resolve. `reticle_sessions` also reports `pendingMarks` so you notice flagged bugs during normal orientation.
312
312
 
313
- ### `reticle_network_mock`: stub the network for error-state testing (driven mode)
313
+ ### `reticle_network_mock`: stub the network for error-state testing
314
314
 
315
- On a page Reticle drives (`reticle drive`), make a request return a 500, force it offline, or delay it, so testing error/edge states is one declared rule, no backend changes:
315
+ On a page Reticle drives (`reticle drive`) or a leased Playwright tab (`reticle_lease acquire`), make a request return a 500, force it offline, or delay it, so testing error/edge states is one declared rule, no backend changes:
316
316
 
317
317
  ```
318
318
  reticle_network_mock({ mocks: [{ urlContains: "/api/pay", method: "POST", status: 500 }] })
@@ -321,7 +321,7 @@ reticle_network_mock({ mocks: [{ urlContains: "/api/feed", abort: true }] }) /
321
321
  reticle_network_mock({ clear: true }) // turn mocking off
322
322
  ```
323
323
 
324
- First matching rule wins (`urlContains` + optional case-insensitive `method`). Needs a driven browser; without one it returns a `recommendation` pointing at `reticle drive`.
324
+ First matching rule wins (`urlContains` + optional case-insensitive `method`). Needs a driven or leased browser; without one it returns a `recommendation` pointing at `reticle drive`.
325
325
 
326
326
  ### `reticle_viewport`: reproducible visual baselines (driven mode)
327
327
 
@@ -597,7 +597,7 @@ export default [
597
597
  ];
598
598
  ```
599
599
 
600
- `mutators` lists the callee names that change state; `signalCallee` (default `['reticleSignal', 'signal']`) is the name that counts as firing a signal. See [`packages/eslint-plugin/README.md`](../packages/eslint-plugin/README.md) for scoping and matching details.
600
+ `mutators` lists the callee names that change state; `signalCallee` (default `['reticleSignal', 'signal']`) is the name that counts as firing a signal. See [`packages/eslint-plugin/README.md`](https://github.com/reticlehq/reticle/blob/main/packages/eslint-plugin/README.md) for scoping and matching details.
601
601
 
602
602
  ---
603
603
 
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@reticlehq/server",
3
- "version": "2.13.1",
3
+ "version": "2.14.0",
4
4
  "description": "Reticle bridge + MCP server. Hosts the browser WS endpoint and exposes MCP tools to the coding agent.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "bin": {
9
- "reticle": "./dist/cli.js"
9
+ "reticle": "./bin/reticle.js"
10
10
  },
11
11
  "exports": {
12
12
  ".": {
@@ -22,7 +22,8 @@
22
22
  "@modelcontextprotocol/sdk": "^1.30.0",
23
23
  "ws": "^8.21.3",
24
24
  "zod": "^3.24.1",
25
- "@reticlehq/core": "2.13.1"
25
+ "@reticlehq/core": "2.14.0",
26
+ "@reticlehq/init": "2.14.0"
26
27
  },
27
28
  "devDependencies": {
28
29
  "@types/pngjs": "^6.0.5",
@@ -44,6 +45,7 @@
44
45
  "homepage": "https://github.com/reticlehq/reticle#readme",
45
46
  "bugs": "https://github.com/reticlehq/reticle/issues",
46
47
  "files": [
48
+ "bin",
47
49
  "dist",
48
50
  "README.md",
49
51
  "LICENSE-ENTERPRISE",
@@ -71,7 +73,8 @@
71
73
  "dev": "tsc -b --watch",
72
74
  "typecheck": "tsc -b",
73
75
  "lint": "eslint src",
74
- "test:unit": "vitest run src --passWithNoTests",
76
+ "test:unit": "node ../../scripts/guard-tests.mjs unit",
77
+ "test:guards": "node ../../scripts/guard-tests.mjs guards",
75
78
  "test:coverage": "vitest run src --passWithNoTests --coverage.enabled --coverage.provider=v8 --coverage.reporter=text-summary --coverage.include='src/**/*.ts' --coverage.exclude='src/**/*.test.ts'"
76
79
  }
77
80
  }
@@ -1,116 +0,0 @@
1
- /**
2
- * `reticle init` writes a behavioral rule into the coding agent's instruction file so the agent
3
- * VERIFIES a feature with Reticle after building it — not only when the user remembers to say "test
4
- * it with reticle". Registering the MCP server (mcp.ts / mcp-clients.ts) only makes the tools AVAILABLE;
5
- * this is the piece that makes the agent reach for them, every session, unprompted.
6
- *
7
- * It carries a SECOND standing instruction, and that one is not about this project at all: send
8
- * feedback to the Reticle maintainers, from the moment instrumentation starts. The agent is the party
9
- * that experiences Reticle, and the only one who can say what it cost — and by the time anyone would
10
- * think to ask, the context that knew is gone. Written into the same block, because the moment the
11
- * rule lands (init, before any framework wiring) is the moment the setup itself is being lived
12
- * through, which is when the reports we hear least about are actually generated.
13
- *
14
- * The rule is framed as a definition-of-done (WHEN to verify, HOW, and the anti-reward-hacking guard),
15
- * written into whichever instruction file the detected agent reads: `CLAUDE.md` (Claude Code),
16
- * `.cursor/rules/reticle.mdc` (Cursor, `alwaysApply` so it stays in context), or `AGENTS.md` as the
17
- * cross-agent fallback. Idempotent via a marker block — safe to append to an existing file and a
18
- * re-run is a no-op. Mirrors the apply/already result shape used across init (see mcp-clients.ts).
19
- */
20
- /** Project-root instruction files the agent re-reads every session. */
21
- export declare const CLAUDE_MD_PATH = "CLAUDE.md";
22
- export declare const AGENTS_MD_PATH = "AGENTS.md";
23
- /**
24
- * The full rules, written once and pointed at from every always-loaded file.
25
- *
26
- * Two problems it solves at the same time. The rule text is dense and most of it is REFERENCE (what
27
- * to do when the tools are missing, what a `version_skew` field means, how to file feedback), which
28
- * an agent needs on the turn it hits that situation and never before — so carrying all of it in
29
- * `CLAUDE.md` taxed every session for text almost every session did not read. And `AGENTS.md` was
30
- * only written when NO agent was detected, so a repo set up on a Claude Code machine told Codex,
31
- * Copilot, Amp and every other agent nothing at all.
32
- *
33
- * So: the operative rules (when to verify, WHEN NOT TO, how, and the honesty guards) go in the files
34
- * that load every turn, and this file holds the rest, one hop away and named in that block.
35
- */
36
- export declare const RETICLE_MD_PATH = "RETICLE.md";
37
- /** Cursor project rule; the frontmatter `alwaysApply` keeps it in context on every turn. */
38
- export declare const CURSOR_RULE_PATH = ".cursor/rules/reticle.mdc";
39
- /**
40
- * Does this file already carry the managed block?
41
- *
42
- * Exported so callers cannot invent their own looser test. The begin marker carries explanatory
43
- * text inside the comment, so a substring check for `reticle:begin` matches files that
44
- * `mergeMarkedInstruction` would treat as having NO block — and the two disagreeing means a refresh
45
- * silently appends a second copy instead of updating the first.
46
- */
47
- export declare function hasManagedBlock(text: string): boolean;
48
- /**
49
- * How the agent must INVOKE the CLI.
50
- *
51
- * `reticle init` installs the SDK packages, never the server — so there is no `reticle` on the
52
- * agent's PATH, and every bare `reticle <cmd>` this rule named was an instruction that could not be
53
- * followed. Reported from a field sweep: three of them, in the file the agent re-reads every session.
54
- *
55
- * `npx @reticlehq/server` is the same invocation the MCP registration uses, and it is derived from
56
- * the package's own name so the two can never drift apart.
57
- */
58
- export declare const CLI: string;
59
- /**
60
- * Who starts the dev server, stated once and rendered everywhere it is needed.
61
- *
62
- * The old rule was "Reticle never starts the dev server for you — that's your job", and agents obeyed
63
- * it exactly: they read it, declined to start anything, and ended the turn with nothing verified. An
64
- * instruction that reliably produces no verification is a defect in the instruction.
65
- *
66
- * The AGENT starts it, not the daemon. A daemon that spawns a build process is invisible to the
67
- * person whose machine it is running on, was never consented to, and orphans when the daemon exits.
68
- * The agent already has shell access in this repo, already runs install and build commands, and runs
69
- * inside a host that asks the human for permission — so a dev server it starts is visible in the
70
- * transcript, attributable, and stoppable.
71
- *
72
- * The guards are the whole reason this is safe, so no renderer may drop them: one server at a time,
73
- * read the command rather than invent one, never kill anything you did not start, and leave the
74
- * permission prompt to the host. "Background it and say so" is no longer among them because the
75
- * branch above now states it at the point of action, and this text is read every turn — a rule
76
- * stated twice costs every agent tokens forever and is the first thing to drift.
77
- *
78
- * The RESTART branch outranks the rest and is stated first. It used to be an aside, while "if a dev
79
- * server is already listening, use it" was a numbered guard — so an agent resolving the two
80
- * reasonably reused a server started before `init` edited the build config, served a bundle with no
81
- * SDK in it, and landed on an empty session list with every other step done correctly.
82
- *
83
- * Exported because slash-command.ts renders the same rule; there must not be two versions of it.
84
- */
85
- export declare const DEV_SERVER_POLICY = "**A dev server already running when `reticle init` ran does not have Reticle in its bundle.** It read the build config at boot; `init` edited it afterwards. It serves the old bundle and no session appears. In order:\n\n1. **A dev server was already running?** Restart it, then hard-reload the tab. \"Something is listening\" does not mean the right bundle is served.\n2. **Nothing was running?** Start it in the BACKGROUND and say so in one line. `reticle_sessions` gives you this project's own dev command in `next_action`; use that, never compose one. Started after `init`, it needs no restart.\n\nStopping to ask is how a verification turn ends with nothing verified.\n\nFour guards, none optional:\n\n1. **Never run two at once.** One dev server on the app's port. Restarting a stale one means stopping it first, not starting a second alongside it.\n2. **Never guess the command.** It comes from `package.json` scripts. No recognisable dev script means say so and stop, not invent one.\n3. **Never kill anything you did not start**, and never a daemon or a port holder. The one exception is the restart above, and say in one line that you did it.\n4. **The permission prompt belongs to your host.** Never bypass, suppress or auto-approve it, and take a refusal as the answer.";
86
- /**
87
- * The operative rules, carried by every file that loads on every turn.
88
- *
89
- * Short on purpose. This is the text that has to CHANGE BEHAVIOUR, so it states when to verify, when
90
- * NOT to, how, and the guards against calling something proven when it is not. Everything an agent
91
- * needs only at the moment it hits a specific situation lives in RETICLE.md, named at the end.
92
- */
93
- export declare const RULE_BODY: string;
94
- /** The full-rules file, written verbatim (no markers: `init` owns this file entirely). */
95
- export declare function reticleMdFile(): string;
96
- export declare const AgentRuleStatus: {
97
- readonly APPLY: "apply";
98
- readonly ALREADY: "already";
99
- };
100
- export type AgentRuleStatus = (typeof AgentRuleStatus)[keyof typeof AgentRuleStatus];
101
- interface AgentRuleResult {
102
- status: AgentRuleStatus;
103
- /** Full file content to write when status is APPLY; the unchanged input otherwise. */
104
- content: string;
105
- }
106
- /** The marker-wrapped block appended to a CLAUDE.md / AGENTS.md instruction file. */
107
- export declare function markedBlock(): string;
108
- /**
109
- * Merge the managed block into a marker-delimited instruction file. Already present ⇒ no change
110
- * (idempotent re-run). Absent/empty ⇒ the block alone. Otherwise append the block, preserving the
111
- * existing content and a clean separating blank line.
112
- */
113
- export declare function mergeMarkedInstruction(existing: string | null | undefined): AgentRuleResult;
114
- /** The Cursor rule file (.mdc): `alwaysApply` keeps the rule in every turn's context. */
115
- export declare function cursorRuleFile(): string;
116
- export {};