@reticlehq/server 3.8.2 → 3.10.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 (477) hide show
  1. package/LICENSE +201 -104
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/SKILL.md +13 -12
  5. package/bin/launch.js +13 -0
  6. package/bin/package.json +3 -0
  7. package/bin/reticle.js +66 -8
  8. package/dist/chromium-launch-options.d.ts +25 -0
  9. package/dist/chromium-launch-options.js +21 -1
  10. package/dist/command/cli/adhoc-suite.js +2 -0
  11. package/dist/command/cli/adhoc-verdict.d.ts +2 -43
  12. package/dist/command/cli/adhoc-verdict.js +50 -160
  13. package/dist/command/cli/answers/gate-exit.d.ts +6 -2
  14. package/dist/command/cli/answers/gate-exit.js +12 -2
  15. package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
  16. package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
  17. package/dist/command/cli/ci-hint.d.ts +44 -0
  18. package/dist/command/cli/ci-hint.js +72 -0
  19. package/dist/command/cli/cli-doctor.d.ts +6 -1
  20. package/dist/command/cli/cli-doctor.js +46 -5
  21. package/dist/command/cli/cli-flow-commands.d.ts +7 -1
  22. package/dist/command/cli/cli-flow-commands.js +39 -24
  23. package/dist/command/cli/cli-kill.d.ts +21 -0
  24. package/dist/command/cli/cli-kill.js +47 -4
  25. package/dist/command/cli/cli-parse-compare.d.ts +22 -0
  26. package/dist/command/cli/cli-parse-compare.js +75 -0
  27. package/dist/command/cli/cli-parse-grade.d.ts +36 -0
  28. package/dist/command/cli/cli-parse-grade.js +75 -0
  29. package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
  30. package/dist/command/cli/cli-parse-grammar.js +18 -20
  31. package/dist/command/cli/cli-parse-verify.d.ts +10 -0
  32. package/dist/command/cli/cli-parse-verify.js +63 -14
  33. package/dist/command/cli/cli-parse.d.ts +22 -17
  34. package/dist/command/cli/cli-parse.js +54 -32
  35. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  36. package/dist/command/cli/cli-update-commands.js +29 -20
  37. package/dist/command/cli/cli-usage.js +61 -31
  38. package/dist/command/cli/cli-verify.d.ts +17 -3
  39. package/dist/command/cli/cli-verify.js +59 -21
  40. package/dist/command/cli/cloud-cli.js +2 -119
  41. package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
  42. package/dist/command/cli/daemon-link/daemon-client.js +205 -0
  43. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
  44. package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
  45. package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
  46. package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
  47. package/dist/command/cli/doctor/doctor-fix.js +89 -0
  48. package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
  49. package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
  50. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  51. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  52. package/dist/command/cli/doctor-repairs.d.ts +64 -0
  53. package/dist/command/cli/doctor-repairs.js +214 -0
  54. package/dist/command/cli/drive/drive-command.js +3 -7
  55. package/dist/command/cli/ensure-daemon.d.ts +26 -0
  56. package/dist/command/cli/ensure-daemon.js +57 -0
  57. package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
  58. package/dist/command/cli/finished-run/grade-command.js +180 -0
  59. package/dist/command/cli/first-use-checks.d.ts +41 -0
  60. package/dist/command/cli/first-use-checks.js +127 -0
  61. package/dist/command/cli/first-verdict-node.d.ts +3 -0
  62. package/dist/command/cli/first-verdict-node.js +189 -0
  63. package/dist/command/cli/first-verdict.d.ts +126 -0
  64. package/dist/command/cli/first-verdict.js +267 -0
  65. package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
  66. package/dist/command/cli/launch/sdk-version-match.js +3 -2
  67. package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
  68. package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
  69. package/dist/command/cli/mcp-command.js +13 -4
  70. package/dist/command/cli/ports/port-holder.d.ts +11 -0
  71. package/dist/command/cli/ports/port-holder.js +36 -4
  72. package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
  73. package/dist/command/cli/setup-mcp-cli.js +98 -23
  74. package/dist/command/cli/status/status-lines.d.ts +2 -0
  75. package/dist/command/cli/status/status-lines.js +72 -17
  76. package/dist/command/cli/status-fields.d.ts +5 -1
  77. package/dist/command/cli/status-fields.js +24 -6
  78. package/dist/command/cli/try-command.d.ts +7 -0
  79. package/dist/command/cli/try-command.js +11 -3
  80. package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
  81. package/dist/command/cli/two-builds/compare-command.js +314 -0
  82. package/dist/command/cli/verify-against.d.ts +61 -0
  83. package/dist/command/cli/verify-against.js +187 -0
  84. package/dist/command/cli/verify-no-session.d.ts +2 -0
  85. package/dist/command/cli/verify-no-session.js +13 -0
  86. package/dist/command/cli/verify-results.d.ts +35 -2
  87. package/dist/command/cli/verify-results.js +76 -10
  88. package/dist/command/cli.js +112 -70
  89. package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
  90. package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
  91. package/dist/command/daemon/daemon-argv.d.ts +9 -0
  92. package/dist/command/daemon/daemon-argv.js +11 -0
  93. package/dist/command/daemon/daemon-resolve.d.ts +8 -1
  94. package/dist/command/daemon/daemon-resolve.js +27 -1
  95. package/dist/command/daemon/daemon.d.ts +22 -4
  96. package/dist/command/daemon/daemon.js +52 -10
  97. package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
  98. package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
  99. package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
  100. package/dist/command/daemon/lifetime/death-cause.js +149 -0
  101. package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
  102. package/dist/command/daemon/lifetime/heartbeat.js +11 -15
  103. package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
  104. package/dist/command/daemon/lifetime/startup-failure.js +62 -0
  105. package/dist/command/daemon/port-state.d.ts +14 -0
  106. package/dist/command/daemon/port-state.js +31 -0
  107. package/dist/command/setup/agent-configs.d.ts +2 -0
  108. package/dist/command/setup/agent-configs.js +42 -15
  109. package/dist/command/setup/agent-next-steps.d.ts +77 -0
  110. package/dist/command/setup/agent-next-steps.js +284 -0
  111. package/dist/command/setup/agent-writer.js +11 -6
  112. package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
  113. package/dist/command/setup/bringup/dev-server-files.js +17 -0
  114. package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
  115. package/dist/command/setup/bringup/static-page-server.js +43 -9
  116. package/dist/command/setup/init/init-host.js +2 -0
  117. package/dist/command/setup/init/init-runtime.d.ts +6 -1
  118. package/dist/command/setup/init/init-runtime.js +63 -21
  119. package/dist/command/setup/mcp-launcher.d.ts +3 -0
  120. package/dist/command/setup/mcp-launcher.js +11 -0
  121. package/dist/command/setup/node-effects.d.ts +3 -2
  122. package/dist/command/setup/node-effects.js +9 -3
  123. package/dist/command/setup/remaining-steps.d.ts +8 -0
  124. package/dist/command/setup/remaining-steps.js +10 -0
  125. package/dist/command/setup/run-setup.d.ts +2 -0
  126. package/dist/command/setup/run-setup.js +9 -1
  127. package/dist/command/setup/setup-command.js +36 -15
  128. package/dist/command/setup/setup-mcp.d.ts +8 -0
  129. package/dist/command/setup/setup-mcp.js +47 -20
  130. package/dist/command/setup/start-dev-server.d.ts +8 -0
  131. package/dist/command/setup/start-dev-server.js +43 -0
  132. package/dist/command/update/updater.js +6 -0
  133. package/dist/command/version/identity/server-version.d.ts +2 -0
  134. package/dist/command/version/identity/server-version.js +2 -0
  135. package/dist/command/version/version-skew.d.ts +7 -0
  136. package/dist/command/version/version-skew.js +14 -3
  137. package/dist/features/compare/action-plan.d.ts +260 -0
  138. package/dist/features/compare/action-plan.js +543 -0
  139. package/dist/features/compare/behaviour-compare.d.ts +24 -0
  140. package/dist/features/compare/behaviour-compare.js +85 -0
  141. package/dist/features/compare/behaviour-diff.d.ts +97 -0
  142. package/dist/features/compare/behaviour-diff.js +202 -0
  143. package/dist/features/compare/behaviour-report.d.ts +40 -0
  144. package/dist/features/compare/behaviour-report.js +128 -0
  145. package/dist/features/compare/build-readings.d.ts +106 -0
  146. package/dist/features/compare/build-readings.js +250 -0
  147. package/dist/features/compare/compare-diff.d.ts +62 -0
  148. package/dist/features/compare/compare-diff.js +177 -0
  149. package/dist/features/compare/compare-report-html.d.ts +6 -0
  150. package/dist/features/compare/compare-report-html.js +102 -0
  151. package/dist/features/compare/compare-report.d.ts +15 -0
  152. package/dist/features/compare/compare-report.js +73 -0
  153. package/dist/features/compare/compare-run.d.ts +60 -0
  154. package/dist/features/compare/compare-run.js +123 -0
  155. package/dist/features/compare/outside/effect-lines.d.ts +26 -0
  156. package/dist/features/compare/outside/effect-lines.js +103 -0
  157. package/dist/features/compare/outside/state-sources.d.ts +76 -0
  158. package/dist/features/compare/outside/state-sources.js +164 -0
  159. package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
  160. package/dist/features/compare/outside/value-dictionary.js +227 -0
  161. package/dist/features/compare/visible-content.d.ts +20 -0
  162. package/dist/features/compare/visible-content.js +125 -0
  163. package/dist/features/crawl/crawl-empty.js +2 -1
  164. package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
  165. package/dist/features/crawl/crawl-exhaustive.js +138 -0
  166. package/dist/features/crawl/crawl-tools.d.ts +9 -2
  167. package/dist/features/crawl/crawl-tools.js +28 -12
  168. package/dist/features/crawl/crawl.d.ts +8 -9
  169. package/dist/features/crawl/crawl.js +61 -65
  170. package/dist/features/exhaust/app-coverage.d.ts +5 -1
  171. package/dist/features/exhaust/app-coverage.js +3 -1
  172. package/dist/features/exhaust/code-coverage.js +8 -4
  173. package/dist/features/exhaust/edge-cases.d.ts +133 -0
  174. package/dist/features/exhaust/edge-cases.js +310 -0
  175. package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
  176. package/dist/features/exhaust/edges/edge-drive.js +364 -0
  177. package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
  178. package/dist/features/exhaust/edges/edge-run.js +169 -0
  179. package/dist/features/exhaust/explorer.d.ts +87 -14
  180. package/dist/features/exhaust/explorer.js +159 -25
  181. package/dist/features/exhaust/failure-branches.d.ts +5 -0
  182. package/dist/features/exhaust/failure-branches.js +29 -11
  183. package/dist/features/exhaust/invariants.d.ts +112 -0
  184. package/dist/features/exhaust/invariants.js +188 -0
  185. package/dist/features/exhaust/ledger.d.ts +68 -0
  186. package/dist/features/exhaust/ledger.js +121 -13
  187. package/dist/features/exhaust/session-fold.d.ts +10 -0
  188. package/dist/features/exhaust/session-fold.js +46 -3
  189. package/dist/features/exhaust/session-port.d.ts +3 -1
  190. package/dist/features/exhaust/session-port.js +97 -28
  191. package/dist/features/grade/grade-answer.d.ts +99 -0
  192. package/dist/features/grade/grade-answer.js +112 -0
  193. package/dist/features/grade/grade-noise.d.ts +27 -0
  194. package/dist/features/grade/grade-noise.js +55 -0
  195. package/dist/features/grade/grade-renumber.d.ts +12 -0
  196. package/dist/features/grade/grade-renumber.js +86 -0
  197. package/dist/features/grade/grade-state.d.ts +50 -0
  198. package/dist/features/grade/grade-state.js +93 -0
  199. package/dist/features/grade/grade-suggest.d.ts +33 -0
  200. package/dist/features/grade/grade-suggest.js +98 -0
  201. package/dist/features/license/license.d.ts +11 -71
  202. package/dist/features/license/license.js +43 -136
  203. package/dist/features/visual/desktop-capture.d.ts +33 -0
  204. package/dist/features/visual/desktop-capture.js +94 -0
  205. package/dist/features/visual/step-shots.js +139 -35
  206. package/dist/features/visual/visual-tools.d.ts +0 -18
  207. package/dist/features/visual/visual-tools.js +67 -99
  208. package/dist/import-graph.js +5 -6
  209. package/dist/index.d.ts +3 -1
  210. package/dist/index.js +19 -7
  211. package/dist/judgement/capsule/causal-summary.js +9 -2
  212. package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
  213. package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
  214. package/dist/judgement/runs/reticle-runner.js +16 -2
  215. package/dist/judgement/runs/run-ledger.d.ts +7 -5
  216. package/dist/judgement/runs/run-ledger.js +98 -69
  217. package/dist/judgement/runs/runner-port.d.ts +2 -0
  218. package/dist/judgement/runs/runner-port.js +23 -5
  219. package/dist/judgement/runs/verification-sync.d.ts +6 -3
  220. package/dist/judgement/runs/verification-sync.js +21 -10
  221. package/dist/language/flows/affected-tools.d.ts +1 -1
  222. package/dist/language/flows/affected-tools.js +49 -30
  223. package/dist/language/flows/change/git-changed.d.ts +2 -1
  224. package/dist/language/flows/change/git-changed.js +19 -2
  225. package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
  226. package/dist/language/flows/fields/flow-secret-field.js +77 -21
  227. package/dist/language/flows/flow-anchor.d.ts +60 -2
  228. package/dist/language/flows/flow-anchor.js +125 -20
  229. package/dist/language/flows/flow-classify.d.ts +20 -0
  230. package/dist/language/flows/flow-classify.js +90 -12
  231. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  232. package/dist/language/flows/flow-cross-step.js +25 -1
  233. package/dist/language/flows/flow-journey.d.ts +38 -4
  234. package/dist/language/flows/flow-journey.js +138 -8
  235. package/dist/language/flows/flow-replay-run.d.ts +0 -16
  236. package/dist/language/flows/flow-replay-run.js +76 -14
  237. package/dist/language/flows/flow-replay-types.d.ts +4 -2
  238. package/dist/language/flows/flow-replay.d.ts +19 -1
  239. package/dist/language/flows/flow-replay.js +169 -52
  240. package/dist/language/flows/flow-replayable.js +7 -1
  241. package/dist/language/flows/flow-start-path.d.ts +34 -5
  242. package/dist/language/flows/flow-start-path.js +202 -15
  243. package/dist/language/flows/flow-step-runners.d.ts +14 -13
  244. package/dist/language/flows/flow-step-runners.js +184 -109
  245. package/dist/language/flows/flow-store-for-session.d.ts +26 -25
  246. package/dist/language/flows/flow-store-for-session.js +51 -5
  247. package/dist/language/flows/flow-tools.js +46 -33
  248. package/dist/language/flows/flows.js +176 -76
  249. package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
  250. package/dist/language/flows/recording/tape/recordings.js +112 -49
  251. package/dist/language/flows/replay.d.ts +36 -12
  252. package/dist/language/flows/replay.js +193 -50
  253. package/dist/language/flows/steps/page-steps.d.ts +68 -0
  254. package/dist/language/flows/steps/page-steps.js +198 -0
  255. package/dist/language/flows/suite/sequential-run.d.ts +68 -0
  256. package/dist/language/flows/suite/sequential-run.js +96 -0
  257. package/dist/language/flows/verify-change-tools.js +26 -15
  258. package/dist/launch-chromium.d.ts +1 -0
  259. package/dist/launch-chromium.js +49 -12
  260. package/dist/memory/cloud/background-sync.d.ts +13 -0
  261. package/dist/memory/cloud/background-sync.js +24 -3
  262. package/dist/memory/cloud/sync-daemon.js +26 -27
  263. package/dist/memory/cloud/sync-screenshots.js +6 -1
  264. package/dist/memory/journal/attach-journal.js +2 -1
  265. package/dist/memory/journal/drive-flow.d.ts +7 -0
  266. package/dist/memory/journal/drive-flow.js +44 -13
  267. package/dist/memory/journal/journal-recorder.d.ts +4 -2
  268. package/dist/memory/journal/session-journal.d.ts +7 -0
  269. package/dist/memory/journal/session-journal.js +58 -10
  270. package/dist/memory/project/root-claims.d.ts +9 -0
  271. package/dist/memory/project/root-claims.js +9 -4
  272. package/dist/portal/bridge/bridge.d.ts +13 -4
  273. package/dist/portal/bridge/bridge.js +10 -9
  274. package/dist/portal/input/download-capture.d.ts +7 -0
  275. package/dist/portal/input/download-capture.js +92 -0
  276. package/dist/portal/input/network-detail.d.ts +6 -0
  277. package/dist/portal/input/network-detail.js +12 -1
  278. package/dist/portal/input/network-mock-tools.js +49 -13
  279. package/dist/portal/input/network-mock.d.ts +8 -0
  280. package/dist/portal/input/network-mock.js +30 -10
  281. package/dist/portal/input/page-capture.d.ts +24 -0
  282. package/dist/portal/input/page-capture.js +33 -0
  283. package/dist/portal/input/real-input.d.ts +35 -18
  284. package/dist/portal/input/real-input.js +99 -33
  285. package/dist/portal/input/viewport-tools.d.ts +8 -0
  286. package/dist/portal/input/viewport-tools.js +81 -21
  287. package/dist/portal/pool/browser-pool.d.ts +16 -30
  288. package/dist/portal/pool/browser-pool.js +64 -52
  289. package/dist/portal/pool/context-permissions.d.ts +34 -17
  290. package/dist/portal/pool/context-permissions.js +94 -1
  291. package/dist/portal/pool/csp-widen.d.ts +62 -0
  292. package/dist/portal/pool/csp-widen.js +132 -0
  293. package/dist/portal/pool/determinism.d.ts +52 -0
  294. package/dist/portal/pool/determinism.js +259 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +34 -1
  296. package/dist/portal/pool/lease-emulation.js +18 -0
  297. package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
  298. package/dist/portal/pool/lease-marker-stamp.js +15 -1
  299. package/dist/portal/pool/lease-page-error.d.ts +56 -0
  300. package/dist/portal/pool/lease-page-error.js +160 -0
  301. package/dist/portal/pool/page-error-journal.d.ts +63 -0
  302. package/dist/portal/pool/page-error-journal.js +208 -0
  303. package/dist/portal/pool/playwright-launcher.js +71 -15
  304. package/dist/portal/pool/pool-contract.d.ts +49 -1
  305. package/dist/portal/pool/pool-lease.d.ts +70 -2
  306. package/dist/portal/pool/pool-lease.js +23 -0
  307. package/dist/portal/pool/zero-install.d.ts +8 -0
  308. package/dist/portal/pool/zero-install.js +91 -1
  309. package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
  310. package/dist/portal/session/dev-server/dev-command.js +110 -16
  311. package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
  312. package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
  313. package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
  314. package/dist/portal/session/dev-server/project-ports.js +62 -0
  315. package/dist/portal/session/facts/departed-network.d.ts +66 -0
  316. package/dist/portal/session/facts/departed-network.js +142 -0
  317. package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
  318. package/dist/portal/session/no-session-diagnosis.js +76 -27
  319. package/dist/portal/session/no-session-next-action.d.ts +14 -0
  320. package/dist/portal/session/no-session-next-action.js +56 -7
  321. package/dist/portal/session/no-session-watch.d.ts +6 -0
  322. package/dist/portal/session/no-session-watch.js +41 -4
  323. package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
  324. package/dist/portal/session/page-commands/undeclared-command.js +16 -7
  325. package/dist/portal/session/recorded-gaps.d.ts +1 -1
  326. package/dist/portal/session/recorded-gaps.js +5 -2
  327. package/dist/portal/session/serving-directory.d.ts +10 -0
  328. package/dist/portal/session/serving-directory.js +39 -8
  329. package/dist/portal/session/session-manager.d.ts +10 -0
  330. package/dist/portal/session/session-manager.js +211 -81
  331. package/dist/portal/session/session.js +4 -3
  332. package/dist/portal/session/zero-install-first-call.d.ts +20 -1
  333. package/dist/portal/session/zero-install-first-call.js +34 -2
  334. package/dist/start-wiring.d.ts +30 -2
  335. package/dist/start-wiring.js +74 -9
  336. package/dist/surface/mcp/mcp-proxy.js +10 -2
  337. package/dist/surface/mcp/mcp.js +8 -5
  338. package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
  339. package/dist/surface/mcp/peer/agents-connected.js +58 -0
  340. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
  341. package/dist/surface/mcp/shared-params.d.ts +2 -0
  342. package/dist/surface/mcp/shared-params.js +31 -0
  343. package/dist/surface/tools/act/act-observation.d.ts +40 -2
  344. package/dist/surface/tools/act/act-observation.js +118 -12
  345. package/dist/surface/tools/act/act-preflight.js +38 -18
  346. package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
  347. package/dist/surface/tools/act/act-sequence-retry.js +61 -5
  348. package/dist/surface/tools/act/act-target.js +3 -1
  349. package/dist/surface/tools/act/after-match.d.ts +10 -0
  350. package/dist/surface/tools/act/after-match.js +40 -0
  351. package/dist/surface/tools/act/already-true.js +1 -1
  352. package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
  353. package/dist/surface/tools/act/navigation/reload-result.js +25 -2
  354. package/dist/surface/tools/act/resolve-target.d.ts +17 -1
  355. package/dist/surface/tools/act/resolve-target.js +59 -9
  356. package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
  357. package/dist/surface/tools/act/sequence-grade.js +45 -27
  358. package/dist/surface/tools/act/settle-in-flight.js +27 -15
  359. package/dist/surface/tools/act-command.d.ts +23 -0
  360. package/dist/surface/tools/act-command.js +50 -0
  361. package/dist/surface/tools/act-sequence-tool.js +81 -50
  362. package/dist/surface/tools/act-tools.d.ts +1 -13
  363. package/dist/surface/tools/act-tools.js +83 -95
  364. package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
  365. package/dist/surface/tools/agent/build-staleness.js +1 -1
  366. package/dist/surface/tools/assert/assert-verdict.js +18 -12
  367. package/dist/surface/tools/browser-tools.js +87 -13
  368. package/dist/surface/tools/compare-tools.d.ts +11 -0
  369. package/dist/surface/tools/compare-tools.js +94 -0
  370. package/dist/surface/tools/coverage-tools.js +1 -1
  371. package/dist/surface/tools/dynamic-tools.js +11 -3
  372. package/dist/surface/tools/empty-session-list.d.ts +2 -0
  373. package/dist/surface/tools/empty-session-list.js +4 -2
  374. package/dist/surface/tools/error-recovery.d.ts +12 -1
  375. package/dist/surface/tools/error-recovery.js +131 -40
  376. package/dist/surface/tools/explore-tools.js +1 -1
  377. package/dist/surface/tools/invoke-tool.js +29 -21
  378. package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
  379. package/dist/surface/tools/lease-coverage-tools.js +128 -0
  380. package/dist/surface/tools/lease-hint.d.ts +42 -1
  381. package/dist/surface/tools/lease-hint.js +52 -3
  382. package/dist/surface/tools/lease-readiness.d.ts +47 -0
  383. package/dist/surface/tools/lease-readiness.js +126 -0
  384. package/dist/surface/tools/lease-seed.d.ts +16 -1
  385. package/dist/surface/tools/lease-seed.js +37 -4
  386. package/dist/surface/tools/lease-tools.d.ts +3 -41
  387. package/dist/surface/tools/lease-tools.js +104 -124
  388. package/dist/surface/tools/lease-url-identity.d.ts +46 -0
  389. package/dist/surface/tools/lease-url-identity.js +97 -0
  390. package/dist/surface/tools/merge-tools.js +99 -2
  391. package/dist/surface/tools/merged-name-redirect.js +5 -1
  392. package/dist/surface/tools/observe-tools.js +15 -9
  393. package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
  394. package/dist/surface/tools/read/console-pre-attach.js +23 -0
  395. package/dist/surface/tools/read-tools.js +33 -30
  396. package/dist/surface/tools/real-input-attempt.d.ts +0 -8
  397. package/dist/surface/tools/real-input-attempt.js +143 -28
  398. package/dist/surface/tools/repeat-hint.d.ts +40 -0
  399. package/dist/surface/tools/repeat-hint.js +171 -0
  400. package/dist/surface/tools/run-report.d.ts +2 -2
  401. package/dist/surface/tools/run-report.js +27 -15
  402. package/dist/surface/tools/session-ports.d.ts +14 -0
  403. package/dist/surface/tools/session-ports.js +53 -0
  404. package/dist/surface/tools/tool-kit.d.ts +18 -0
  405. package/dist/surface/tools/tool-kit.js +9 -3
  406. package/dist/surface/tools/tool-surface.js +0 -1
  407. package/dist/surface/tools/tools.js +54 -18
  408. package/dist/surface/tools/type-spelling.d.ts +13 -0
  409. package/dist/surface/tools/type-spelling.js +36 -0
  410. package/dist/telemetry/agent-client.d.ts +6 -0
  411. package/dist/telemetry/agent-client.js +10 -0
  412. package/dist/telemetry/argument-shape.js +17 -7
  413. package/dist/telemetry/cli-telemetry.d.ts +10 -1
  414. package/dist/telemetry/cli-telemetry.js +15 -0
  415. package/dist/telemetry/init-telemetry.d.ts +2 -1
  416. package/dist/telemetry/init-telemetry.js +47 -2
  417. package/dist/telemetry/install-trace.js +23 -4
  418. package/dist/telemetry/onboarding-funnel.d.ts +19 -2
  419. package/dist/telemetry/onboarding-funnel.js +25 -3
  420. package/dist/telemetry/proxy-telemetry.d.ts +2 -1
  421. package/dist/telemetry/proxy-telemetry.js +2 -2
  422. package/dist/telemetry/session-metrics.d.ts +1 -1
  423. package/dist/telemetry/session-metrics.js +67 -27
  424. package/dist/telemetry/telemetry.d.ts +3 -1
  425. package/dist/telemetry/telemetry.js +60 -28
  426. package/dist/telemetry/tool-refused.d.ts +6 -3
  427. package/dist/telemetry/tool-refused.js +15 -3
  428. package/docs/actions.mdx +3 -3
  429. package/docs/agent-cheatsheet.md +1 -1
  430. package/docs/architecture.md +3 -6
  431. package/docs/capabilities.mdx +61 -1
  432. package/docs/cli/affected.mdx +9 -7
  433. package/docs/cli/cloud.mdx +3 -3
  434. package/docs/cli/compare.mdx +94 -0
  435. package/docs/cli/doctor.mdx +41 -2
  436. package/docs/cli/grade.mdx +97 -0
  437. package/docs/cli/help.mdx +4 -2
  438. package/docs/cli/license.mdx +13 -12
  439. package/docs/cli/restart.mdx +7 -5
  440. package/docs/cli/rollback.mdx +5 -5
  441. package/docs/cli/setup.mdx +13 -2
  442. package/docs/cli/status.mdx +4 -0
  443. package/docs/cli/stop.mdx +3 -3
  444. package/docs/cli/update.mdx +2 -2
  445. package/docs/cli/verify.mdx +23 -1
  446. package/docs/cli.mdx +34 -24
  447. package/docs/deploy-checks.md +25 -0
  448. package/docs/desktop.mdx +1 -1
  449. package/docs/enterprise.md +17 -22
  450. package/docs/environment.mdx +1 -0
  451. package/docs/first-drive.md +1 -1
  452. package/docs/flows.md +11 -1
  453. package/docs/frameworks.mdx +9 -9
  454. package/docs/getting-started.md +1 -1
  455. package/docs/install-manual.mdx +16 -1
  456. package/docs/license-activation.mdx +3 -3
  457. package/docs/packages/engine.mdx +1 -1
  458. package/docs/packages/server.mdx +1 -1
  459. package/docs/packages/tauri.mdx +1 -1
  460. package/docs/packages/test.mdx +1 -1
  461. package/docs/packages.mdx +1 -1
  462. package/docs/platform-integration.md +1 -1
  463. package/docs/predicates.mdx +1 -1
  464. package/docs/quickstart.mdx +68 -49
  465. package/docs/skill-setup.md +1 -1
  466. package/docs/skill.md +14 -13
  467. package/docs/telemetry.md +6 -4
  468. package/docs/tools/navigate.mdx +1 -1
  469. package/docs/tools/verify.mdx +4 -1
  470. package/docs/troubleshooting.mdx +1 -1
  471. package/docs/usage.md +17 -14
  472. package/package.json +18 -14
  473. package/LICENSE-ENTERPRISE +0 -37
  474. package/dist/features/ee/audit-log.d.ts +0 -14
  475. package/dist/features/ee/audit-log.js +0 -11
  476. package/dist/features/exhaust/exhaust-run.d.ts +0 -33
  477. package/dist/features/exhaust/exhaust-run.js +0 -82
@@ -15,7 +15,7 @@
15
15
  * URLs, no error messages — the accumulator has no way to hold them, which is a stronger guarantee
16
16
  * than a rule saying it shouldn't.
17
17
  */
18
- import { BrowserLaunchKind, type AgentNudgeKind, type ConnectFailure, type SessionSummary } from '@reticlehq/core/telemetry';
18
+ import { BrowserLaunchKind, ConnectFailure, type AgentNudgeKind, type SessionSummary } from '@reticlehq/core/telemetry';
19
19
  import type { HudUseData } from '@reticlehq/core';
20
20
  import { type HudSignals } from './hud-metrics.js';
21
21
  /**
@@ -15,12 +15,13 @@
15
15
  * URLs, no error messages — the accumulator has no way to hold them, which is a stronger guarantee
16
16
  * than a rule saying it shouldn't.
17
17
  */
18
- import { BrowserLaunchKind, } from '@reticlehq/core/telemetry';
18
+ import { BrowserLaunchKind, ConnectFailure, OnboardingPhase, OnboardingStop, } from '@reticlehq/core/telemetry';
19
19
  import { errorSkeleton, fingerprintError } from './error-fingerprint.js';
20
20
  import { describeToolParams } from './argument-shape.js';
21
21
  import { machineSnapshot } from './machine-snapshot.js';
22
22
  import { classifyError } from './error-class.js';
23
23
  import { HudMetrics } from './hud-metrics.js';
24
+ import { reportOnboardingStop } from './onboarding-funnel.js';
24
25
  import { releaseVersionOf } from '../command/update/version-seen.js';
25
26
  /** Cap the distinct error shapes held in memory — a pathological loop must not grow unbounded. */
26
27
  const MAX_ERROR_KINDS = 40;
@@ -58,6 +59,12 @@ const BREADCRUMB_LENGTH = 12;
58
59
  * never fires for the sessions that need it most.
59
60
  */
60
61
  const UNVERIFIED_ACTION_NUDGE_AT = 3;
62
+ /** The launch failures that leave no browser to drive: a stop on the path to a first verdict. */
63
+ const CHROMIUM_UNAVAILABLE = new Set([
64
+ ConnectFailure.CHROMIUM_MISSING,
65
+ ConnectFailure.PLAYWRIGHT_MISSING,
66
+ ]);
67
+ const DRIVEN_STEP = 'driven';
61
68
  /**
62
69
  * Mutable counters for one daemon lifetime. A plain class, not a store: it is process-local, it never
63
70
  * persists, and it dies with the daemon.
@@ -187,10 +194,12 @@ export class SessionMetrics {
187
194
  }
188
195
  /** A tab went into the background (true) or came back (false): its HUD time pauses meanwhile. */
189
196
  setHudTabHidden(tab, hidden) {
190
- if (hidden)
197
+ if (hidden) {
191
198
  this.#hud.hide(tab);
192
- else
199
+ }
200
+ else {
193
201
  this.#hud.show(tab);
202
+ }
194
203
  }
195
204
  /** A tab went away: its HUD stops accruing time. */
196
205
  closeHudTab(tab) {
@@ -204,12 +213,14 @@ export class SessionMetrics {
204
213
  startToolCall(tool, args) {
205
214
  this.recordToolCall(tool, args);
206
215
  this.#concurrent += 1;
207
- if (this.#concurrent > this.#peakConcurrent)
216
+ if (this.#concurrent > this.#peakConcurrent) {
208
217
  this.#peakConcurrent = this.#concurrent;
218
+ }
209
219
  let settled = false;
210
220
  return (durationMs) => {
211
- if (settled)
212
- return; // a double-settle would corrupt the concurrency count
221
+ if (settled) {
222
+ return;
223
+ } // a double-settle would corrupt the concurrency count
213
224
  settled = true;
214
225
  this.#concurrent = Math.max(0, this.#concurrent - 1);
215
226
  this.#busyMs += durationMs;
@@ -243,8 +254,9 @@ export class SessionMetrics {
243
254
  */
244
255
  recordUnknownTool(name) {
245
256
  this.#unknownToolCalls += 1;
246
- if (name === undefined || 0 === name.length)
257
+ if (name === undefined || 0 === name.length) {
247
258
  return;
259
+ }
248
260
  const key = name.slice(0, 64);
249
261
  const seen = this.#unknownTools.get(key);
250
262
  if (seen !== undefined) {
@@ -253,8 +265,9 @@ export class SessionMetrics {
253
265
  }
254
266
  // Stop growing once full: a pathological loop must not balloon the payload. The head is what
255
267
  // gets built; the tail is noise.
256
- if (this.#unknownTools.size >= MAX_ERROR_KINDS)
268
+ if (this.#unknownTools.size >= MAX_ERROR_KINDS) {
257
269
  return;
270
+ }
258
271
  this.#unknownTools.set(key, 1);
259
272
  }
260
273
  recordToolCall(tool, args) {
@@ -269,8 +282,9 @@ export class SessionMetrics {
269
282
  if (this.#currentRun > 1) {
270
283
  const best = this.#repeatRuns.get(tool) ?? 0;
271
284
  if (this.#currentRun > best &&
272
- (this.#repeatRuns.has(tool) || this.#repeatRuns.size < MAX_REPEAT_TOOLS))
285
+ (this.#repeatRuns.has(tool) || this.#repeatRuns.size < MAX_REPEAT_TOOLS)) {
273
286
  this.#repeatRuns.set(tool, this.#currentRun);
287
+ }
274
288
  }
275
289
  this.#toolCalls += 1;
276
290
  this.#lifetimeToolCalls += 1;
@@ -280,23 +294,27 @@ export class SessionMetrics {
280
294
  bump(this.#toolCounts, tool);
281
295
  this.#inFlight = tool;
282
296
  this.#breadcrumb.push(tool);
283
- if (this.#breadcrumb.length > BREADCRUMB_LENGTH)
297
+ if (this.#breadcrumb.length > BREADCRUMB_LENGTH) {
284
298
  this.#breadcrumb.shift();
285
- if (args === undefined)
299
+ }
300
+ if (args === undefined) {
286
301
  return;
302
+ }
287
303
  // Which PARAMETERS get used, per tool — names only (plus a short allowlist of our own enums).
288
304
  // Bounded by our own schemas: a tool has a fixed handful of declared parameters, so this map
289
305
  // cannot grow with traffic the way a value-carrying one would.
290
306
  let perTool = this.#toolParams.get(tool);
291
307
  if (perTool === undefined) {
292
- if (this.#toolParams.size >= MAX_PARAM_TOOLS)
308
+ if (this.#toolParams.size >= MAX_PARAM_TOOLS) {
293
309
  return;
310
+ }
294
311
  perTool = new Map();
295
312
  this.#toolParams.set(tool, perTool);
296
313
  }
297
314
  for (const param of describeToolParams(args)) {
298
- if (perTool.size < MAX_PARAMS_PER_TOOL || perTool.has(param))
315
+ if (perTool.size < MAX_PARAMS_PER_TOOL || perTool.has(param)) {
299
316
  bump(perTool, param);
317
+ }
300
318
  }
301
319
  }
302
320
  /**
@@ -310,8 +328,9 @@ export class SessionMetrics {
310
328
  // indistinguishable from the rest inside one `toolErrors` count.
311
329
  bump(this.#errorClasses, classifyError(message));
312
330
  this.#currentCallErrored = true;
313
- if (NO_SESSION_ERROR.test(message))
331
+ if (NO_SESSION_ERROR.test(message)) {
314
332
  this.#noSessionErrors += 1;
333
+ }
315
334
  const fingerprint = fingerprintError(message);
316
335
  const existing = this.#errorKinds.get(fingerprint);
317
336
  if (existing !== undefined) {
@@ -319,8 +338,9 @@ export class SessionMetrics {
319
338
  return;
320
339
  }
321
340
  // Stop growing once the cap is hit; the tail is noise and the head is what gets fixed.
322
- if (this.#errorKinds.size >= MAX_ERROR_KINDS)
341
+ if (this.#errorKinds.size >= MAX_ERROR_KINDS) {
323
342
  return;
343
+ }
324
344
  this.#errorKinds.set(fingerprint, {
325
345
  fingerprint,
326
346
  count: 1,
@@ -343,8 +363,9 @@ export class SessionMetrics {
343
363
  existing.count += 1;
344
364
  return;
345
365
  }
346
- if (this.#sdkFailureKinds.size >= MAX_ERROR_KINDS)
366
+ if (this.#sdkFailureKinds.size >= MAX_ERROR_KINDS) {
347
367
  return;
368
+ }
348
369
  this.#sdkFailureKinds.set(fingerprint, {
349
370
  fingerprint,
350
371
  count: 1,
@@ -428,8 +449,9 @@ export class SessionMetrics {
428
449
  /** The 1-based occurrence of this finding in the session, or undefined past the cap. */
429
450
  recordBugOccurrence(fingerprint) {
430
451
  const seen = this.#bugOccurrences.get(fingerprint);
431
- if (seen === undefined && this.#bugOccurrences.size >= MAX_BUG_FINGERPRINTS)
452
+ if (seen === undefined && this.#bugOccurrences.size >= MAX_BUG_FINGERPRINTS) {
432
453
  return undefined;
454
+ }
433
455
  const occurrence = (seen ?? 0) + 1;
434
456
  this.#bugOccurrences.set(fingerprint, occurrence);
435
457
  return occurrence;
@@ -437,8 +459,9 @@ export class SessionMetrics {
437
459
  recordBug(kind) {
438
460
  this.#bugsFound += 1;
439
461
  this.#lifetimeBugsFound += 1;
440
- if (this.#bugKinds.size < MAX_ERROR_KINDS || this.#bugKinds.has(kind))
462
+ if (this.#bugKinds.size < MAX_ERROR_KINDS || this.#bugKinds.has(kind)) {
441
463
  bump(this.#bugKinds, kind);
464
+ }
442
465
  const first = !this.#seenBugKinds.has(kind);
443
466
  this.#seenBugKinds.add(kind);
444
467
  return first;
@@ -457,8 +480,9 @@ export class SessionMetrics {
457
480
  this.#connections.set(kind, stats);
458
481
  let settled = false;
459
482
  return (failure) => {
460
- if (settled)
483
+ if (settled) {
461
484
  return;
485
+ }
462
486
  settled = true;
463
487
  if (failure === undefined) {
464
488
  stats.successes += 1;
@@ -466,12 +490,21 @@ export class SessionMetrics {
466
490
  }
467
491
  stats.failures ??= {};
468
492
  stats.failures[failure] = (stats.failures[failure] ?? 0) + 1;
493
+ if (CHROMIUM_UNAVAILABLE.has(failure)) {
494
+ reportOnboardingStop({
495
+ phase: OnboardingPhase.FIRST_RUN,
496
+ step: DRIVEN_STEP,
497
+ reason: failure,
498
+ stop: OnboardingStop.CHROMIUM_UNAVAILABLE,
499
+ });
500
+ }
469
501
  };
470
502
  }
471
503
  recordClient(name, version) {
472
504
  const key = name.slice(0, 64);
473
- if (this.#clients.size < MAX_CLIENTS)
505
+ if (this.#clients.size < MAX_CLIENTS) {
474
506
  this.#clients.add(key);
507
+ }
475
508
  // The version was already in the handshake and was being dropped. A regression in agent
476
509
  // behaviour is usually a client version, and without this it is unattributable.
477
510
  if (version !== undefined && '' !== version && this.#clientVersions.size < MAX_CLIENTS) {
@@ -511,8 +544,9 @@ export class SessionMetrics {
511
544
  summarize(final, exit) {
512
545
  // The last call has no successor to resolve it, so resolve it here. Only on a FINAL summary:
513
546
  // a periodic flush is not the end of anything and would resolve a call still in flight.
514
- if (final)
547
+ if (final) {
515
548
  this.#resolveRecovery();
549
+ }
516
550
  const machine = machineSnapshot();
517
551
  // EVERY event reports its own window, the final one included: summing a session's
518
552
  // `session_progress` + `daemon_stopped` rows is then its total. The final event used to swap in
@@ -612,10 +646,12 @@ export class SessionMetrics {
612
646
  */
613
647
  #resolveRecovery() {
614
648
  if (this.#priorCallErrored) {
615
- if (this.#currentCallErrored)
649
+ if (this.#currentCallErrored) {
616
650
  this.#errorsRepeated += 1;
617
- else
651
+ }
652
+ else {
618
653
  this.#errorsRecovered += 1;
654
+ }
619
655
  }
620
656
  this.#priorCallErrored = this.#currentCallErrored;
621
657
  this.#currentCallErrored = false;
@@ -625,14 +661,18 @@ export class SessionMetrics {
625
661
  * that left explains everything after it, and a verdict settles whatever preceded it.
626
662
  */
627
663
  #endReason() {
628
- if (0 === this.#lifetimeToolCalls)
664
+ if (0 === this.#lifetimeToolCalls) {
629
665
  return 'never_used';
630
- if (this.#clientLeft)
666
+ }
667
+ if (this.#clientLeft) {
631
668
  return 'client_left';
632
- if (this.#unsettledActions > 0)
669
+ }
670
+ if (this.#unsettledActions > 0) {
633
671
  return 'abandoned';
634
- if (this.#lifetimeVerifications > 0)
672
+ }
673
+ if (this.#lifetimeVerifications > 0) {
635
674
  return 'verified';
675
+ }
636
676
  return 'explored';
637
677
  }
638
678
  /**
@@ -1,4 +1,4 @@
1
- import { TelemetryEventKind, ProjectIdSource, type Crash, type Feedback, type Identity, type BugFound, type InitOutcome, type OnboardingStep, type InstallSource, type McpConnection, type McpOutage, type DaemonDeath, type ProxyExit, type WakeRefusal, type DaemonSpawnMethod, type ToolRefusal, type AppInstrumentation, type HarnessRun, type HudEvent, type PlatformLink, type ProjectProfile, type SessionSummary, type TelemetryActor, type Verification, type VersionChange } from '@reticlehq/core/telemetry';
1
+ import { TelemetryEventKind, ProjectIdSource, type Crash, type Feedback, type Identity, type BugFound, type InitOutcome, type OnboardingStep, type InstallSource, type McpConnection, type McpOutage, type DaemonDeath, type GateCompleted, type ProxyExit, type WakeRefusal, type DaemonSpawnMethod, type ToolRefusal, type AppInstrumentation, type HarnessRun, type HudEvent, type PlatformLink, type ProjectProfile, type SessionSummary, type TelemetryActor, type Verification, type VersionChange } from '@reticlehq/core/telemetry';
2
2
  /**
3
3
  * Presence of this file marks the MACHINE as the Reticle team's own: every event carries
4
4
  * `internal: true`. The persistent twin of `RETICLE_INTERNAL=1`, for a dev machine where setting a
@@ -113,6 +113,8 @@ export interface TelemetryExtra {
113
113
  daemonDeath?: DaemonDeath;
114
114
  /** `wake_refused`: what held the port. */
115
115
  wakeRefusal?: WakeRefusal;
116
+ /** `gate_completed`: how `reticle gate` ended. */
117
+ gate?: GateCompleted;
116
118
  /** `daemon_started`: how the parent started the daemon. */
117
119
  spawnMethod?: DaemonSpawnMethod;
118
120
  /**
@@ -138,20 +138,24 @@ const Env = {
138
138
  };
139
139
  const isDisabled = (env, cwd = process.cwd()) => {
140
140
  const off = new Set(['0', 'false', 'off', 'no']);
141
- if (off.has((env[Env.DISABLE] ?? '').toLowerCase()))
141
+ if (off.has((env[Env.DISABLE] ?? '').toLowerCase())) {
142
142
  return true;
143
+ }
143
144
  // Recording to a local file is not "phoning home", and the guards below exist to stop us phoning
144
145
  // home. Chief among them is the source-checkout rule — which is exactly where a release sweep is
145
146
  // driven from, so a sink that inherited it would record nothing and look like it had worked.
146
- if ((env[Env.FILE] ?? '') !== '')
147
+ if ((env[Env.FILE] ?? '') !== '') {
147
148
  return false;
148
- if (env[Env.VITEST] !== undefined)
149
- return true; // a test run is not a user
149
+ }
150
+ if (env[Env.VITEST] !== undefined) {
151
+ return true;
152
+ } // a test run is not a user
150
153
  // Developing Reticle is not using Reticle. The `.env` carrying RETICLE_TELEMETRY=0 is gitignored,
151
154
  // so it only exists on the machine that made it — a fresh clone would phone home on a
152
155
  // contributor's first `reticle serve`. The repo marker is committed, so this guarantee travels.
153
- if (isReticleSourceCheckout(cwd))
156
+ if (isReticleSourceCheckout(cwd)) {
154
157
  return true;
158
+ }
155
159
  const dnt = env[Env.DO_NOT_TRACK];
156
160
  return 'string' === typeof dnt && dnt !== '' && dnt !== '0';
157
161
  };
@@ -191,19 +195,22 @@ const readIdFile = (file) => {
191
195
  export const resolveIdentity = (file = ID_FILE) => {
192
196
  try {
193
197
  const existing = readIdFile(file);
194
- if (existing !== undefined)
198
+ if (existing !== undefined) {
195
199
  return { anonymousId: existing, firstRun: false };
200
+ }
196
201
  const id = randomUUID();
197
202
  mkdirSync(dirname(file), { recursive: true });
198
203
  try {
199
204
  writeFileSync(file, id, { encoding: 'utf8', flag: 'wx' });
200
205
  }
201
206
  catch (error) {
202
- if (!isAlreadyThere(error))
207
+ if (!isAlreadyThere(error)) {
203
208
  throw error;
209
+ }
204
210
  const raced = readIdFile(file);
205
- if (raced !== undefined)
211
+ if (raced !== undefined) {
206
212
  return { anonymousId: raced, firstRun: false };
213
+ }
207
214
  // An empty file left by a crash: replace it, as the old code did.
208
215
  writeFileSync(file, id, 'utf8');
209
216
  }
@@ -235,30 +242,40 @@ export const projectFingerprint = (cwd) => {
235
242
  // stable across every directory inside one machine's checkout, a package.json root is the same for
236
243
  // a non-git project — and the raw cwd is stable across nothing, which is why it is last. See
237
244
  // `project-identity.test.ts` for what a wrong order costs.
238
- const { key, source } = origin !== undefined
239
- ? { key: origin, source: ProjectIdSource.GIT_ORIGIN }
240
- : root !== undefined
241
- ? { key: root, source: ProjectIdSource.GIT_ROOT }
242
- : packageRoot(cwd) !== null
243
- ? { key: packageRoot(cwd) ?? cwd, source: ProjectIdSource.PACKAGE_ROOT }
244
- : { key: cwd, source: ProjectIdSource.CWD };
245
+ const { key, source } = projectKey(cwd, origin, root);
245
246
  return {
246
247
  projectId: createHash('sha256').update(key).digest('hex').slice(0, 32),
247
248
  // Reported alongside so the analytics knows whether this id is comparable to another machine's.
248
249
  source,
249
250
  };
250
251
  };
252
+ /** The most stable key this directory has, and what it came from. */
253
+ function projectKey(cwd, origin, root) {
254
+ if (origin !== undefined) {
255
+ return { key: origin, source: ProjectIdSource.GIT_ORIGIN };
256
+ }
257
+ if (root !== undefined) {
258
+ return { key: root, source: ProjectIdSource.GIT_ROOT };
259
+ }
260
+ const pkg = packageRoot(cwd);
261
+ if (pkg !== null) {
262
+ return { key: pkg, source: ProjectIdSource.PACKAGE_ROOT };
263
+ }
264
+ return { key: cwd, source: ProjectIdSource.CWD };
265
+ }
251
266
  /** Nearest ancestor holding a package.json — the project boundary when there is no git. */
252
267
  const packageRoot = (cwd) => {
253
268
  let dir = cwd;
254
269
  // Same bound as the git walk: deep monorepos are well inside 20, and an unbounded loop on a
255
270
  // pathological path would hang the CLI's startup.
256
271
  for (let depth = 0; depth < 20; depth += 1) {
257
- if (existsSync(join(dir, 'package.json')))
272
+ if (existsSync(join(dir, 'package.json'))) {
258
273
  return dir;
274
+ }
259
275
  const parent = dirname(dir);
260
- if (parent === dir)
276
+ if (parent === dir) {
261
277
  return null;
278
+ }
262
279
  dir = parent;
263
280
  }
264
281
  return null;
@@ -329,18 +346,21 @@ export const createTelemetry = (opts) => {
329
346
  const cwd = opts.cwd ?? process.cwd();
330
347
  // A source checkout silences metrics but must not silence FEEDBACK — see onlyBlockedBySourceCheckout.
331
348
  const feedbackOnly = onlyBlockedBySourceCheckout(env, cwd);
332
- if (isDisabled(env, cwd) && !feedbackOnly)
349
+ if (isDisabled(env, cwd) && !feedbackOnly) {
333
350
  return NOOP;
351
+ }
334
352
  try {
335
- if (existsSync(join(reticleDir, OPT_OUT_FILE_NAME)))
336
- return NOOP; // the persistent `reticle telemetry disable` opt-out
353
+ if (existsSync(join(reticleDir, OPT_OUT_FILE_NAME))) {
354
+ return NOOP;
355
+ } // the persistent `reticle telemetry disable` opt-out
337
356
  }
338
357
  catch {
339
358
  /* unreadable home dir — fall through; the env-var opt-outs above still apply */
340
359
  }
341
360
  const apiKey = env[Env.KEY] ?? POSTHOG_KEY;
342
- if ('' === apiKey)
343
- return NOOP; // no key baked in (dev/test build) — nowhere to send, stay silent
361
+ if ('' === apiKey) {
362
+ return NOOP;
363
+ } // no key baked in (dev/test build) — nowhere to send, stay silent
344
364
  const now = opts.now ?? (() => Date.now());
345
365
  const doFetch = opts.fetchImpl ?? fetch;
346
366
  const url = `${(env[Env.URL] ?? DEFAULT_URL).replace(/\/+$/, '')}${TELEMETRY_PATH}`;
@@ -375,8 +395,9 @@ export const createTelemetry = (opts) => {
375
395
  // How this process was launched: a property of the process, so read once. Only the bucket leaves.
376
396
  const launch = launchMethodOf(process.argv[1]);
377
397
  const home = opts.home ?? homedir();
378
- if (!feedbackOnly)
398
+ if (!feedbackOnly) {
379
399
  showNoticeOnce(reticleDir);
400
+ }
380
401
  const spawnDetached = opts.spawnImpl ??
381
402
  ((command, args, input) => {
382
403
  const bodyFile = join(tmpdir(), `reticle-telemetry-${randomUUID()}.json`);
@@ -397,8 +418,9 @@ export const createTelemetry = (opts) => {
397
418
  const emit = async (kind, extra) => {
398
419
  // In a Reticle source checkout the emitter carries FEEDBACK and nothing else: somebody typed the
399
420
  // feedback, and no metric is worth phoning home from a contributor's clone.
400
- if (feedbackOnly && TelemetryEventKind.FEEDBACK_SUBMITTED !== kind)
421
+ if (feedbackOnly && TelemetryEventKind.FEEDBACK_SUBMITTED !== kind) {
401
422
  return false;
423
+ }
402
424
  // One clock read for the whole event: `ts` and the licence check must agree, and two calls to
403
425
  // now() can straddle an expiry.
404
426
  const eventTs = now();
@@ -470,6 +492,7 @@ export const createTelemetry = (opts) => {
470
492
  ...(extra?.proxyExit !== undefined ? { proxyExit: extra.proxyExit } : {}),
471
493
  ...(extra?.daemonDeath !== undefined ? { daemonDeath: extra.daemonDeath } : {}),
472
494
  ...(extra?.wakeRefusal !== undefined ? { wakeRefusal: extra.wakeRefusal } : {}),
495
+ ...(extra?.gate !== undefined ? { gate: extra.gate } : {}),
473
496
  // A SCALAR: the event build and the wire schema, no `blocks` entry.
474
497
  ...(extra?.spawnMethod !== undefined ? { spawnMethod: extra.spawnMethod } : {}),
475
498
  };
@@ -484,7 +507,7 @@ export const createTelemetry = (opts) => {
484
507
  // PostHog filters and breakdowns operate on top-level properties, so a nested `feedback.stack`
485
508
  // would be invisible to the exact "which stacks report the most bugs" question this exists to
486
509
  // answer. One prefix keeps them grouped in the UI without a nested path.
487
- const { anonymousId: distinctId, event: name, ts, sessionId: eventSessionId, feedback, session, project, verification, versionChange, crash, identity, connection, init, onboarding, bug, refusal, outage, instrumentation, hud, link, harness, proxyExit, daemonDeath, wakeRefusal, ...rest } = event;
510
+ const { anonymousId: distinctId, event: name, ts, sessionId: eventSessionId, feedback, session, project, verification, versionChange, crash, identity, connection, init, onboarding, bug, refusal, outage, instrumentation, hud, link, harness, proxyExit, daemonDeath, wakeRefusal, gate, ...rest } = event;
488
511
  // `$session_id` is PostHog's OWN session property, so sending ours under that name lights up
489
512
  // its built-in session views and funnels for free rather than requiring custom HogQL everywhere.
490
513
  // `sessionId` rides only on events that happened inside a daemon run. A one-shot CLI command
@@ -522,6 +545,7 @@ export const createTelemetry = (opts) => {
522
545
  proxyExit,
523
546
  daemonDeath,
524
547
  wakeRefusal,
548
+ gate,
525
549
  };
526
550
  for (const [prefix, block] of Object.entries(blocks)) {
527
551
  for (const [key, value] of Object.entries(block ?? {})) {
@@ -583,8 +607,9 @@ export const createTelemetry = (opts) => {
583
607
  return response.ok !== false;
584
608
  }
585
609
  catch (error) {
586
- if (attempt === attempts - 1)
610
+ if (attempt === attempts - 1) {
587
611
  throw error;
612
+ }
588
613
  }
589
614
  }
590
615
  return false;
@@ -602,10 +627,17 @@ export const createTelemetry = (opts) => {
602
627
  */
603
628
  let invalidDropped = 0;
604
629
  export const droppedInvalidEvents = () => invalidDropped;
605
- /** `RETICLE_INTERNAL=1`, or the machine-wide marker file. Unreadable home → not internal. */
630
+ /** The values of `RETICLE_INTERNAL` that mark a run, after trim and lower case. Anything else is not. */
631
+ const INTERNAL_ON = new Set(['1', 'true', 'yes', 'on']);
632
+ /**
633
+ * The one decision for the `internal` field on every event: `RETICLE_INTERNAL` set to an "on" value,
634
+ * or the machine-wide marker file. An explicit signal only, never read from a name, email or path.
635
+ * Unreadable home → not internal.
636
+ */
606
637
  const isInternal = (env, dir) => {
607
- if ('1' === env[Env.INTERNAL] || 'true' === env[Env.INTERNAL])
638
+ if (INTERNAL_ON.has((env[Env.INTERNAL] ?? '').trim().toLowerCase())) {
608
639
  return true;
640
+ }
609
641
  try {
610
642
  return existsSync(join(dir, INTERNAL_MARKER_FILE));
611
643
  }
@@ -10,12 +10,15 @@
10
10
  * Emitted from `runTool`, which is the one place both dispatch paths cross, so a tool added later is
11
11
  * covered without anybody remembering to cover it.
12
12
  */
13
- import { RefusalReason, type NoSessionReason } from '@reticlehq/core/telemetry';
13
+ import { RefusalReason, type NoSessionReason, type RefusalDetail } from '@reticlehq/core/telemetry';
14
14
  /** Record the branch code for the no-session error being thrown right now. */
15
15
  export declare function notePendingNoSessionReason(reason: NoSessionReason | undefined): void;
16
16
  /** A call that was served. Breaks the retry chain: what follows it is not a retry of anything. */
17
17
  export declare function noteToolServed(): void;
18
- /** One refused call, reported with its cause and whether it was itself a retry. */
19
- export declare function reportToolRefused(tool: string, reason: RefusalReason): void;
18
+ /**
19
+ * One refused call, reported with its cause, whether it was a retry, and the names of its arguments.
20
+ * `detail` is the cause inside `reason`, when the recovery table names one.
21
+ */
22
+ export declare function reportToolRefused(tool: string, reason: RefusalReason, args?: Record<string, unknown>, detail?: RefusalDetail): void;
20
23
  /** Tests only — the counters are process-lifetime, so each case has to start from zero. */
21
24
  export declare function resetToolRefusals(): void;
@@ -11,6 +11,7 @@
11
11
  * covered without anybody remembering to cover it.
12
12
  */
13
13
  import { RefusalReason, TelemetryActor, TelemetryEventKind, } from '@reticlehq/core/telemetry';
14
+ import { describeToolParams } from './argument-shape.js';
14
15
  import { getTelemetry } from './telemetry.js';
15
16
  /**
16
17
  * Refusal events one daemon run will send.
@@ -54,16 +55,22 @@ export function notePendingNoSessionReason(reason) {
54
55
  export function noteToolServed() {
55
56
  lastRefusedTool = undefined;
56
57
  }
57
- /** One refused call, reported with its cause and whether it was itself a retry. */
58
- export function reportToolRefused(tool, reason) {
58
+ /** How many argument names one refusal carries. A call with more is malformed in its own way. */
59
+ const MAX_REFUSAL_PARAMS = 16;
60
+ /**
61
+ * One refused call, reported with its cause, whether it was a retry, and the names of its arguments.
62
+ * `detail` is the cause inside `reason`, when the recovery table names one.
63
+ */
64
+ export function reportToolRefused(tool, reason, args = {}, detail) {
59
65
  const retried = lastRefusedTool === tool;
60
66
  lastRefusedTool = tool;
61
67
  // Read and clear whatever the throw left, whether or not this refusal can use it: a reason left
62
68
  // sitting would attach itself to an unrelated refusal later in the session.
63
69
  const noSessionReason = pendingNoSessionReason;
64
70
  pendingNoSessionReason = undefined;
65
- if (sent >= MAX_REFUSALS_PER_SESSION)
71
+ if (sent >= MAX_REFUSALS_PER_SESSION) {
66
72
  return;
73
+ }
67
74
  sent += 1;
68
75
  void getTelemetry().emit(TelemetryEventKind.TOOL_REFUSED, {
69
76
  actor: TelemetryActor.AGENT,
@@ -71,11 +78,16 @@ export function reportToolRefused(tool, reason) {
71
78
  tool,
72
79
  reason,
73
80
  retried,
81
+ ...(() => {
82
+ const params = describeToolParams(args).slice(0, MAX_REFUSAL_PARAMS);
83
+ return 0 === params.length ? {} : { params };
84
+ })(),
74
85
  // Only where it means something. On any other refusal reason this field would be answering
75
86
  // a question nobody asked of it.
76
87
  ...(RefusalReason.NO_SESSION === reason && noSessionReason !== undefined
77
88
  ? { noSessionReason }
78
89
  : {}),
90
+ ...(detail === undefined ? {} : { detail }),
79
91
  },
80
92
  });
81
93
  }
package/docs/actions.mdx CHANGED
@@ -22,13 +22,13 @@ Every action Reticle can perform takes the same shape: an element, an `action` n
22
22
  | `select` | `{ value }` | For `<select>` |
23
23
  | `check` / `uncheck` | none | Checkbox and radio, or a `role="checkbox"`/`role="switch"` element (fails if `aria-checked` does not change) |
24
24
  | `submit` | none | Submits the element's `<form>` |
25
- | `press` | `{ text, modifiers?, holdMs?, keys?, code? }` | `text` is the key **name**: `Escape`, `Tab`, `Enter`. `key` is an accepted alias. `modifiers` is an array of `Meta`, `Control`, `Shift`, `Alt`. `holdMs` holds the key down; `keys` holds several together; `code` names the physical key |
25
+ | `press` | `{ text, modifiers?, holdMs?, keys?, code?, document? }` | `text` is the key **name**: `Escape`, `Tab`, `Enter`. `key` is an accepted alias. `document: true` sends any key to the focused element or the document with no `ref` (a canvas game reads WASD and Space from the page). `modifiers` is an array of `Meta`, `Control`, `Shift`, `Alt`. `holdMs` holds the key down; `keys` holds several together; `code` names the physical key |
26
26
  | `scrollIntoView` | none | |
27
- | `scroll` | `{ dy?, dx?, fraction? }` | Scrolls the nearest scrollable container (or the page, with no `ref`) by `dy`/`dx` pixels, either direction. `fraction` (0 to 1) jumps to that point of the height. No args steps down most of a screen |
27
+ | `scroll` | `{ dy?, dx?, fraction?, wheel? }` | Scrolls the nearest scrollable container (or the page, with no `ref`) by `dy`/`dx` pixels, either direction. `fraction` (0 to 1) jumps to that point of the height. `wheel: true` sends a cancelable `wheel` event and leaves the movement to the page, for apps that scroll from a wheel listener. No args steps down most of a screen |
28
28
  | `tap` | `{ holdMs? }` | A touch tap: pointer and touch events, then `click`. `holdMs` makes it a long press |
29
29
  | `zoom` | none | Page zoom. Refused inside the page, because CSS zoom changes how a page looks without changing its layout, and a passing check on it would be false |
30
30
  | `upload` | `{ content?, name?, type?, path? }` | Sets a file on `<input type="file">`. Inline bytes default to `"reticle test file"` / `"file.txt"` / `"text/plain"`. `path` reads a file from disk, scoped to the project root plus any opt-in directories listed in `.reticle.json` as `"uploadRoots": ["~/Downloads", "/Volumes/fixtures"]`. A refusal names every allowed root. |
31
- | `drag` | `{ toRef }` | Pointer-based drag (dnd-kit, react-beautiful-dnd) plus HTML5 DnD. `target` is an alias |
31
+ | `drag` | `{ toRef, at?, to?, modifiers? }` | Pointer-based drag (dnd-kit, react-beautiful-dnd) plus HTML5 DnD. `target` is an alias. `modifiers` (for example `["Shift"]`) are held for the whole drag, so a canvas editor sees `shiftKey` on every pointer event |
32
32
 
33
33
  ### Arguments that are not actions
34
34
 
@@ -126,7 +126,7 @@ Call an old name and you are told the new one. `reticle_tools` prints the live s
126
126
 
127
127
  Not on this surface at all, but one hop away: `reticle_run { tool, args }` calls any registered tool by name, advertised or not, and `reticle_tools { names: [...] }` loads its arguments. That reaches `reticle_capabilities` (the app's whole testable surface in one call), `reticle_domain` (learn the app + gaps), `reticle_run { tool: "reticle_baseline", args: { action: "diff" } }`, `reticle_project` (run history), `reticle_screenshot`, `reticle_visual_diff`, `reticle_storage`, `reticle_network_mock` and `reticle_clock`. A daemon started with `RETICLE_ADVERTISE_ALL_TOOLS=1` advertises some of these directly (`reticle_capabilities`, `reticle_screenshot`, `reticle_visual_diff`, `reticle_storage`, `reticle_network_mock`, `reticle_clock`, plus `reticle_record`, `reticle_flow_save`, `reticle_flow_replay`, `reticle_intent` and `reticle_context`); the rest stay behind `reticle_run`. It also switches to the unmerged spelling: `reticle_snapshot`/`reticle_query`/`reticle_inspect`/`reticle_state` replace `reticle_look`, `reticle_network`/`reticle_console` replace `reticle_observe { action }`, `reticle_wait_for` replaces `reticle_assert { action: "wait" }`, `reticle_sessions`/`reticle_feedback` replace `reticle_session` list/feedback, and `reticle_act_sequence` replaces `reticle_act { steps }`. Examples on this page use the default spelling.
128
128
 
129
- **What the wider surface adds, through `reticle_run` (a few are also advertised directly with `RETICLE_ADVERTISE_ALL_TOOLS=1`):** record/replay a journey (`reticle_run { tool: "reticle_record", args: { action: "start" } }/stop`, `reticle_replay`), persist a self-healing golden flow (`reticle_flow_save*` / `reticle_flow_replay` / `reticle_verify { action: "heal" }`), compile annotations (`reticle_annotate`), explore autonomously (`reticle_explore` lists controls; `reticle_verify { action: "crawl" }` is now advertised directly, clicks them all and reports anomalies, and is **destructive**), reveal a virtualized off-screen row (`reticle_scroll_to`, for when `reticle_look { action: "find" }` finds nothing because a windowed list hasn't rendered it yet), visual-check (`reticle_screenshot` / `reticle_visual_diff`, pinned with `reticle_viewport` for reproducible baselines), test error/edge states by stubbing the network (`reticle_network_mock`: 500 / offline / delay, driven or leased), control time for toasts/debounces/auto-dismiss (`reticle_clock { freeze | advanceMs | reset }`), or work with a human (`reticle_session { action: "end" }` / `reticle_session { action: "resume" }` / `reticle_session { action: "messages" }`, and **`reticle_session { action: "review" }`** to drain + fix the bugs the human flagged from the panel).
129
+ **What the wider surface adds, through `reticle_run` (a few are also advertised directly with `RETICLE_ADVERTISE_ALL_TOOLS=1`):** record/replay a journey (`reticle_run { tool: "reticle_record", args: { action: "start" } }/stop`, then `{ action: "replay" }`), persist a self-healing golden flow (`reticle_flow_save*` / `reticle_flow_replay` / `reticle_verify { action: "heal" }`), compile annotations (`reticle_annotate`), explore autonomously (`reticle_look { action: "page", mode: "interactive" }` lists controls; `reticle_verify { action: "crawl" }` is now advertised directly, clicks them all and reports anomalies, and is **destructive**), reveal a virtualized off-screen row (`reticle_scroll_to`, for when `reticle_look { action: "find" }` finds nothing because a windowed list hasn't rendered it yet), visual-check (`reticle_screenshot` / `reticle_visual_diff`, pinned with `reticle_viewport` for reproducible baselines), test error/edge states by stubbing the network (`reticle_network_mock`: 500 / offline / delay, or `forwardTo` another origin, driven or leased), control time for toasts/debounces/auto-dismiss (`reticle_clock { freeze | advanceMs | reset }`), or work with a human (`reticle_session { action: "end" }` / `reticle_session { action: "resume" }` / `reticle_session { action: "messages" }`, and **`reticle_session { action: "review" }`** to drain + fix the bugs the human flagged from the panel).
130
130
 
131
131
  ## flows vs baselines vs project.json (the persistence layers)
132
132
 
@@ -115,14 +115,11 @@ This is plain, reviewable, version-controllable data, not a black box.
115
115
 
116
116
  ---
117
117
 
118
- ## Open-core licensing (what's free, what's protected)
118
+ ## Licensing
119
119
 
120
- - The **protocol and the rules** (`open-verification`, `@reticlehq/core`, `@reticlehq/engine`) are **Apache-2.0**. The part that decides a verdict is the part a sceptical reader most wants to audit, so it is the part with no licence in the way.
121
- - The embeddable **SDK** (`@reticlehq/browser`, `@reticlehq/react` and the build adapters) is **Apache-2.0**, safe to ship inside your own app.
122
- - The **server / CLI** is under the **Functional Source License (FSL-1.1, Apache-2.0 future)**: source-available, converts to Apache-2.0 over time.
123
- - Enterprise-only features live behind a license gate and are clearly separated.
120
+ Every npm package is **Apache-2.0**: the protocol and the rules (`open-verification`, `@reticlehq/core`, `@reticlehq/engine`), the embeddable SDK and its adapters, and the server, CLI, `init` and spec runner. The `reticle-tauri` crate is MIT.
124
121
 
125
- See [LICENSE](https://github.com/reticlehq/reticle/blob/main/LICENSE) and each package's own `LICENSE` file. The licensing _mechanism_ is open and inspectable; activation is offline (no phone-home).
122
+ See [LICENSE](https://github.com/reticlehq/reticle/blob/main/LICENSE) and each package's own `LICENSE` file.
126
123
 
127
124
  ---
128
125