@reticlehq/server 2.4.0 → 2.6.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 (472) hide show
  1. package/SKILL.md +719 -0
  2. package/dist/bridge/auth-failure-reason.d.ts +19 -0
  3. package/dist/bridge/auth-failure-reason.js +29 -0
  4. package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
  5. package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
  6. package/dist/{bridge.d.ts → bridge/bridge.d.ts} +13 -1
  7. package/dist/{bridge.js → bridge/bridge.js} +95 -15
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +9 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +18 -10
  10. package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
  11. package/dist/capsule/capsule-store.d.ts +8 -3
  12. package/dist/capsule/capsule-store.js +7 -2
  13. package/dist/capsule/capsule.js +3 -3
  14. package/dist/capsule/causal-summary.d.ts +8 -0
  15. package/dist/capsule/causal-summary.js +22 -12
  16. package/dist/capsule/divergence.d.ts +9 -4
  17. package/dist/capsule/divergence.js +8 -8
  18. package/dist/capsule/predicate-to-links.js +11 -8
  19. package/dist/cli/cli-doctor.d.ts +1 -0
  20. package/dist/cli/cli-doctor.js +135 -0
  21. package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
  22. package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
  23. package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
  24. package/dist/cli/cli-launch.js +171 -0
  25. package/dist/cli/cli-parse-feedback.d.ts +31 -0
  26. package/dist/cli/cli-parse-feedback.js +56 -0
  27. package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +6 -19
  28. package/dist/{cli-parse.js → cli/cli-parse.js} +118 -81
  29. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
  30. package/dist/{cli-port.js → cli/cli-port.js} +9 -9
  31. package/dist/cli/cli-update-commands.d.ts +4 -0
  32. package/dist/cli/cli-update-commands.js +93 -0
  33. package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
  34. package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
  35. package/dist/cli/doctor-daemon-line.d.ts +37 -0
  36. package/dist/cli/doctor-daemon-line.js +35 -0
  37. package/dist/cli/port-holder.d.ts +43 -0
  38. package/dist/cli/port-holder.js +99 -0
  39. package/dist/cli.d.ts +2 -2
  40. package/dist/cli.js +302 -100
  41. package/dist/cloud/cloud-config.d.ts +0 -1
  42. package/dist/cloud/cloud-config.js +9 -9
  43. package/dist/cloud/cloud-sync.d.ts +1 -7
  44. package/dist/cloud/cloud-sync.js +12 -12
  45. package/dist/crawl/crawl-empty.d.ts +16 -0
  46. package/dist/crawl/crawl-empty.js +24 -0
  47. package/dist/crawl/crawl-tools.js +4 -1
  48. package/dist/crawl/crawl.js +26 -7
  49. package/dist/daemon/daemon-resilience.d.ts +73 -0
  50. package/dist/daemon/daemon-resilience.js +279 -0
  51. package/dist/daemon/daemon-usefulness.d.ts +61 -0
  52. package/dist/daemon/daemon-usefulness.js +62 -0
  53. package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
  54. package/dist/{daemon.js → daemon/daemon.js} +105 -48
  55. package/dist/daemon/heartbeat.d.ts +115 -0
  56. package/dist/daemon/heartbeat.js +141 -0
  57. package/dist/daemon/idle-grace.d.ts +32 -0
  58. package/dist/daemon/idle-grace.js +41 -0
  59. package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +23 -2
  60. package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +37 -6
  61. package/dist/daemon/port-presence.d.ts +76 -0
  62. package/dist/daemon/port-presence.js +93 -0
  63. package/dist/daemon/state-dir.d.ts +7 -0
  64. package/dist/daemon/state-dir.js +59 -0
  65. package/dist/daemon/unclean-predecessor.d.ts +23 -0
  66. package/dist/daemon/unclean-predecessor.js +27 -0
  67. package/dist/domain/domain-model.js +2 -2
  68. package/dist/events/body-failures.js +8 -8
  69. package/dist/events/contradictions.d.ts +1 -1
  70. package/dist/events/contradictions.js +60 -10
  71. package/dist/events/echo-mismatch.js +10 -10
  72. package/dist/events/event-filters.js +6 -6
  73. package/dist/events/json-salvage.d.ts +2 -1
  74. package/dist/events/json-salvage.js +6 -6
  75. package/dist/events/observed-in-window.d.ts +12 -0
  76. package/dist/events/observed-in-window.js +21 -0
  77. package/dist/events/predicate-eval.d.ts +53 -20
  78. package/dist/events/predicate-eval.js +179 -55
  79. package/dist/events/predicate-parse.d.ts +23 -0
  80. package/dist/events/predicate-parse.js +54 -0
  81. package/dist/events/predicate.d.ts +7 -2
  82. package/dist/events/predicate.js +126 -35
  83. package/dist/events/reconcile.js +5 -5
  84. package/dist/events/ring-buffer.js +2 -17
  85. package/dist/events/stale-response.js +6 -6
  86. package/dist/events/testid-near-miss.d.ts +22 -0
  87. package/dist/events/testid-near-miss.js +33 -0
  88. package/dist/events/unit-mismatch.js +8 -8
  89. package/dist/flows/affected-tools.js +19 -4
  90. package/dist/flows/affected.js +1 -1
  91. package/dist/flows/annotate-target.d.ts +1 -0
  92. package/dist/flows/annotate-target.js +20 -0
  93. package/dist/flows/annotate-tools.js +25 -3
  94. package/dist/flows/annotate.js +17 -4
  95. package/dist/flows/assertion-integrity.d.ts +2 -1
  96. package/dist/flows/assertion-tiers-store.d.ts +3 -66
  97. package/dist/flows/assertion-tiers-store.js +2 -2
  98. package/dist/flows/attributed-failure.d.ts +17 -0
  99. package/dist/flows/attributed-failure.js +20 -0
  100. package/dist/flows/buddy-status.d.ts +2 -1
  101. package/dist/flows/buddy-status.js +2 -2
  102. package/dist/flows/coverage.d.ts +3 -2
  103. package/dist/flows/coverage.js +2 -2
  104. package/dist/flows/decision.js +24 -9
  105. package/dist/flows/empty-flow.d.ts +6 -0
  106. package/dist/flows/empty-flow.js +24 -0
  107. package/dist/flows/flake-store.d.ts +0 -1
  108. package/dist/flows/flake-store.js +1 -1
  109. package/dist/flows/flake.d.ts +2 -1
  110. package/dist/flows/flake.js +2 -2
  111. package/dist/flows/flow-classify.js +12 -0
  112. package/dist/flows/flow-replay-run.js +4 -4
  113. package/dist/flows/flow-replay.d.ts +6 -8
  114. package/dist/flows/flow-replay.js +132 -48
  115. package/dist/flows/flow-report.js +1 -1
  116. package/dist/flows/flow-scope.d.ts +1 -6
  117. package/dist/flows/flow-step-runners.d.ts +26 -6
  118. package/dist/flows/flow-step-runners.js +156 -6
  119. package/dist/flows/flow-success.js +20 -15
  120. package/dist/flows/flow-tools.js +63 -21
  121. package/dist/flows/flows.js +15 -11
  122. package/dist/flows/gate.d.ts +4 -3
  123. package/dist/flows/gate.js +1 -1
  124. package/dist/flows/heal-run.d.ts +0 -8
  125. package/dist/flows/heal-run.js +5 -5
  126. package/dist/flows/heal.js +3 -3
  127. package/dist/flows/predicate-to-expect.d.ts +38 -0
  128. package/dist/flows/predicate-to-expect.js +95 -0
  129. package/dist/flows/replay.d.ts +16 -1
  130. package/dist/flows/replay.js +58 -22
  131. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  132. package/dist/flows/role-anchor-nearest.js +45 -0
  133. package/dist/flows/role-drift-reason.d.ts +20 -0
  134. package/dist/flows/role-drift-reason.js +39 -0
  135. package/dist/flows/server-verify.d.ts +1 -1
  136. package/dist/flows/server-verify.js +5 -5
  137. package/dist/flows/suite-flakes.d.ts +33 -0
  138. package/dist/flows/suite-flakes.js +32 -0
  139. package/dist/flows/verify-change-tools.js +32 -10
  140. package/dist/flows/verify-change-verdict.d.ts +15 -0
  141. package/dist/flows/verify-change-verdict.js +25 -0
  142. package/dist/flows/watch-batcher.d.ts +3 -2
  143. package/dist/honesty/already-true.d.ts +2 -0
  144. package/dist/honesty/already-true.js +31 -0
  145. package/dist/honesty/blind-spots.d.ts +35 -3
  146. package/dist/honesty/blind-spots.js +57 -12
  147. package/dist/honesty/honesty.d.ts +3 -2
  148. package/dist/honesty/honesty.js +4 -4
  149. package/dist/honesty/uncaptured-bodies.js +1 -1
  150. package/dist/honesty/unread-outcome.js +2 -2
  151. package/dist/honesty/verified.d.ts +31 -3
  152. package/dist/honesty/verified.js +64 -8
  153. package/dist/http-server.js +23 -7
  154. package/dist/hunt/hunt-report.d.ts +2 -1
  155. package/dist/hunt/hunt-report.js +2 -2
  156. package/dist/index.d.ts +9 -6
  157. package/dist/index.js +41 -25
  158. package/dist/init/agent-rules.d.ts +20 -1
  159. package/dist/init/agent-rules.js +64 -8
  160. package/dist/init/app-choice.d.ts +20 -0
  161. package/dist/init/app-choice.js +25 -0
  162. package/dist/init/astro-host.d.ts +21 -0
  163. package/dist/init/astro-host.js +27 -0
  164. package/dist/init/astro-patch.d.ts +16 -0
  165. package/dist/init/astro-patch.js +240 -0
  166. package/dist/init/capabilities.js +4 -1
  167. package/dist/init/cra.d.ts +50 -0
  168. package/dist/init/cra.js +106 -0
  169. package/dist/init/cursor.js +39 -4
  170. package/dist/init/desktop-doctor.d.ts +3 -2
  171. package/dist/init/desktop-doctor.js +4 -4
  172. package/dist/init/detect.d.ts +9 -2
  173. package/dist/init/detect.js +24 -5
  174. package/dist/init/mcp-clients.d.ts +81 -0
  175. package/dist/init/mcp-clients.js +248 -0
  176. package/dist/init/mcp-registered.d.ts +12 -0
  177. package/dist/init/mcp-registered.js +14 -0
  178. package/dist/init/mcp.d.ts +27 -2
  179. package/dist/init/mcp.js +40 -4
  180. package/dist/init/next-patch.d.ts +2 -4
  181. package/dist/init/next-patch.js +109 -19
  182. package/dist/init/node-io.js +29 -6
  183. package/dist/init/plan-framework.d.ts +16 -1
  184. package/dist/init/plan-framework.js +166 -8
  185. package/dist/init/plan.d.ts +85 -6
  186. package/dist/init/plan.js +196 -33
  187. package/dist/init/project-id.d.ts +5 -9
  188. package/dist/init/project-id.js +10 -22
  189. package/dist/init/run.d.ts +23 -1
  190. package/dist/init/run.js +338 -47
  191. package/dist/init/slash-command.d.ts +9 -0
  192. package/dist/init/slash-command.js +10 -1
  193. package/dist/init/snippets.d.ts +7 -10
  194. package/dist/init/snippets.js +44 -15
  195. package/dist/init/vite-config.js +1 -1
  196. package/dist/init/windows-quote.d.ts +38 -0
  197. package/dist/init/windows-quote.js +70 -0
  198. package/dist/init/workspace-apps.d.ts +23 -0
  199. package/dist/init/workspace-apps.js +68 -0
  200. package/dist/input/driven-redaction.js +1 -1
  201. package/dist/input/network-detail.js +8 -8
  202. package/dist/input/network-mock-tools.js +2 -2
  203. package/dist/input/network-mock.js +4 -4
  204. package/dist/input/real-input.js +8 -3
  205. package/dist/input/scroll-find.js +2 -2
  206. package/dist/input/scroll-tools.d.ts +0 -5
  207. package/dist/input/scroll-tools.js +11 -4
  208. package/dist/input/viewport-tools.js +2 -2
  209. package/dist/journal/ambient-store.d.ts +0 -2
  210. package/dist/journal/ambient-store.js +1 -1
  211. package/dist/journal/ambient.js +1 -1
  212. package/dist/journal/attach-journal.d.ts +2 -1
  213. package/dist/journal/deviation-report.js +6 -6
  214. package/dist/journal/deviation-service.js +1 -1
  215. package/dist/journal/envelope-store.d.ts +0 -2
  216. package/dist/journal/envelope-store.js +1 -1
  217. package/dist/journal/envelope.d.ts +2 -3
  218. package/dist/journal/envelope.js +3 -3
  219. package/dist/journal/journal-query.js +1 -1
  220. package/dist/journal/journal-recorder.d.ts +2 -1
  221. package/dist/journal/journal-recorder.js +2 -2
  222. package/dist/journal/rollups.js +9 -9
  223. package/dist/journal/session-end.d.ts +2 -1
  224. package/dist/journal/session-journal.js +4 -4
  225. package/dist/license/license.d.ts +0 -14
  226. package/dist/license/license.js +8 -8
  227. package/dist/log.d.ts +10 -0
  228. package/dist/log.js +11 -1
  229. package/dist/mcp/mcp-is-error.d.ts +13 -0
  230. package/dist/mcp/mcp-is-error.js +18 -0
  231. package/dist/mcp/mcp-outage.d.ts +32 -0
  232. package/dist/mcp/mcp-outage.js +55 -0
  233. package/dist/mcp/mcp-proxy.d.ts +134 -0
  234. package/dist/mcp/mcp-proxy.js +720 -0
  235. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  236. package/dist/{mcp.js → mcp/mcp.js} +139 -37
  237. package/dist/mcp/proxy-handshake.d.ts +3 -0
  238. package/dist/mcp/proxy-handshake.js +54 -0
  239. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  240. package/dist/mcp/proxy-lifecycle.js +70 -0
  241. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  242. package/dist/mcp/tool-catalog-cache.js +55 -0
  243. package/dist/oracles/propose-consequences.d.ts +2 -1
  244. package/dist/oracles/propose-consequences.js +16 -11
  245. package/dist/oracles/self-instrument.d.ts +2 -1
  246. package/dist/oracles/self-instrument.js +1 -1
  247. package/dist/phenomena/phenomena.js +3 -3
  248. package/dist/platform.d.ts +16 -0
  249. package/dist/platform.js +16 -0
  250. package/dist/pool/browser-pool.d.ts +9 -0
  251. package/dist/pool/browser-pool.js +38 -9
  252. package/dist/pool/playwright-launcher.d.ts +15 -2
  253. package/dist/pool/playwright-launcher.js +21 -2
  254. package/dist/project/fs-port.js +1 -1
  255. package/dist/project/project-tools.js +2 -2
  256. package/dist/runs/build-verification-run.js +1 -1
  257. package/dist/runs/repair-prompt.d.ts +0 -6
  258. package/dist/runs/repair-prompt.js +3 -3
  259. package/dist/runs/risk-classify.js +1 -1
  260. package/dist/runs/run-diff.d.ts +0 -2
  261. package/dist/runs/run-diff.js +3 -3
  262. package/dist/runs/run-tools.js +2 -2
  263. package/dist/runs/verification-sync.js +2 -2
  264. package/dist/runs/verify-http.js +1 -1
  265. package/dist/runs/verify-server.js +1 -1
  266. package/dist/session/attachment-history.d.ts +46 -0
  267. package/dist/session/attachment-history.js +65 -0
  268. package/dist/session/command-timeout.d.ts +11 -3
  269. package/dist/session/command-timeout.js +2 -2
  270. package/dist/session/control-envelope.d.ts +6 -0
  271. package/dist/session/control-envelope.js +7 -1
  272. package/dist/session/dev-server-probe.d.ts +13 -0
  273. package/dist/session/dev-server-probe.js +52 -0
  274. package/dist/session/last-act.d.ts +17 -3
  275. package/dist/session/last-act.js +16 -4
  276. package/dist/session/live-control-tools.js +7 -2
  277. package/dist/session/live-control.js +1 -1
  278. package/dist/session/looks-like-dev-server.d.ts +14 -0
  279. package/dist/session/looks-like-dev-server.js +25 -0
  280. package/dist/session/no-session-diagnosis.d.ts +45 -0
  281. package/dist/session/no-session-diagnosis.js +120 -0
  282. package/dist/session/no-session-watch.d.ts +21 -0
  283. package/dist/session/no-session-watch.js +69 -0
  284. package/dist/session/observed-state.d.ts +4 -0
  285. package/dist/session/observed-state.js +19 -1
  286. package/dist/session/output-budget.js +1 -1
  287. package/dist/session/pending-commands.js +1 -0
  288. package/dist/session/session-health.d.ts +8 -1
  289. package/dist/session/session-health.js +8 -7
  290. package/dist/session/session-info.d.ts +43 -8
  291. package/dist/session/session-info.js +46 -1
  292. package/dist/session/session-lease.d.ts +0 -11
  293. package/dist/session/session-lease.js +1 -1
  294. package/dist/session/session-manager.d.ts +6 -0
  295. package/dist/session/session-manager.js +124 -12
  296. package/dist/session/session-readiness.d.ts +1 -1
  297. package/dist/session/session-readiness.js +6 -1
  298. package/dist/session/session-reaper.js +1 -1
  299. package/dist/session/session-reconnect.d.ts +32 -0
  300. package/dist/session/session-reconnect.js +42 -0
  301. package/dist/session/session.d.ts +15 -2
  302. package/dist/session/session.js +77 -26
  303. package/dist/session/state-select.d.ts +1 -1
  304. package/dist/session/state-select.js +1 -1
  305. package/dist/status-payload.d.ts +19 -0
  306. package/dist/status-payload.js +11 -0
  307. package/dist/telemetry/argument-shape.js +10 -1
  308. package/dist/telemetry/browser-mode.d.ts +27 -0
  309. package/dist/telemetry/browser-mode.js +33 -0
  310. package/dist/telemetry/bug-found.d.ts +17 -21
  311. package/dist/telemetry/bug-found.js +120 -8
  312. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  313. package/dist/telemetry/cli-telemetry.js +27 -4
  314. package/dist/telemetry/crash-cause.d.ts +47 -0
  315. package/dist/telemetry/crash-cause.js +104 -0
  316. package/dist/telemetry/daemon-telemetry.d.ts +38 -1
  317. package/dist/telemetry/daemon-telemetry.js +37 -12
  318. package/dist/telemetry/dev-repo.js +4 -4
  319. package/dist/telemetry/error-class.d.ts +26 -0
  320. package/dist/telemetry/error-class.js +52 -0
  321. package/dist/telemetry/error-fingerprint.js +21 -2
  322. package/dist/telemetry/feedback-cli.d.ts +8 -3
  323. package/dist/telemetry/feedback-cli.js +52 -8
  324. package/dist/telemetry/feedback-context.d.ts +23 -6
  325. package/dist/telemetry/feedback-context.js +105 -5
  326. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  327. package/dist/telemetry/feedback-delivery.js +30 -0
  328. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  329. package/dist/telemetry/feedback-outbox.js +87 -0
  330. package/dist/telemetry/feedback.d.ts +22 -1
  331. package/dist/telemetry/feedback.js +67 -8
  332. package/dist/telemetry/git-facts.d.ts +7 -0
  333. package/dist/telemetry/git-facts.js +5 -5
  334. package/dist/telemetry/project-profile.js +2 -1
  335. package/dist/telemetry/session-metrics.d.ts +47 -3
  336. package/dist/telemetry/session-metrics.js +315 -15
  337. package/dist/telemetry/telemetry.d.ts +45 -2
  338. package/dist/telemetry/telemetry.js +150 -37
  339. package/dist/telemetry/verification-of.d.ts +22 -0
  340. package/dist/telemetry/verification-of.js +84 -0
  341. package/dist/tools/act-capsule.js +2 -2
  342. package/dist/tools/act-danger.d.ts +12 -0
  343. package/dist/tools/act-danger.js +20 -3
  344. package/dist/tools/act-helpers.js +4 -4
  345. package/dist/tools/act-tools.d.ts +0 -8
  346. package/dist/tools/act-tools.js +114 -118
  347. package/dist/tools/act-view.js +7 -7
  348. package/dist/tools/alias-args.d.ts +17 -0
  349. package/dist/tools/alias-args.js +25 -0
  350. package/dist/tools/assert-grade.js +9 -9
  351. package/dist/tools/assert-verdict.d.ts +9 -1
  352. package/dist/tools/assert-verdict.js +21 -6
  353. package/dist/tools/browser-tools.js +36 -11
  354. package/dist/tools/contract-tools.d.ts +0 -5
  355. package/dist/tools/contract-tools.js +27 -1
  356. package/dist/tools/coverage-identity.d.ts +34 -0
  357. package/dist/tools/coverage-identity.js +46 -0
  358. package/dist/tools/coverage-tools.js +10 -14
  359. package/dist/tools/dynamic-tools.d.ts +2 -1
  360. package/dist/tools/dynamic-tools.js +96 -19
  361. package/dist/tools/error-recovery.d.ts +34 -2
  362. package/dist/tools/error-recovery.js +255 -4
  363. package/dist/tools/feedback-invite.d.ts +48 -0
  364. package/dist/tools/feedback-invite.js +71 -0
  365. package/dist/tools/feedback-tools.d.ts +12 -1
  366. package/dist/tools/feedback-tools.js +28 -5
  367. package/dist/tools/invoke-tool.d.ts +0 -12
  368. package/dist/tools/invoke-tool.js +126 -33
  369. package/dist/tools/lease-hint.d.ts +17 -0
  370. package/dist/tools/lease-hint.js +24 -0
  371. package/dist/tools/lease-tools.js +6 -5
  372. package/dist/tools/merge-tools.d.ts +10 -1
  373. package/dist/tools/merge-tools.js +9 -3
  374. package/dist/tools/merged-name-redirect.d.ts +13 -0
  375. package/dist/tools/merged-name-redirect.js +55 -0
  376. package/dist/tools/navigate-arrival.d.ts +26 -0
  377. package/dist/tools/navigate-arrival.js +60 -0
  378. package/dist/tools/navigate-result.d.ts +31 -0
  379. package/dist/tools/navigate-result.js +38 -0
  380. package/dist/tools/observe-tools.js +72 -20
  381. package/dist/tools/observed-nothing.d.ts +25 -0
  382. package/dist/tools/observed-nothing.js +33 -0
  383. package/dist/tools/query-paginate.js +2 -2
  384. package/dist/tools/query-shape.d.ts +18 -0
  385. package/dist/tools/query-shape.js +39 -0
  386. package/dist/tools/read-tools.js +81 -20
  387. package/dist/tools/real-input-attempt.d.ts +28 -0
  388. package/dist/tools/real-input-attempt.js +93 -0
  389. package/dist/tools/reconcile-tools.js +7 -7
  390. package/dist/tools/reload-result.d.ts +14 -0
  391. package/dist/tools/reload-result.js +29 -0
  392. package/dist/tools/snapshot-delta.d.ts +4 -5
  393. package/dist/tools/snapshot-delta.js +0 -0
  394. package/dist/tools/tool-kit.d.ts +16 -0
  395. package/dist/tools/tool-surface.d.ts +83 -0
  396. package/dist/tools/tool-surface.js +217 -0
  397. package/dist/tools/tools-helpers.js +6 -6
  398. package/dist/tools/tools.d.ts +15 -0
  399. package/dist/tools/tools.js +53 -17
  400. package/dist/tools/unadvertised-help.d.ts +5 -0
  401. package/dist/tools/unadvertised-help.js +39 -0
  402. package/dist/trace.d.ts +69 -0
  403. package/dist/trace.js +150 -0
  404. package/dist/update/nudge-credit.d.ts +4 -0
  405. package/dist/update/nudge-credit.js +53 -0
  406. package/dist/update/sdk-sync.d.ts +21 -0
  407. package/dist/update/sdk-sync.js +42 -0
  408. package/dist/update/update-checker.js +3 -3
  409. package/dist/update/update-nudge.d.ts +63 -6
  410. package/dist/update/update-nudge.js +128 -15
  411. package/dist/update/updater.d.ts +1 -9
  412. package/dist/update/updater.js +13 -8
  413. package/dist/version/peer-announce.d.ts +4 -0
  414. package/dist/version/peer-announce.js +30 -0
  415. package/dist/{server-version.js → version/server-version.js} +5 -1
  416. package/dist/version/version-nudge.d.ts +28 -0
  417. package/dist/version/version-nudge.js +40 -0
  418. package/dist/version/version-skew.d.ts +66 -0
  419. package/dist/version/version-skew.js +71 -0
  420. package/dist/visual/visual-diff.js +2 -2
  421. package/dist/visual/visual-tools.js +4 -4
  422. package/docs/README.md +55 -0
  423. package/docs/agent-cheatsheet.md +85 -0
  424. package/docs/architecture.md +113 -0
  425. package/docs/benchmarks.md +255 -0
  426. package/docs/debugging.md +102 -0
  427. package/docs/deploy-checks.md +69 -0
  428. package/docs/desktop-apps.md +256 -0
  429. package/docs/enterprise.md +62 -0
  430. package/docs/fixtures-dispatch-receiver.yml +76 -0
  431. package/docs/fixtures.md +45 -0
  432. package/docs/flows.md +166 -0
  433. package/docs/gate-plan.md +98 -0
  434. package/docs/gates.md +117 -0
  435. package/docs/getting-started.md +469 -0
  436. package/docs/human-control.md +63 -0
  437. package/docs/integration-patterns.md +171 -0
  438. package/docs/local-registry.md +126 -0
  439. package/docs/matrix/2.5.0/claude-code-machine.json +19 -0
  440. package/docs/matrix/2.5.0/codex-machine.json +20 -0
  441. package/docs/matrix/2.5.0/cursor-machine.json +22 -0
  442. package/docs/matrix/2.5.0/gemini-machine.json +22 -0
  443. package/docs/matrix/2.5.0/opencode-machine.json +22 -0
  444. package/docs/matrix/2.5.0/vscode-machine.json +22 -0
  445. package/docs/matrix/2.5.0/windsurf-machine.json +22 -0
  446. package/docs/matrix/MATRIX.md +26 -0
  447. package/docs/matrix/README.md +59 -0
  448. package/docs/mint.json +61 -0
  449. package/docs/multi-agent-testing.md +55 -0
  450. package/docs/platform-integration.md +122 -0
  451. package/docs/system-map.md +152 -0
  452. package/docs/telemetry-contract.md +214 -0
  453. package/docs/telemetry.md +191 -0
  454. package/docs/testing.md +82 -0
  455. package/docs/token-efficiency.md +80 -0
  456. package/docs/usage.md +1046 -0
  457. package/package.json +8 -5
  458. package/dist/cli-doctor.d.ts +0 -6
  459. package/dist/cli-doctor.js +0 -60
  460. package/dist/cli-launch.js +0 -112
  461. package/dist/daemon-resilience.d.ts +0 -22
  462. package/dist/daemon-resilience.js +0 -85
  463. package/dist/mcp-proxy.d.ts +0 -67
  464. package/dist/mcp-proxy.js +0 -337
  465. package/dist/tools/profiles.d.ts +0 -37
  466. package/dist/tools/profiles.js +0 -139
  467. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  468. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  469. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  470. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  471. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  472. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -1,6 +1,8 @@
1
1
  import { z } from 'zod';
2
+ import { emptyFlowRefusal } from './empty-flow.js';
3
+ import { aliasParam } from '../tools/alias-args.js';
2
4
  import { FlowErrorCode, RecordedSaveError, ReplayStatus, } from '@reticlehq/core';
3
- import { FlakeStore } from './flake-store.js';
5
+ import { recordSuiteFlakes } from './suite-flakes.js';
4
6
  import { ReticleTool } from '../tools/tool-names.js';
5
7
  import { asNumber, asString } from '../tools/tools-helpers.js';
6
8
  import { log } from '../log.js';
@@ -25,7 +27,7 @@ export { replayNamedFlow } from './flow-replay-run.js';
25
27
  async function syncSavedFlowToCloud(deps, flow, projectId) {
26
28
  // Per-project cloud: sync a saved flow only when cloud is attached AND flow sync is enabled.
27
29
  const cloud = await resolveProjectCloud(deps.fs, deps.reticleRoot, homedir(), process.env);
28
- if (cloud.config === null || !cloud.policy.flows)
30
+ if (null === cloud.config || !cloud.policy.flows)
29
31
  return; // not attached / flows disabled → local only
30
32
  const result = await syncFlowToCloud(flow, cloud.config, projectId, (url, init) => fetch(url, init));
31
33
  if (result.outcome !== SyncOutcome.SYNCED) {
@@ -43,7 +45,7 @@ async function syncSavedFlowToCloud(deps, flow, projectId) {
43
45
  export function leasableAppUrl(deps, sessionId) {
44
46
  try {
45
47
  const url = deps.sessions.resolve(sessionId).url;
46
- if (typeof url !== 'string' || url.length === 0)
48
+ if (typeof url !== 'string' || 0 === url.length)
47
49
  return undefined;
48
50
  return new URL(url).origin;
49
51
  }
@@ -70,6 +72,10 @@ export const FLOW_TOOLS = [
70
72
  name: ReticleTool.FLOW_SAVE,
71
73
  description: 'Persist the last/active recording (by name) as a git-checked, anchor-resolved flow at .reticle/flows/<name>.json. Each step is bound to a SEMANTIC anchor (testid/role/signal), never a volatile ref; steps without a resolvable testid are kept with degraded:true (a "add a data-testid here" marker) rather than dropped. Returns { name, stepCount, degraded, empty, assertions } — `assertions.grade` is asserted | presence-only | assertion-free: a flow that only acts (or only checks element presence) will pass even if the feature breaks, so when grade is not "asserted" follow assertions.warning and add a consequence assertion via reticle_annotate (assert-signal / assert-net / success-state).',
72
74
  inputSchema: {
75
+ flow: z
76
+ .string()
77
+ .optional()
78
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
73
79
  flowName: z
74
80
  .string()
75
81
  .describe('Name for the flow file (saved to .reticle/flows/<flowName>.json). Use again in reticle_flow{action:"load"} / reticle_flow_replay.'),
@@ -103,7 +109,7 @@ export const FLOW_TOOLS = [
103
109
  code: z.string().optional(),
104
110
  },
105
111
  handler: (deps, args) => {
106
- const name = asString(args['flowName']) ?? '';
112
+ const name = asString(aliasParam(args, 'flowName', ['flow'])['flowName']) ?? '';
107
113
  const program = deps.recordings.getCompiled(name);
108
114
  if (program === undefined) {
109
115
  return Promise.resolve({
@@ -121,6 +127,11 @@ export const FLOW_TOOLS = [
121
127
  ...(intent !== undefined ? { intent } : {}),
122
128
  };
123
129
  const projectId = sessionProjectId(deps, asString(args['sessionId']));
130
+ // A zero-step recording is not a flow. Saving it wrote a file the suite reports "unverifiable"
131
+ // forever while telling the agent it had saved a regression test — see empty-flow.
132
+ const emptyRefusal = emptyFlowRefusal(program.steps.length, name);
133
+ if (emptyRefusal !== undefined)
134
+ return Promise.resolve(emptyRefusal);
124
135
  return deps.flows.save(program, annotations, projectId).then(async (res) => {
125
136
  if (!res.ok)
126
137
  return { error: flowErrorMessage(res.code), code: res.code };
@@ -170,6 +181,10 @@ export const FLOW_TOOLS = [
170
181
  name: ReticleTool.FLOW_LOAD,
171
182
  description: 'Read + validate a saved flow by flowName from .reticle/flows/<flowName>.json. Returns the FlowFile (version, flowName, createdAt, anchored steps) or a structured { error, code }.',
172
183
  inputSchema: {
184
+ flow: z
185
+ .string()
186
+ .optional()
187
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
173
188
  flowName: z
174
189
  .string()
175
190
  .describe('Flow file name (without .json extension) from reticle_flow{action:"list"}.'),
@@ -179,13 +194,19 @@ export const FLOW_TOOLS = [
179
194
  .describe('Active session ID — resolves the flow within that app’s scope.'),
180
195
  },
181
196
  outputSchema: {
197
+ flow: z
198
+ .string()
199
+ .optional()
200
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
182
201
  flowName: z.string(),
183
202
  steps: z.array(z.unknown()),
184
203
  createdAt: z.number().optional(),
185
204
  },
186
205
  handler: (deps, args) => {
187
206
  const projectId = sessionProjectId(deps, asString(args['sessionId']));
188
- return deps.flows.load(asString(args['flowName']) ?? '', projectId).then((res) => {
207
+ return deps.flows
208
+ .load(asString(aliasParam(args, 'flowName', ['flow'])['flowName']) ?? '', projectId)
209
+ .then((res) => {
189
210
  if (!res.ok)
190
211
  return { error: flowErrorMessage(res.code), code: res.code };
191
212
  const { name, ...rest } = res.value;
@@ -199,6 +220,10 @@ export const FLOW_TOOLS = [
199
220
  'to the connected app. Returns { deleted: true } or a structured { error, code } (code not_found ' +
200
221
  'when no such flow — deleting an absent flow is an error, not a silent no-op).',
201
222
  inputSchema: {
223
+ flow: z
224
+ .string()
225
+ .optional()
226
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
202
227
  flowName: z
203
228
  .string()
204
229
  .describe('Flow file name (without .json extension) from reticle_flow{action:"list"}.'),
@@ -214,7 +239,9 @@ export const FLOW_TOOLS = [
214
239
  },
215
240
  handler: (deps, args) => {
216
241
  const projectId = sessionProjectId(deps, asString(args['sessionId']));
217
- return deps.flows.remove(asString(args['flowName']) ?? '', projectId).then((res) => {
242
+ return deps.flows
243
+ .remove(asString(aliasParam(args, 'flowName', ['flow'])['flowName']) ?? '', projectId)
244
+ .then((res) => {
218
245
  if (!res.ok)
219
246
  return { error: flowErrorMessage(res.code), code: res.code };
220
247
  return { deleted: true };
@@ -230,6 +257,10 @@ export const FLOW_TOOLS = [
230
257
  'Returns { name, status: ok|drift|error, steps:[...] }; missing/malformed files and action ' +
231
258
  'failures are status:error with a structured code (distinct from contract-changed drift).',
232
259
  inputSchema: {
260
+ flow: z
261
+ .string()
262
+ .optional()
263
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
233
264
  flowName: z
234
265
  .string()
235
266
  .describe('Flow file name (without .json extension) from reticle_flow{action:"list"}.'),
@@ -311,7 +342,7 @@ export const FLOW_TOOLS = [
311
342
  // "Replay all" means all of THIS app's flows (+ legacy), not every project's on a shared daemon.
312
343
  const projectId = sessionProjectId(deps, sessionId);
313
344
  const requested = Array.isArray(args['names'])
314
- ? args['names'].filter((n) => typeof n === 'string')
345
+ ? args['names'].filter((n) => 'string' === typeof n)
315
346
  : await deps.flows.list(projectId);
316
347
  // verify:server — hand the whole suite to the hosted runner; it records the verification itself.
317
348
  const cloud = await resolveProjectCloud(deps.fs, deps.reticleRoot, homedir(), process.env);
@@ -352,18 +383,15 @@ export const FLOW_TOOLS = [
352
383
  const flow = loaded !== null && loaded.ok ? loaded.value : undefined;
353
384
  return flow === undefined ? { replay } : { replay, flow };
354
385
  }));
355
- return buildSuiteVerdict(parallelRuns);
386
+ const flaky = await recordSuiteFlakes(deps.fs, deps.reticleRoot, parallelRuns);
387
+ const verdict = buildSuiteVerdict(parallelRuns);
388
+ return flaky.length > 0 ? { ...verdict, flaky: [...flaky] } : verdict;
356
389
  }
357
390
  // The flow FILE travels with each replay so the verdict can tell a green that verified
358
391
  // something from a green that could never have gone red. Without it the suite reported "all 1
359
392
  // flow pass" for a flow with no steps at all.
360
393
  const runs = [];
361
394
  const timed = [];
362
- // The flake ledger the CLI gate already keeps — see FlakeStore. It was only ever written by
363
- // `reticle flow` on the command line, so an AGENT running this tool a hundred times learned
364
- // nothing about which flows are intermittent. Same product, same ledger, two surfaces, and the
365
- // one an agent uses was the blind half.
366
- const flakes = new FlakeStore(deps.fs, deps.reticleRoot);
367
395
  // Sequential default: every flow replays against the same live session, so they must not overlap.
368
396
  for (const flowName of requested) {
369
397
  const start = deps.now();
@@ -373,19 +401,18 @@ export const FLOW_TOOLS = [
373
401
  runs.push(flow === undefined ? { replay } : { replay, flow });
374
402
  timed.push({ replay, durationMs: deps.now() - start });
375
403
  }
376
- // Accrue this run's outcomes, then report what the ledger knows. Best-effort on both halves: a
377
- // flake ledger is memory, not a gate, and it must never turn a working verify into an error.
378
- for (const { replay } of runs) {
379
- await flakes.record(replay.name, replay.status === ReplayStatus.OK).catch(() => undefined);
380
- }
381
- const flaky = await flakes.flakyFlows().catch(() => []);
404
+ // The flake ledger the CLI gate already keeps — see FlakeStore. It was only ever written by
405
+ // `reticle flow` on the command line, so an AGENT running this tool a hundred times learned
406
+ // nothing about which flows are intermittent. Same product, same ledger, two surfaces, and the
407
+ // one an agent uses was the blind half.
408
+ const flaky = await recordSuiteFlakes(deps.fs, deps.reticleRoot, runs);
382
409
  // Emit the consolidated run artifact (Runs tab) + best-effort cloud push. Never blocks the verdict.
383
410
  await persistAndSyncVerificationRun(deps, timed, projectId);
384
411
  const verdict = buildSuiteVerdict(runs);
385
412
  // A flow that has both passed and failed on UNCHANGED code is a different thing from a
386
413
  // regression, and an agent that cannot tell them apart either chases a ghost or ignores a real
387
414
  // break. Present only when the ledger has seen enough runs to say so.
388
- return flaky.length > 0 ? { ...verdict, flaky } : verdict;
415
+ return flaky.length > 0 ? { ...verdict, flaky: [...flaky] } : verdict;
389
416
  },
390
417
  },
391
418
  {
@@ -397,6 +424,10 @@ export const FLOW_TOOLS = [
397
424
  'recorded name. Returns { name, stepCount, degraded, empty } or { error, code } (code ' +
398
425
  'flow_no_recorded when no recording is present).',
399
426
  inputSchema: {
427
+ flow: z
428
+ .string()
429
+ .optional()
430
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
400
431
  flowName: z
401
432
  .string()
402
433
  .optional()
@@ -427,10 +458,13 @@ export const FLOW_TOOLS = [
427
458
  code: RecordedSaveError.NO_RECORDED_FLOW,
428
459
  };
429
460
  }
430
- const override = asString(args['flowName']);
461
+ const override = asString(aliasParam(args, 'flowName', ['flow'])['flowName']);
431
462
  const flow = override !== undefined ? { ...recorded.flow, name: override } : recorded.flow;
432
463
  // The store stamps the project into the file AND routes it to the per-project subdir (a shared
433
464
  // daemon serves many apps), so location and content agree from one source of truth.
465
+ const emptyRecorded = emptyFlowRefusal(flow.steps.length, flow.name);
466
+ if (emptyRecorded !== undefined)
467
+ return emptyRecorded;
434
468
  const res = await deps.flows.saveFlow(flow, session.projectId);
435
469
  if (!res.ok)
436
470
  return { error: flowErrorMessage(res.code), code: res.code };
@@ -454,6 +488,10 @@ export const FLOW_TOOLS = [
454
488
  'untouched). Returns { name, status: healed|drift|unhealable|consequence_broken|' +
455
489
  'nothing_to_heal|error, applied, proposals[], changed[], message }.',
456
490
  inputSchema: {
491
+ flow: z
492
+ .string()
493
+ .optional()
494
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
457
495
  flowName: z.string().describe('Flow file name to heal (from reticle_flow{action:"list"}).'),
458
496
  apply: z.boolean().optional(),
459
497
  confirmDangerous: z
@@ -466,6 +504,10 @@ export const FLOW_TOOLS = [
466
504
  .describe('Active session ID from reticle_sessions. Omit when only one browser session is open.'),
467
505
  },
468
506
  outputSchema: {
507
+ flow: z
508
+ .string()
509
+ .optional()
510
+ .describe('Alias for `flowName` (the name reticle_annotate uses).'),
469
511
  flowName: z.string(),
470
512
  status: z.string(),
471
513
  applied: z.boolean(),
@@ -28,10 +28,10 @@ function sourceArg(src) {
28
28
  const source = asRecord(src['source']);
29
29
  const file = source['file'];
30
30
  const line = source['line'];
31
- if (typeof file !== 'string' || file.length === 0 || typeof line !== 'number')
31
+ if (typeof file !== 'string' || 0 === file.length || typeof line !== 'number')
32
32
  return undefined;
33
33
  const out = { file, line };
34
- if (typeof source['column'] === 'number')
34
+ if ('number' === typeof source['column'])
35
35
  out.column = source['column'];
36
36
  return out;
37
37
  }
@@ -109,8 +109,12 @@ export function recordedStepToFlowStep(step) {
109
109
  if (step.tool === ReticleTool.ACT_SEQUENCE) {
110
110
  const rawSubs = Array.isArray(step.args['steps']) ? step.args['steps'] : [];
111
111
  const subs = rawSubs.map(subStepToFlowStep);
112
- const degraded = subs.some((s) => s.degraded === true);
113
- const anchor = subs[0]?.anchor ?? degradedAnchor();
112
+ const degraded = subs.some((s) => true === s.degraded);
113
+ // The first sub-step that HAS an anchor, not blindly the first. Taking subs[0] handed the whole
114
+ // sequence the degraded sentinel whenever sub-step 0 lacked a testid — even with every later
115
+ // sub-step perfectly anchored — and replay then queried the DOM for a testid literally named
116
+ // "unresolved", so the step drifted on all 5 apps, every replay.
117
+ const anchor = subs.find((s) => s.degraded !== true)?.anchor ?? subs[0]?.anchor ?? degradedAnchor();
114
118
  const out = { tool: ReticleTool.ACT_SEQUENCE, anchor, steps: subs };
115
119
  if (degraded)
116
120
  out.degraded = true;
@@ -185,14 +189,14 @@ export class FlowStore {
185
189
  const flow = withAnnotations(base, annotations);
186
190
  await this.#fs.mkdir(flowDir(this.#root, pid));
187
191
  await this.#fs.writeFile(flowPath(this.#root, program.name, pid), this.#serialize(flow));
188
- const degraded = flow.steps.filter((s) => s.degraded === true).length;
192
+ const degraded = flow.steps.filter((s) => true === s.degraded).length;
189
193
  return {
190
194
  ok: true,
191
195
  value: {
192
196
  name: program.name,
193
197
  stepCount: flow.steps.length,
194
198
  degraded,
195
- empty: flow.steps.length === 0,
199
+ empty: 0 === flow.steps.length,
196
200
  },
197
201
  };
198
202
  }
@@ -214,14 +218,14 @@ export class FlowStore {
214
218
  const valid = parsed.data;
215
219
  await this.#fs.mkdir(flowDir(this.#root, pid));
216
220
  await this.#fs.writeFile(flowPath(this.#root, asFlowName(valid.name), pid), this.#serialize(valid));
217
- const degraded = valid.steps.filter((s) => s.degraded === true).length;
221
+ const degraded = valid.steps.filter((s) => true === s.degraded).length;
218
222
  return {
219
223
  ok: true,
220
224
  value: {
221
225
  name: valid.name,
222
226
  stepCount: valid.steps.length,
223
227
  degraded,
224
- empty: valid.steps.length === 0,
228
+ empty: 0 === valid.steps.length,
225
229
  },
226
230
  };
227
231
  }
@@ -247,7 +251,7 @@ export class FlowStore {
247
251
  // Write back to the SAME file load resolved (nested if it lives there, else legacy flat), so a
248
252
  // heal never forks a second copy and byte-stability holds regardless of where the flow lives.
249
253
  const path = await this.#resolveReadPath(name, pid);
250
- if (path === null)
254
+ if (null === path)
251
255
  return { ok: false, code: FlowErrorCode.NOT_FOUND };
252
256
  const { flow: next, applied } = applyHealChanges(flow, changes);
253
257
  await this.#fs.writeFile(path, this.#serialize(next));
@@ -343,7 +347,7 @@ export class FlowStore {
343
347
  if (!isValidFlowName(name))
344
348
  return { ok: false, code: FlowErrorCode.INVALID_NAME };
345
349
  const path = await this.#resolveReadPath(name, safeProjectId(projectId));
346
- if (path === null)
350
+ if (null === path)
347
351
  return { ok: false, code: FlowErrorCode.NOT_FOUND };
348
352
  let text;
349
353
  try {
@@ -377,7 +381,7 @@ export class FlowStore {
377
381
  if (!isValidFlowName(name))
378
382
  return { ok: false, code: FlowErrorCode.INVALID_NAME };
379
383
  const path = await this.#resolveReadPath(name, safeProjectId(projectId));
380
- if (path === null)
384
+ if (null === path)
381
385
  return { ok: false, code: FlowErrorCode.NOT_FOUND };
382
386
  await this.#fs.rm(path);
383
387
  return { ok: true, value: undefined };
@@ -6,12 +6,12 @@
6
6
  * inputs (git diff → affected → run artifacts + flake ledger) and maps `pass` to the exit code.
7
7
  */
8
8
  /** A flow whose assertions were WEAKENED since its last passing run. */
9
- export interface DowngradedFlow {
9
+ interface DowngradedFlow {
10
10
  flow: string;
11
11
  /** Step indices whose mustHold dropped from a consequence to presence-only. */
12
12
  steps: number[];
13
13
  }
14
- export interface GateInput {
14
+ interface GateInput {
15
15
  /** Flows that must be covered (from the affected index over the changed files). */
16
16
  affected: readonly string[];
17
17
  /** Flows that have a passing verification artifact. */
@@ -23,7 +23,7 @@ export interface GateInput {
23
23
  /** Flows that covered a changed file but no longer exist — coverage deleted rather than satisfied. */
24
24
  deleted?: readonly string[];
25
25
  }
26
- export interface GateResult {
26
+ interface GateResult {
27
27
  /** True when every affected, non-flaky flow has a passing artifact AND nothing was weakened/deleted. */
28
28
  pass: boolean;
29
29
  /** Affected flows with no passing artifact and not flaky — these block the gate. */
@@ -36,3 +36,4 @@ export interface GateResult {
36
36
  deleted: string[];
37
37
  }
38
38
  export declare function gateDecision(input: GateInput): GateResult;
39
+ export {};
@@ -24,7 +24,7 @@ export function gateDecision(input) {
24
24
  const downgraded = [...(input.downgraded ?? [])];
25
25
  const deleted = [...(input.deleted ?? [])];
26
26
  return {
27
- pass: uncovered.length === 0 && downgraded.length === 0 && deleted.length === 0,
27
+ pass: 0 === uncovered.length && 0 === downgraded.length && 0 === deleted.length,
28
28
  uncovered,
29
29
  quarantined,
30
30
  downgraded,
@@ -7,12 +7,4 @@
7
7
  */
8
8
  import { type FlowHealResult } from '@reticlehq/core';
9
9
  import type { ToolDeps } from '../tools/tools.js';
10
- export declare const HEAL_MESSAGES: {
11
- readonly NOTHING: "nothing to heal — every anchor resolved on replay";
12
- readonly HEALED: "rewrote drifted testid anchors to their nearest surviving match and re-verified the flow's success consequence still fires";
13
- readonly DRIFT_DRY: "confident rebind(s) proposed — re-run with apply:true to write them to disk";
14
- readonly UNHEALABLE: "drift found, but no nearest match cleared the confidence floor (HEAL_CONFIDENCE_MIN=0.5); file left untouched — add a data-testid or fix the flow by hand";
15
- readonly HEALED_UNVERIFIED: "rewrote drifted testid anchors — but this flow declares no success consequence, so the rebind resolves a locator without proving the intent still holds. Add a success-state assertion (reticle_annotate) so future heals can be verified.";
16
- readonly CONSEQUENCE_BROKEN: "rebind resolves the drifted locator to a surviving element, but the healed flow no longer satisfies its success consequence — refusing to write (a heal that loses the intent would ship a green-but-dead test). Fix by hand and verify";
17
- };
18
10
  export declare function healFlow(deps: ToolDeps, args: Record<string, unknown>): Promise<FlowHealResult>;
@@ -12,7 +12,7 @@ import { replayFlow } from './flow-replay.js';
12
12
  import { applyHealChanges, collectProposals } from './heal.js';
13
13
  import { assertSuccess, dynamicTestids, successLabel } from './flow-success.js';
14
14
  import { flowErrorMessage, sessionProjectId } from './flow-replay-run.js';
15
- export const HEAL_MESSAGES = {
15
+ const HEAL_MESSAGES = {
16
16
  NOTHING: 'nothing to heal — every anchor resolved on replay',
17
17
  HEALED: "rewrote drifted testid anchors to their nearest surviving match and re-verified the flow's success consequence still fires",
18
18
  DRIFT_DRY: 'confident rebind(s) proposed — re-run with apply:true to write them to disk',
@@ -25,7 +25,7 @@ function toChange(proposal) {
25
25
  }
26
26
  export async function healFlow(deps, args) {
27
27
  const name = asString(args['flowName']) ?? '';
28
- const apply = args['apply'] === true;
28
+ const apply = true === args['apply'];
29
29
  const projectId = sessionProjectId(deps, asString(args['sessionId']));
30
30
  const loaded = await deps.flows.load(name, projectId);
31
31
  if (!loaded.ok) {
@@ -40,7 +40,7 @@ export async function healFlow(deps, args) {
40
40
  };
41
41
  }
42
42
  const session = deps.sessions.resolve(asString(args['sessionId']));
43
- const steps = await replayFlow(session, loaded.value, waitForPredicate, FLOW_SIGNAL_TIMEOUT_MS, args['confirmDangerous'] === true);
43
+ const steps = await replayFlow(session, loaded.value, waitForPredicate, FLOW_SIGNAL_TIMEOUT_MS, true === args['confirmDangerous']);
44
44
  const drifted = steps.some((s) => s.drift !== undefined);
45
45
  const failed = steps.find((s) => !s.ok && s.drift === undefined);
46
46
  if (failed !== undefined) {
@@ -66,7 +66,7 @@ export async function healFlow(deps, args) {
66
66
  };
67
67
  }
68
68
  const proposals = collectProposals(steps);
69
- if (proposals.length === 0) {
69
+ if (0 === proposals.length) {
70
70
  return {
71
71
  name,
72
72
  status: HealStatus.UNHEALABLE,
@@ -97,7 +97,7 @@ export async function healFlow(deps, args) {
97
97
  // Floor the success oracle at the start of the VERIFY replay so the earlier drift replay's signal
98
98
  // cannot fake the verification.
99
99
  const verifyFloor = session.elapsed();
100
- const verifySteps = await replayFlow(session, toVerify, waitForPredicate, FLOW_SIGNAL_TIMEOUT_MS, args['confirmDangerous'] === true);
100
+ const verifySteps = await replayFlow(session, toVerify, waitForPredicate, FLOW_SIGNAL_TIMEOUT_MS, true === args['confirmDangerous']);
101
101
  const verifyClean = verifySteps.length > 0 && verifySteps.every((s) => s.ok && s.drift === undefined);
102
102
  const verdict = verifyClean
103
103
  ? await assertSuccess(session, healed.success, dynamicTestids(healed), waitForPredicate, FLOW_SIGNAL_TIMEOUT_MS, verifyFloor)
@@ -23,7 +23,7 @@ export function confidenceFor(from, to) {
23
23
  if (from === to)
24
24
  return 1;
25
25
  const span = Math.max(from.length, to.length);
26
- if (span === 0)
26
+ if (0 === span)
27
27
  return 1;
28
28
  const raw = 1 - editDistance(from, to) / span;
29
29
  if (raw >= 1)
@@ -62,10 +62,10 @@ function proposeRebindWith(drift, step, minConfidence) {
62
62
  // Never auto-heal an ambiguous drift: when two present testids tie at the minimum distance, the
63
63
  // `nearest` pick is arbitrary, so a rebind would be a coin-flip that can land on the wrong element
64
64
  // and ship a bug green. Surface it (the drift still carries `nearest`) and defer to a human.
65
- if (drift.ambiguous === true)
65
+ if (true === drift.ambiguous)
66
66
  return undefined;
67
67
  const to = drift.nearest;
68
- if (to === null)
68
+ if (null === to)
69
69
  return undefined;
70
70
  const confidence = confidenceFor(drift.anchor, to);
71
71
  if (confidence < minConfidence)
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The assertion the agent MADE, in the shape a saved flow can keep.
3
+ *
4
+ * `reticle_act_and_wait { until }` is how agents assert — 12 of 14 calls in a day of telemetry
5
+ * carried an `until`. `compileActStep` recorded only the ACTION, so a flow saved after an asserted
6
+ * drive came back graded `assertion-free`: "performs actions but asserts no observable consequence —
7
+ * it will pass even if the feature is broken." The agent had already said what success meant;
8
+ * Reticle discarded it and then warned the agent that the flow asserts nothing.
9
+ *
10
+ * That is the regression-suite story failing at its last step. "Record once, verify forever" is only
11
+ * worth anything if the recorded flow can go RED, and locally 32 of 39 saved flows cannot.
12
+ *
13
+ * The inverse of `successToPredicate`. Only the kinds FlowExpect can express are carried: `settled`
14
+ * is a wait rather than a claim, and `route`/`animation`/`anyOf`/`not` have no representation at all.
15
+ * Inventing one would write an assertion into the file that the agent never made, which is worse
16
+ * than recording none — a flow that asserts something nobody chose is a false green with extra steps.
17
+ */
18
+ import type { FlowExpect } from '@reticlehq/core';
19
+ import type { Predicate } from '../events/predicate.js';
20
+ export declare function predicateToExpect(predicate: Predicate): FlowExpect | undefined;
21
+ /**
22
+ * The subset a REPLAY actually enforces today.
23
+ *
24
+ * `flow-replay` checks exactly two things per step: `expect.element.testid` is present after the
25
+ * action, and `expect.state` holds. A recorded `net` or `signal` expect is graded as a consequence
26
+ * assertion by `classifyFlowAssertions` and then never evaluated — so writing one into a flow file
27
+ * would make it report `grade: "asserted"` while nothing checks it.
28
+ *
29
+ * That is a false green, in the feature whose entire purpose is preventing them, produced by the
30
+ * change that was meant to strengthen it. So only the enforced kinds are recorded: a flow that says
31
+ * it asserts something must actually go red when that thing breaks.
32
+ *
33
+ * Lifting this is worth doing — net and signal are the assertions agents most often make, and the
34
+ * conversion above already handles them — but it requires replay to evaluate them per step (the
35
+ * machinery exists: successToPredicate + the predicate engine). Until then, recording them would
36
+ * trade a weak flow for a lying one.
37
+ */
38
+ export declare function enforcedOnReplay(expect: FlowExpect | undefined): FlowExpect | undefined;
@@ -0,0 +1,95 @@
1
+ import { PredicateKind } from '@reticlehq/core';
2
+ /** Merge two partial expectations; later keys win only where the earlier one said nothing. */
3
+ function merge(into, from) {
4
+ return { ...from, ...into };
5
+ }
6
+ export function predicateToExpect(predicate) {
7
+ switch (predicate.kind) {
8
+ case PredicateKind.SIGNAL: {
9
+ if (predicate.name === undefined)
10
+ return undefined;
11
+ return predicate.dataMatches === undefined
12
+ ? { signal: predicate.name }
13
+ : { signal: predicate.name, signalData: predicate.dataMatches };
14
+ }
15
+ case PredicateKind.NET: {
16
+ const net = {};
17
+ if (predicate.method !== undefined)
18
+ net.method = predicate.method;
19
+ if (predicate.urlContains !== undefined)
20
+ net.urlContains = predicate.urlContains;
21
+ if (predicate.status !== undefined)
22
+ net.status = predicate.status;
23
+ if (predicate.count !== undefined)
24
+ net.count = predicate.count;
25
+ return 0 === Object.keys(net).length ? undefined : { net };
26
+ }
27
+ case PredicateKind.CONSOLE: {
28
+ const console_ = {};
29
+ if (predicate.level !== undefined)
30
+ console_.level = predicate.level;
31
+ if (predicate.absent !== undefined)
32
+ console_.absent = predicate.absent;
33
+ return 0 === Object.keys(console_).length ? undefined : { console: console_ };
34
+ }
35
+ case PredicateKind.ELEMENT: {
36
+ const element = {};
37
+ if (predicate.query.testid !== undefined)
38
+ element.testid = predicate.query.testid;
39
+ if (predicate.query.role !== undefined)
40
+ element.role = predicate.query.role;
41
+ if (predicate.query.name !== undefined)
42
+ element.name = predicate.query.name;
43
+ return 0 === Object.keys(element).length ? undefined : { element };
44
+ }
45
+ case PredicateKind.STATE: {
46
+ const state = { path: predicate.path };
47
+ if (predicate.store !== undefined)
48
+ state.store = predicate.store;
49
+ if (predicate.equals !== undefined)
50
+ state.equals = predicate.equals;
51
+ return { state };
52
+ }
53
+ case PredicateKind.ALL_OF: {
54
+ // `settled` members drop out on their own by returning undefined.
55
+ let combined;
56
+ for (const part of predicate.predicates) {
57
+ const expect = predicateToExpect(part);
58
+ if (expect === undefined)
59
+ continue;
60
+ combined = combined === undefined ? expect : merge(combined, expect);
61
+ }
62
+ return combined;
63
+ }
64
+ default:
65
+ // settled | route | animation | anyOf | not — nothing FlowExpect can say honestly.
66
+ return undefined;
67
+ }
68
+ }
69
+ /**
70
+ * The subset a REPLAY actually enforces today.
71
+ *
72
+ * `flow-replay` checks exactly two things per step: `expect.element.testid` is present after the
73
+ * action, and `expect.state` holds. A recorded `net` or `signal` expect is graded as a consequence
74
+ * assertion by `classifyFlowAssertions` and then never evaluated — so writing one into a flow file
75
+ * would make it report `grade: "asserted"` while nothing checks it.
76
+ *
77
+ * That is a false green, in the feature whose entire purpose is preventing them, produced by the
78
+ * change that was meant to strengthen it. So only the enforced kinds are recorded: a flow that says
79
+ * it asserts something must actually go red when that thing breaks.
80
+ *
81
+ * Lifting this is worth doing — net and signal are the assertions agents most often make, and the
82
+ * conversion above already handles them — but it requires replay to evaluate them per step (the
83
+ * machinery exists: successToPredicate + the predicate engine). Until then, recording them would
84
+ * trade a weak flow for a lying one.
85
+ */
86
+ export function enforcedOnReplay(expect) {
87
+ if (expect === undefined)
88
+ return undefined;
89
+ const kept = {};
90
+ if (expect.element?.testid !== undefined)
91
+ kept.element = expect.element;
92
+ if (expect.state !== undefined)
93
+ kept.state = expect.state;
94
+ return 0 === Object.keys(kept).length ? undefined : kept;
95
+ }
@@ -15,6 +15,17 @@ export declare function ambiguousTestidNote(value: string): string;
15
15
  export declare function queryRefs(result: CommandResult): string[];
16
16
  /** A destructive-action confirmation is one-shot and must never persist into a recording. */
17
17
  export declare function replayActionArgs(value: unknown, confirmDangerous?: boolean): Record<string, unknown>;
18
+ /**
19
+ * Capture an act into every in-flight recording, or do nothing when none is running.
20
+ *
21
+ * Every tool that drives the page must call this. reticle_act_and_wait did not, which is the tool
22
+ * the documented agent recipe drives with — so "record start -> drive -> record stop -> flow_save"
23
+ * saved a flow with zero steps.
24
+ */
25
+ export declare function captureAct(recordings: {
26
+ active: () => string[];
27
+ capture: (step: RecordedStep) => void;
28
+ }, args: Record<string, unknown>, res: unknown): void;
18
29
  /**
19
30
  * Compile a single reticle_act invocation into a normalized RecordedStep using the action result. Anchor
20
31
  * priority mirrors synthesizeAnchor: a data-testid is the gold standard; failing that, the element's
@@ -22,7 +33,11 @@ export declare function replayActionArgs(value: unknown, confirmDangerous?: bool
22
33
  * a volatile ref. Only when neither is available is the step ref-bound (in-session only).
23
34
  */
24
35
  export declare function compileActStep(args: Record<string, unknown>, res: unknown): RecordedStep;
25
- /** Compile an reticle_act_sequence invocation, normalizing each sub-step to its testid where resolvable. */
36
+ /**
37
+ * Compile an reticle_act_sequence invocation, normalizing each sub-step through the SAME anchor
38
+ * priority a single act uses (see compileAnchorArgs) — not testid-or-nothing, which is what made
39
+ * every sequence unreplayable on an app without testids.
40
+ */
26
41
  export declare function compileSequenceStep(args: Record<string, unknown>, res: unknown): RecordedStep;
27
42
  interface ReplayStepResult {
28
43
  tool: string;