@reticlehq/server 2.12.0 → 2.13.1

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 (386) hide show
  1. package/SKILL.md +67 -109
  2. package/dist/bridge/auth-failure-reason.d.ts +6 -2
  3. package/dist/bridge/auth-failure-reason.js +15 -8
  4. package/dist/bridge/bridge.d.ts +18 -1
  5. package/dist/bridge/bridge.js +247 -164
  6. package/dist/bridge/pairing-token.d.ts +5 -0
  7. package/dist/bridge/pairing-token.js +28 -0
  8. package/dist/bridge/protocol-skew.d.ts +37 -0
  9. package/dist/bridge/protocol-skew.js +45 -0
  10. package/dist/capsule/capsule-store.d.ts +6 -6
  11. package/dist/capsule/causal-summary.js +7 -2
  12. package/dist/cli/cli-doctor.js +31 -1
  13. package/dist/cli/cli-launch.d.ts +11 -1
  14. package/dist/cli/cli-launch.js +59 -10
  15. package/dist/cli/cli-parse.d.ts +15 -1
  16. package/dist/cli/cli-parse.js +212 -8
  17. package/dist/cli/cli-verify.d.ts +1 -0
  18. package/dist/cli/cli-verify.js +3 -2
  19. package/dist/cli/cloud-cli.js +428 -259
  20. package/dist/cli/cloud-keystore.d.ts +37 -0
  21. package/dist/cli/cloud-keystore.js +97 -0
  22. package/dist/cli/cloud-kit.d.ts +37 -0
  23. package/dist/cli/cloud-kit.js +121 -0
  24. package/dist/cli/cloud-login.d.ts +17 -0
  25. package/dist/cli/cloud-login.js +183 -0
  26. package/dist/cli/cloud-session.d.ts +48 -0
  27. package/dist/cli/cloud-session.js +53 -0
  28. package/dist/cli/config-discovery.js +1 -0
  29. package/dist/cli/daemon-start-options.d.ts +32 -0
  30. package/dist/cli/daemon-start-options.js +38 -0
  31. package/dist/cli/device-flow.d.ts +76 -0
  32. package/dist/cli/device-flow.js +56 -0
  33. package/dist/cli/doctor-rows.d.ts +9 -0
  34. package/dist/cli/doctor-rows.js +9 -0
  35. package/dist/cli/drive-attach.d.ts +13 -0
  36. package/dist/cli/drive-attach.js +18 -0
  37. package/dist/cli/drive-command.js +7 -3
  38. package/dist/cli/mcp-command.js +51 -20
  39. package/dist/cli/project-name.d.ts +30 -0
  40. package/dist/cli/project-name.js +44 -0
  41. package/dist/cli/status-next-action.d.ts +14 -0
  42. package/dist/cli/status-next-action.js +4 -4
  43. package/dist/cli.d.ts +1 -0
  44. package/dist/cli.js +134 -80
  45. package/dist/cloud/cloud-config.d.ts +22 -1
  46. package/dist/cloud/cloud-config.js +64 -5
  47. package/dist/cloud/cloud-sync.d.ts +5 -5
  48. package/dist/cloud/cloud-sync.js +33 -2
  49. package/dist/cloud/sync-cycle.d.ts +110 -0
  50. package/dist/cloud/sync-cycle.js +270 -0
  51. package/dist/cloud/sync-daemon.d.ts +69 -0
  52. package/dist/cloud/sync-daemon.js +260 -0
  53. package/dist/cloud/sync-disk.d.ts +9 -0
  54. package/dist/cloud/sync-disk.js +191 -0
  55. package/dist/cloud/sync-hash.d.ts +2 -0
  56. package/dist/cloud/sync-hash.js +35 -0
  57. package/dist/crawl/crawl-tools.js +5 -3
  58. package/dist/crawl/crawl.d.ts +3 -0
  59. package/dist/crawl/crawl.js +5 -0
  60. package/dist/daemon/daemon-resolve.d.ts +43 -0
  61. package/dist/daemon/daemon-resolve.js +69 -0
  62. package/dist/daemon/dev-servers.d.ts +15 -0
  63. package/dist/daemon/dev-servers.js +68 -0
  64. package/dist/daemon/wake-decision.d.ts +32 -0
  65. package/dist/daemon/wake-decision.js +38 -0
  66. package/dist/domain/domain-tools.js +2 -2
  67. package/dist/events/contradictions.d.ts +18 -0
  68. package/dist/events/contradictions.js +134 -21
  69. package/dist/events/declared.d.ts +7 -4
  70. package/dist/events/declared.js +15 -6
  71. package/dist/events/echo-mismatch.js +64 -14
  72. package/dist/events/event-filters.d.ts +8 -0
  73. package/dist/events/event-filters.js +19 -2
  74. package/dist/events/predicate-eval.js +53 -5
  75. package/dist/events/predicate-precheck.d.ts +8 -0
  76. package/dist/events/predicate-precheck.js +41 -0
  77. package/dist/events/predicate-route.d.ts +14 -0
  78. package/dist/events/predicate-route.js +36 -8
  79. package/dist/events/predicate.d.ts +5 -0
  80. package/dist/events/predicate.js +37 -5
  81. package/dist/events/split-text-miss.d.ts +30 -0
  82. package/dist/events/split-text-miss.js +44 -0
  83. package/dist/flows/flake.d.ts +6 -6
  84. package/dist/flows/flow-memory-consult.d.ts +55 -0
  85. package/dist/flows/flow-memory-consult.js +38 -0
  86. package/dist/flows/flow-replay-run.d.ts +18 -7
  87. package/dist/flows/flow-replay-run.js +239 -22
  88. package/dist/flows/flow-replay.js +11 -2
  89. package/dist/flows/flow-step-runners.d.ts +8 -0
  90. package/dist/flows/flow-step-runners.js +8 -2
  91. package/dist/flows/flow-store-for-session.d.ts +31 -0
  92. package/dist/flows/flow-store-for-session.js +33 -0
  93. package/dist/flows/flow-tools.js +58 -32
  94. package/dist/flows/flows.d.ts +8 -0
  95. package/dist/flows/flows.js +468 -2
  96. package/dist/flows/heal-run.js +5 -2
  97. package/dist/flows/predicate-to-expect.d.ts +17 -12
  98. package/dist/flows/predicate-to-expect.js +30 -12
  99. package/dist/flows/recordings.d.ts +13 -1
  100. package/dist/flows/recordings.js +17 -2
  101. package/dist/flows/replay.d.ts +22 -2
  102. package/dist/flows/replay.js +28 -2
  103. package/dist/flows/verify-change-tools.js +5 -2
  104. package/dist/honesty/blind-spots.d.ts +55 -2
  105. package/dist/honesty/blind-spots.js +63 -3
  106. package/dist/honesty/honesty.d.ts +24 -0
  107. package/dist/honesty/honesty.js +25 -1
  108. package/dist/honesty/instrumentation-gaps.d.ts +9 -0
  109. package/dist/honesty/instrumentation-gaps.js +29 -2
  110. package/dist/honesty/verified.d.ts +2 -1
  111. package/dist/honesty/verified.js +16 -1
  112. package/dist/http-server.js +12 -0
  113. package/dist/impact/impact-recorder.d.ts +31 -8
  114. package/dist/impact/impact-recorder.js +104 -21
  115. package/dist/impact/impact-store.d.ts +15 -1
  116. package/dist/impact/impact-store.js +43 -2
  117. package/dist/index.js +113 -7
  118. package/dist/init/agent-rules.d.ts +13 -6
  119. package/dist/init/agent-rules.js +23 -12
  120. package/dist/init/astro-patch.d.ts +16 -0
  121. package/dist/init/astro-patch.js +28 -0
  122. package/dist/init/capabilities.d.ts +4 -1
  123. package/dist/init/capabilities.js +22 -2
  124. package/dist/init/confirm.d.ts +31 -7
  125. package/dist/init/confirm.js +48 -8
  126. package/dist/init/cra.d.ts +20 -4
  127. package/dist/init/cra.js +57 -17
  128. package/dist/init/csp-check.js +17 -2
  129. package/dist/init/csp-doctor.d.ts +8 -1
  130. package/dist/init/csp-doctor.js +8 -3
  131. package/dist/init/dev-script.d.ts +3 -1
  132. package/dist/init/dev-script.js +8 -5
  133. package/dist/init/format-generated.d.ts +18 -0
  134. package/dist/init/format-generated.js +39 -0
  135. package/dist/init/install-hint.d.ts +9 -0
  136. package/dist/init/install-hint.js +29 -0
  137. package/dist/init/mcp-clients.d.ts +7 -0
  138. package/dist/init/mcp-clients.js +7 -0
  139. package/dist/init/mcp.d.ts +1 -1
  140. package/dist/init/mcp.js +1 -1
  141. package/dist/init/node-io.js +11 -1
  142. package/dist/init/plan-framework.js +81 -45
  143. package/dist/init/plan.d.ts +20 -7
  144. package/dist/init/plan.js +20 -45
  145. package/dist/init/preflight.d.ts +28 -0
  146. package/dist/init/preflight.js +38 -0
  147. package/dist/init/run.d.ts +32 -9
  148. package/dist/init/run.js +141 -119
  149. package/dist/init/slash-command.d.ts +1 -1
  150. package/dist/init/snippets.js +41 -25
  151. package/dist/init/vite-config.d.ts +1 -1
  152. package/dist/init/vite-config.js +39 -25
  153. package/dist/init/workspace-apps.d.ts +17 -10
  154. package/dist/init/workspace-apps.js +110 -0
  155. package/dist/input/network-mock-tools.js +3 -6
  156. package/dist/input/real-input.js +25 -5
  157. package/dist/input/scroll-tools.js +4 -6
  158. package/dist/input/viewport-tools.js +5 -4
  159. package/dist/intent/inline-intent.d.ts +10 -19
  160. package/dist/intent/inline-intent.js +91 -1
  161. package/dist/intent/intent-shard-store.d.ts +72 -0
  162. package/dist/intent/intent-shard-store.js +203 -0
  163. package/dist/intent/intent-shard.d.ts +411 -0
  164. package/dist/intent/intent-shard.js +176 -0
  165. package/dist/intent/intent-store.d.ts +12 -0
  166. package/dist/intent/intent-store.js +21 -0
  167. package/dist/intent/intent-subject.d.ts +45 -0
  168. package/dist/intent/intent-subject.js +177 -0
  169. package/dist/intent/intent-tools.js +65 -2
  170. package/dist/intent/open-intents.d.ts +21 -0
  171. package/dist/intent/open-intents.js +15 -0
  172. package/dist/license/license-env.d.ts +29 -0
  173. package/dist/license/license-env.js +148 -0
  174. package/dist/loopback-agent.d.ts +31 -0
  175. package/dist/loopback-agent.js +57 -0
  176. package/dist/mcp/attach-memory.d.ts +18 -2
  177. package/dist/mcp/attach-memory.js +50 -7
  178. package/dist/mcp/client-identity.d.ts +31 -0
  179. package/dist/mcp/client-identity.js +51 -0
  180. package/dist/mcp/mcp-post-transport.d.ts +26 -0
  181. package/dist/mcp/mcp-post-transport.js +109 -0
  182. package/dist/mcp/mcp-proxy.d.ts +2 -1
  183. package/dist/mcp/mcp-proxy.js +52 -62
  184. package/dist/mcp/mcp.js +7 -1
  185. package/dist/mcp/proxy-backoff.d.ts +11 -0
  186. package/dist/mcp/proxy-backoff.js +13 -0
  187. package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
  188. package/dist/mcp/proxy-daemon-probe.js +7 -1
  189. package/dist/mcp/proxy-handshake.d.ts +23 -0
  190. package/dist/mcp/proxy-handshake.js +31 -0
  191. package/dist/mcp/tool-catalog-cache.d.ts +8 -0
  192. package/dist/mcp/tool-catalog-cache.js +12 -0
  193. package/dist/memory/memory-tools.d.ts +2 -0
  194. package/dist/memory/memory-tools.js +82 -0
  195. package/dist/memory/project-memory.d.ts +34 -0
  196. package/dist/memory/project-memory.js +96 -0
  197. package/dist/oracles/propose-consequences.js +12 -3
  198. package/dist/pool/browser-pool.d.ts +63 -4
  199. package/dist/pool/browser-pool.js +113 -4
  200. package/dist/pool/playwright-launcher.js +9 -0
  201. package/dist/project/project-tools.js +3 -3
  202. package/dist/project/reticle-dir.d.ts +15 -2
  203. package/dist/project/reticle-dir.js +21 -4
  204. package/dist/runs/run-store.d.ts +10 -0
  205. package/dist/runs/run-store.js +10 -0
  206. package/dist/runs/verification-sync.d.ts +0 -11
  207. package/dist/runs/verification-sync.js +22 -1
  208. package/dist/runs/verify-server.d.ts +8 -1
  209. package/dist/runs/verify-server.js +14 -2
  210. package/dist/session/command-timeout.d.ts +5 -2
  211. package/dist/session/command-timeout.js +5 -4
  212. package/dist/session/lease-visibility.d.ts +67 -0
  213. package/dist/session/lease-visibility.js +76 -0
  214. package/dist/session/no-session-diagnosis.d.ts +23 -0
  215. package/dist/session/no-session-diagnosis.js +58 -17
  216. package/dist/session/no-session-next-action.d.ts +7 -0
  217. package/dist/session/no-session-next-action.js +42 -3
  218. package/dist/session/no-session-watch.d.ts +10 -6
  219. package/dist/session/no-session-watch.js +51 -19
  220. package/dist/session/pending-commands.d.ts +11 -1
  221. package/dist/session/pending-commands.js +12 -2
  222. package/dist/session/resolve-within.d.ts +34 -0
  223. package/dist/session/resolve-within.js +53 -0
  224. package/dist/session/session-info.d.ts +18 -0
  225. package/dist/session/session-info.js +11 -0
  226. package/dist/session/session-manager.d.ts +14 -0
  227. package/dist/session/session-manager.js +61 -3
  228. package/dist/session/session-mirror.d.ts +16 -0
  229. package/dist/session/session-mirror.js +22 -0
  230. package/dist/session/session-recommendation.d.ts +19 -5
  231. package/dist/session/session-recommendation.js +25 -9
  232. package/dist/session/session-successor.js +36 -1
  233. package/dist/session/session-tools.js +2 -2
  234. package/dist/session/session.d.ts +22 -2
  235. package/dist/session/session.js +87 -7
  236. package/dist/session/wall-clock.d.ts +12 -0
  237. package/dist/session/wall-clock.js +14 -0
  238. package/dist/setup/agent-configs.d.ts +96 -0
  239. package/dist/setup/agent-configs.js +333 -0
  240. package/dist/setup/agent-io.d.ts +9 -0
  241. package/dist/setup/agent-io.js +16 -0
  242. package/dist/setup/agent-writer.d.ts +51 -0
  243. package/dist/setup/agent-writer.js +115 -0
  244. package/dist/setup/approval-migration.d.ts +47 -0
  245. package/dist/setup/approval-migration.js +68 -0
  246. package/dist/setup/auto-approve.d.ts +85 -0
  247. package/dist/setup/auto-approve.js +150 -0
  248. package/dist/setup/bridge-port.d.ts +15 -0
  249. package/dist/setup/bridge-port.js +24 -0
  250. package/dist/setup/desktop-shape.d.ts +57 -0
  251. package/dist/setup/desktop-shape.js +63 -0
  252. package/dist/setup/dev-server-wait.d.ts +68 -0
  253. package/dist/setup/dev-server-wait.js +67 -0
  254. package/dist/setup/drive-agent.d.ts +71 -0
  255. package/dist/setup/drive-agent.js +171 -0
  256. package/dist/setup/drive-plan.d.ts +68 -0
  257. package/dist/setup/drive-plan.js +130 -0
  258. package/dist/setup/ensure-daemon.d.ts +29 -0
  259. package/dist/setup/ensure-daemon.js +58 -0
  260. package/dist/setup/init-runtime.d.ts +47 -0
  261. package/dist/setup/init-runtime.js +160 -0
  262. package/dist/setup/interrupt.d.ts +25 -0
  263. package/dist/setup/interrupt.js +40 -0
  264. package/dist/setup/license-key.d.ts +39 -0
  265. package/dist/setup/license-key.js +72 -0
  266. package/dist/setup/listeners.d.ts +37 -0
  267. package/dist/setup/listeners.js +85 -0
  268. package/dist/setup/node-effects.d.ts +60 -0
  269. package/dist/setup/node-effects.js +210 -0
  270. package/dist/setup/page-probe.d.ts +39 -0
  271. package/dist/setup/page-probe.js +49 -0
  272. package/dist/setup/relaunch.d.ts +36 -0
  273. package/dist/setup/relaunch.js +57 -0
  274. package/dist/setup/remaining-steps.d.ts +19 -0
  275. package/dist/setup/remaining-steps.js +31 -0
  276. package/dist/setup/run-setup.d.ts +99 -0
  277. package/dist/setup/run-setup.js +203 -0
  278. package/dist/setup/session-pick.d.ts +47 -0
  279. package/dist/setup/session-pick.js +51 -0
  280. package/dist/setup/setup-command.d.ts +45 -0
  281. package/dist/setup/setup-command.js +199 -0
  282. package/dist/setup/setup-options.d.ts +74 -0
  283. package/dist/setup/setup-options.js +67 -0
  284. package/dist/setup/transcripts.d.ts +16 -0
  285. package/dist/setup/transcripts.js +43 -0
  286. package/dist/status-payload.d.ts +14 -1
  287. package/dist/status-payload.js +23 -1
  288. package/dist/telemetry/daemon-telemetry.d.ts +8 -1
  289. package/dist/telemetry/daemon-telemetry.js +52 -5
  290. package/dist/telemetry/error-class.js +1 -1
  291. package/dist/telemetry/feedback-context.d.ts +9 -1
  292. package/dist/telemetry/feedback-context.js +60 -29
  293. package/dist/telemetry/feedback-local.d.ts +15 -0
  294. package/dist/telemetry/feedback-local.js +56 -0
  295. package/dist/telemetry/feedback.d.ts +11 -0
  296. package/dist/telemetry/feedback.js +19 -6
  297. package/dist/telemetry/init-telemetry.d.ts +2 -0
  298. package/dist/telemetry/init-telemetry.js +2 -0
  299. package/dist/telemetry/install-source.d.ts +14 -0
  300. package/dist/telemetry/install-source.js +30 -0
  301. package/dist/telemetry/license-activation.d.ts +7 -1
  302. package/dist/telemetry/license-activation.js +9 -5
  303. package/dist/telemetry/mcp-connection.js +7 -0
  304. package/dist/telemetry/project-profile.d.ts +12 -1
  305. package/dist/telemetry/project-profile.js +11 -6
  306. package/dist/telemetry/proxy-telemetry.d.ts +3 -0
  307. package/dist/telemetry/proxy-telemetry.js +21 -0
  308. package/dist/telemetry/session-metrics.d.ts +12 -0
  309. package/dist/telemetry/session-metrics.js +35 -1
  310. package/dist/telemetry/telemetry.js +17 -2
  311. package/dist/telemetry/tool-refused.d.ts +3 -1
  312. package/dist/telemetry/tool-refused.js +34 -2
  313. package/dist/tools/act-capsule.d.ts +10 -0
  314. package/dist/tools/act-capsule.js +8 -2
  315. package/dist/tools/act-danger.d.ts +2 -1
  316. package/dist/tools/act-danger.js +11 -3
  317. package/dist/tools/act-observation.d.ts +41 -0
  318. package/dist/tools/act-observation.js +36 -0
  319. package/dist/tools/act-preflight.d.ts +20 -0
  320. package/dist/tools/act-preflight.js +98 -0
  321. package/dist/tools/act-sequence-retry.d.ts +45 -0
  322. package/dist/tools/act-sequence-retry.js +58 -0
  323. package/dist/tools/act-sequence-tool.d.ts +13 -0
  324. package/dist/tools/act-sequence-tool.js +135 -0
  325. package/dist/tools/act-target.d.ts +14 -0
  326. package/dist/tools/act-target.js +47 -0
  327. package/dist/tools/act-tools.d.ts +21 -1
  328. package/dist/tools/act-tools.js +100 -213
  329. package/dist/tools/assert-verdict.js +22 -16
  330. package/dist/tools/browser-tools.js +6 -2
  331. package/dist/tools/dynamic-tools.js +24 -5
  332. package/dist/tools/error-recovery.d.ts +1 -0
  333. package/dist/tools/error-recovery.js +8 -0
  334. package/dist/tools/invoke-tool.js +59 -9
  335. package/dist/tools/lease-tools.d.ts +30 -4
  336. package/dist/tools/lease-tools.js +169 -5
  337. package/dist/tools/merged-name-redirect.d.ts +13 -0
  338. package/dist/tools/merged-name-redirect.js +22 -0
  339. package/dist/tools/numeric-bounds.d.ts +100 -0
  340. package/dist/tools/numeric-bounds.js +125 -0
  341. package/dist/tools/observe-tools.js +47 -40
  342. package/dist/tools/read-tools.js +28 -7
  343. package/dist/tools/real-input-attempt.d.ts +10 -0
  344. package/dist/tools/real-input-attempt.js +59 -1
  345. package/dist/tools/reconcile-tools.js +4 -4
  346. package/dist/tools/tool-kit.d.ts +12 -0
  347. package/dist/tools/tool-kit.js +6 -1
  348. package/dist/tools/tool-names.d.ts +2 -0
  349. package/dist/tools/tool-names.js +2 -0
  350. package/dist/tools/tools-helpers.d.ts +19 -0
  351. package/dist/tools/tools-helpers.js +46 -0
  352. package/dist/tools/tools.d.ts +2 -0
  353. package/dist/tools/tools.js +56 -8
  354. package/dist/update/reticle-deps.d.ts +9 -0
  355. package/dist/update/reticle-deps.js +27 -0
  356. package/dist/update/sdk-sync.d.ts +1 -2
  357. package/dist/update/sdk-sync.js +1 -21
  358. package/dist/update/update-nudge.d.ts +18 -0
  359. package/dist/update/update-nudge.js +20 -0
  360. package/dist/version/peer-announce.js +4 -2
  361. package/dist/version/sdk-fix.d.ts +47 -0
  362. package/dist/version/sdk-fix.js +127 -0
  363. package/dist/version/version-nudge.d.ts +14 -0
  364. package/dist/version/version-nudge.js +21 -0
  365. package/dist/version/version-skew.d.ts +38 -3
  366. package/dist/version/version-skew.js +83 -7
  367. package/dist/visual/visual-store.d.ts +6 -6
  368. package/dist/visual/visual-store.js +18 -16
  369. package/dist/visual/visual-tools.js +57 -12
  370. package/docs/cli/doctor.mdx +1 -0
  371. package/docs/cli/serve.mdx +4 -2
  372. package/docs/cli.mdx +7 -3
  373. package/docs/desktop.mdx +1 -1
  374. package/docs/docs.json +1 -1
  375. package/docs/getting-started.md +19 -3
  376. package/docs/index.mdx +9 -6
  377. package/docs/install-agentic.mdx +38 -12
  378. package/docs/install-manual.mdx +1 -1
  379. package/docs/packages.mdx +1 -1
  380. package/docs/skill-file.mdx +3 -3
  381. package/docs/telemetry-contract.md +108 -4
  382. package/docs/tools-act-sequence.mdx +16 -0
  383. package/docs/usage.md +1 -1
  384. package/package.json +4 -3
  385. package/dist/init/cursor.d.ts +0 -24
  386. package/dist/init/cursor.js +0 -80
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Everything refused BEFORE the action window opens.
3
+ *
4
+ * Both checks here share one property, and it is the reason they belong together: each is decidable
5
+ * without touching the page, and each would otherwise be discovered only after the click had landed
6
+ * — when the action is spent, the page has moved, and the honest answer has already been lost.
7
+ *
8
+ * Refusing early is not a convenience. `reticle_act_and_wait` promises a verdict, and a verdict that
9
+ * blames the app for the caller's own mistake is the most damaging thing a verification tool can
10
+ * produce: it sends somebody to fix code that is not broken. "Nothing was acted on" is a far better
11
+ * outcome than "unknown".
12
+ */
13
+ import { SessionReplacedError } from '../session/pending-commands.js';
14
+ import { assertNativeInputSupported } from './act-danger.js';
15
+ import { unevaluablePredicateReason } from '../events/predicate-precheck.js';
16
+ /**
17
+ * Refuse a sequence whose steps cannot be addressed.
18
+ *
19
+ * `steps` is a bare array of objects, so a step with neither `ref` nor `target` used to travel on
20
+ * and dispatch as `ref: ''`. The browser then threw `ref '' no longer resolves to an element` —
21
+ * a stale-ref diagnosis for a missing locator — and the caller went looking for a re-render.
22
+ *
23
+ * `target` is the same locator `reticle_act` / `reticle_act_and_wait` take; the handler resolves it
24
+ * with `resolveActTarget` before dispatch. This check only asks that every step names one of the
25
+ * two, and it runs before the first step, so a typo in step three cannot leave one and two applied.
26
+ */
27
+ /**
28
+ * Keys an agent reaches for when it means "and prove this happened".
29
+ *
30
+ * A sub-step reads `ref`/`target`/`action`/`args` and nothing else, and the schema is a permissive
31
+ * record, so any of these was accepted and dropped. `until` is the likeliest of them by a distance:
32
+ * it is what act_and_wait — the tool immediately next to this one — calls its assertion.
33
+ *
34
+ * Silently ignoring one manufactures a false green. A sequence carrying an impossible `until` came
35
+ * back `completed: 1` with no error and nothing said about the predicate, which reads as the
36
+ * consequence having held. act_sequence cannot grade one; refusing and naming the tool that can is
37
+ * the same answer given to an unsupported native click, and for the same reason.
38
+ */
39
+ const CONSEQUENCE_KEYS = ['until', 'expect', 'assert', 'waitFor'];
40
+ export function assertSequenceSteps(steps) {
41
+ if (0 === steps.length) {
42
+ throw new Error('reticle_act_sequence was given no steps. Pass steps: [{ ref, action, args? }] or [{ target, action, args? }] — nothing was acted on.');
43
+ }
44
+ steps.forEach((raw, i) => {
45
+ const step = 'object' === typeof raw && null !== raw ? raw : {};
46
+ const claimed = CONSEQUENCE_KEYS.find((k) => step[k] !== undefined);
47
+ if (claimed !== undefined) {
48
+ throw new Error(`step ${String(i)} carries \`${claimed}\`, and reticle_act_sequence cannot grade it. ` +
49
+ 'Sub-steps are dispatched, never asserted — the key would be dropped and the sequence ' +
50
+ 'would report success having checked nothing. Drive the steps here, then prove the ' +
51
+ 'consequence with reticle_act_and_wait on the LAST action (its `until` is graded), or ' +
52
+ 'with reticle_assert after this call. Nothing was acted on.');
53
+ }
54
+ if ('string' === typeof step['ref'] && step['ref'].length > 0)
55
+ return;
56
+ if (step['target'] !== undefined)
57
+ return;
58
+ throw new Error(`step ${String(i)} has no \`ref\` or \`target\`. ` +
59
+ 'Sequence steps take `ref` (from reticle_query/reticle_snapshot) or `target` ' +
60
+ '(e.g. { testid } or { label }), the same locator reticle_act accepts. ' +
61
+ 'Nothing was acted on — the whole sequence is refused so a bad step cannot leave the earlier ones half-applied.');
62
+ });
63
+ }
64
+ /**
65
+ * Throws if this call cannot honestly be driven. Call it after the args are parsed and before the
66
+ * first dispatch — anything that depends on what is actually rendered belongs after the action.
67
+ */
68
+ export function preflightAct(actArgs, until) {
69
+ // This path cannot honour a native-input request, and taking the argument and ignoring it told
70
+ // the agent its trusted click had happened. See act-danger.
71
+ assertNativeInputSupported(actArgs);
72
+ const unevaluable = unevaluablePredicateReason(until);
73
+ if (unevaluable !== undefined)
74
+ throw new Error(unevaluable);
75
+ }
76
+ /**
77
+ * Dispatch a write, or report that its outcome went unobserved.
78
+ *
79
+ * Returns null — never throws — when the transport was displaced by a newer connection claiming the
80
+ * same id. That happens on any full-document navigation the act itself causes: the page unloads,
81
+ * re-announces, and the write in flight is rejected by the handle that just died.
82
+ *
83
+ * The write is deliberately NOT re-sent. Re-asking a READ on the successor is free; re-sending a
84
+ * WRITE is not, because nothing can prove the first one did not reach the page — and a duplicated
85
+ * click on a button that charges a card is a far worse outcome than a verdict of "I could not see".
86
+ * Every other failure propagates unchanged: only a replacement is an observation problem, and
87
+ * treating a timeout or a refusal as one would launder a real failure into a shrug.
88
+ */
89
+ export async function dispatchAct(send) {
90
+ try {
91
+ return await send();
92
+ }
93
+ catch (error) {
94
+ if (error instanceof SessionReplacedError)
95
+ return null;
96
+ throw error;
97
+ }
98
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The two things a sequence step needs beyond a plain act: a retry when the ref goes stale under a
3
+ * re-render, and a result shaped for the per-step report.
4
+ *
5
+ * ── THE RETRY ─────────────────────────────────────────────────────────────────────────────────
6
+ *
7
+ * Refs are invalidated by a re-render, and `reticle_act_sequence` exists precisely because the
8
+ * caller cannot re-snapshot between steps. So `fill -> fill -> submit` fails on step two the moment
9
+ * step one causes React to re-render — and the SAME refs then work when the caller retries the whole
10
+ * sequence by hand, which is the tell: this is a race with the render, not a dead element. Losing
11
+ * the sequence to it makes the tool unusable for the exact shape it was built for.
12
+ *
13
+ * The fix is one retry, after the app has been given the grace period it already gets elsewhere, and
14
+ * ONLY for staleness. A genuinely gone element fails again immediately, and a step that failed for
15
+ * any other reason is never retried — a tool that quietly re-runs actions would turn one click into
16
+ * two, which is worse than the failure it was papering over.
17
+ */
18
+ import { waitForReaction } from './react-grace.js';
19
+ export declare const isStaleRefError: (error: string | undefined) => boolean;
20
+ /** The shape a step attempt returns. Structural so this file needs nothing from the tool layer. */
21
+ export interface StepOutcome {
22
+ ok: boolean;
23
+ error?: string | undefined;
24
+ result?: unknown;
25
+ }
26
+ /** Just enough of a session for the grace period. Same structural contract react-grace.ts uses. */
27
+ type ReactionSource = Parameters<typeof waitForReaction>[0];
28
+ /**
29
+ * Run one step, and retry it once if — and only if — its ref went stale under a re-render.
30
+ *
31
+ * `attempt` is called at most twice with identical arguments, so it must be the same idempotent
32
+ * dispatch the caller would have made itself.
33
+ */
34
+ export declare function runStepWithStaleRetry(attempt: () => Promise<StepOutcome>, session: ReactionSource, since: number, budgetMs: number, opts?: {
35
+ sleep(ms: number): Promise<void>;
36
+ }): Promise<StepOutcome>;
37
+ /**
38
+ * One step's entry in the per-step report.
39
+ *
40
+ * Only the fields the underlying act actually produced. Copying them conditionally keeps a clean step
41
+ * from carrying a row of nulls that read as "we looked and found nothing" rather than "there was
42
+ * nothing to look for".
43
+ */
44
+ export declare function describeStepResult(step: Record<string, unknown>, result: Record<string, unknown>): Record<string, unknown>;
45
+ export {};
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The two things a sequence step needs beyond a plain act: a retry when the ref goes stale under a
3
+ * re-render, and a result shaped for the per-step report.
4
+ *
5
+ * ── THE RETRY ─────────────────────────────────────────────────────────────────────────────────
6
+ *
7
+ * Refs are invalidated by a re-render, and `reticle_act_sequence` exists precisely because the
8
+ * caller cannot re-snapshot between steps. So `fill -> fill -> submit` fails on step two the moment
9
+ * step one causes React to re-render — and the SAME refs then work when the caller retries the whole
10
+ * sequence by hand, which is the tell: this is a race with the render, not a dead element. Losing
11
+ * the sequence to it makes the tool unusable for the exact shape it was built for.
12
+ *
13
+ * The fix is one retry, after the app has been given the grace period it already gets elsewhere, and
14
+ * ONLY for staleness. A genuinely gone element fails again immediately, and a step that failed for
15
+ * any other reason is never retried — a tool that quietly re-runs actions would turn one click into
16
+ * two, which is worse than the failure it was papering over.
17
+ */
18
+ import { waitForReaction } from './react-grace.js';
19
+ /** Matches the daemon's own wording, which error-recovery.ts also keys its STALE_REF hint off. */
20
+ const STALE_REF = /no longer resolves to an element/i;
21
+ export const isStaleRefError = (error) => error !== undefined && STALE_REF.test(error);
22
+ const realSleep = {
23
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
24
+ };
25
+ /**
26
+ * Run one step, and retry it once if — and only if — its ref went stale under a re-render.
27
+ *
28
+ * `attempt` is called at most twice with identical arguments, so it must be the same idempotent
29
+ * dispatch the caller would have made itself.
30
+ */
31
+ export async function runStepWithStaleRetry(attempt, session, since, budgetMs, opts = realSleep) {
32
+ const first = await attempt();
33
+ if (first.ok || !isStaleRefError(first.error))
34
+ return first;
35
+ await waitForReaction(session, since, budgetMs, opts);
36
+ return attempt();
37
+ }
38
+ /**
39
+ * One step's entry in the per-step report.
40
+ *
41
+ * Only the fields the underlying act actually produced. Copying them conditionally keeps a clean step
42
+ * from carrying a row of nulls that read as "we looked and found nothing" rather than "there was
43
+ * nothing to look for".
44
+ */
45
+ export function describeStepResult(step, result) {
46
+ const out = {
47
+ ref: result['ref'] ?? step['ref'],
48
+ action: result['action'] ?? step['action'],
49
+ dispatched: result['dispatched'] ?? true,
50
+ settled: result['settled'] ?? null,
51
+ settleReason: result['settleReason'] ?? null,
52
+ };
53
+ for (const key of ['testid', 'component', 'role', 'name', 'source', 'warning']) {
54
+ if (result[key] !== undefined)
55
+ out[key] = result[key];
56
+ }
57
+ return out;
58
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `reticle_act_sequence` — several actions compiled into one round trip.
3
+ *
4
+ * Split out of `act-tools.ts` when that file passed the 1000-line backstop. A tool seam rather than
5
+ * an arbitrary one: its two neighbours drive ONE action and grade its consequence, while this one
6
+ * compiles a list of steps and runs them inside a single action window, reporting per step.
7
+ *
8
+ * It keeps its own `beginAction` — the dispatch and the attribution window that must wrap it stay in
9
+ * the same file, which is the property `dispatch-attribution.test.ts` enforces. An earlier attempt
10
+ * split the shared `actCommand` helper out instead, which separated the two and that guard caught it.
11
+ */
12
+ import { type ToolDef } from './tool-kit.js';
13
+ export declare const ACT_SEQUENCE_TOOL: ToolDef;
@@ -0,0 +1,135 @@
1
+ /**
2
+ * `reticle_act_sequence` — several actions compiled into one round trip.
3
+ *
4
+ * Split out of `act-tools.ts` when that file passed the 1000-line backstop. A tool seam rather than
5
+ * an arbitrary one: its two neighbours drive ONE action and grade its consequence, while this one
6
+ * compiles a list of steps and runs them inside a single action window, reporting per step.
7
+ *
8
+ * It keeps its own `beginAction` — the dispatch and the attribution window that must wrap it stay in
9
+ * the same file, which is the property `dispatch-attribution.test.ts` enforces. An earlier attempt
10
+ * split the shared `actCommand` helper out instead, which separated the two and that guard caught it.
11
+ */
12
+ import { z } from 'zod';
13
+ import { timeoutMsSchema } from './numeric-bounds.js';
14
+ import { compileSequenceStep } from '../flows/replay.js';
15
+ import { ReticleTool } from './tool-names.js';
16
+ import { healthEnvelope } from '../session/session-health.js';
17
+ import { pausedShortCircuit, pausedOutputShape, withControl } from '../session/control-envelope.js';
18
+ import { asRecord, sessionIdFromArgs } from './tools-helpers.js';
19
+ import { describeStepResult, runStepWithStaleRetry } from './act-sequence-retry.js';
20
+ import { assertSequenceSteps } from './act-preflight.js';
21
+ import { sessionIdShape } from './tool-kit.js';
22
+ import { actCommand } from './act-tools.js';
23
+ // resolveActTarget moved out of act-tools into its own module on this branch; #706 was written
24
+ // against the older layout where act-tools re-exported it.
25
+ import { resolveActTarget } from './act-target.js';
26
+ export const ACT_SEQUENCE_TOOL = {
27
+ name: ReticleTool.ACT_SEQUENCE,
28
+ // The example is required for a core tool, and this one carries weight: the measured loop it
29
+ // replaces is literally a login form driven as three separate reticle_act calls (98 clicks and
30
+ // 21 fills inside looping sessions, 2026-08-10/11). Showing fill -> fill -> click is showing the
31
+ // exact shape an agent otherwise spends three round trips on.
32
+ example: {
33
+ steps: [
34
+ { ref: 'e12', action: 'fill', args: { value: 'a@b.com' } },
35
+ { ref: 'e13', action: 'fill', args: { value: 'hunter2' } },
36
+ { ref: 'e14', action: 'click' },
37
+ ],
38
+ },
39
+ description: 'Run multiple actions in order (fill -> fill -> submit) in ONE round-trip. Prefer this over repeating reticle_act for a multi-step journey, then assert its consequence once. Returns per-step effects[] (see reticle_act).',
40
+ inputSchema: {
41
+ steps: z
42
+ .array(z.record(z.unknown()))
43
+ .describe('Ordered list of { ref | target, action, args? } objects. Each step is equivalent to one reticle_act call — give `ref` from a snapshot/query, or `target` ({ testid } | { label } | { role, name } | { text }) to resolve in this call. Put confirmDangerous:true in a destructive step args object.'),
44
+ timeout_ms: timeoutMsSchema
45
+ .optional()
46
+ .describe('Per-step timeout in milliseconds. Default: 8000. Each step gets this budget independently.'),
47
+ ...sessionIdShape,
48
+ },
49
+ outputSchema: {
50
+ since: z.number(),
51
+ dispatched: z.boolean(),
52
+ completed: z.number(),
53
+ stalled_at: z.number().optional(),
54
+ steps: z.array(z.record(z.unknown())).optional(),
55
+ result: z.unknown().optional(),
56
+ session: z
57
+ .object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
58
+ .optional(),
59
+ // Short-circuits to pausedShortCircuit while paused — declare its fields (drained-once guidance).
60
+ ...pausedOutputShape,
61
+ },
62
+ handler: async (deps, args) => {
63
+ const session = deps.sessions.resolve(sessionIdFromArgs(args));
64
+ const paused = pausedShortCircuit(session);
65
+ if (paused !== undefined)
66
+ return paused;
67
+ const since = session.elapsed();
68
+ session.beginAction(ReticleTool.ACT_SEQUENCE, asRecord(args));
69
+ try {
70
+ const inputSteps = Array.isArray(args['steps']) ? args['steps'] : [];
71
+ assertSequenceSteps(inputSteps);
72
+ const perStepTimeout = 'number' === typeof args['timeout_ms'] ? args['timeout_ms'] : 8000;
73
+ const stepResults = [];
74
+ let stalledAt;
75
+ // DIVERGENCE: live sends N individual ACT commands (for per-step timeout + progress);
76
+ // replay sends one batched ACT_SEQUENCE command (flows/replay.ts:294). A bug in either is
77
+ // invisible from the other — cover both when changing sequence semantics.
78
+ for (let i = 0; i < inputSteps.length; i++) {
79
+ const step = asRecord(inputSteps[i]);
80
+ try {
81
+ // One retry when the ref went stale under a re-render — see act-sequence-retry.ts.
82
+ // Resolve `target` with the same helper reticle_act uses, then dispatch by ref. Passing
83
+ // the unresolved step through used to send `ref: undefined` and the browser blamed a
84
+ // stale empty ref — the caller went looking for a re-render instead of a missing locator.
85
+ const outcome = await runStepWithStaleRetry(async () => {
86
+ const resolved = await resolveActTarget(session, step);
87
+ if ('error' === resolved.kind)
88
+ return { ok: false, error: resolved.message };
89
+ return actCommand(deps, session, { ref: resolved.ref, action: step['action'], args: step['args'] ?? {} }, perStepTimeout);
90
+ }, session, since, perStepTimeout);
91
+ if (!outcome.ok) {
92
+ stalledAt = i;
93
+ stepResults.push({
94
+ ref: step['ref'],
95
+ action: step['action'],
96
+ dispatched: false,
97
+ error: outcome.error ?? 'step failed',
98
+ });
99
+ break;
100
+ }
101
+ stepResults.push(describeStepResult(step, asRecord(outcome.result)));
102
+ }
103
+ catch (err) {
104
+ stalledAt = i;
105
+ stepResults.push({
106
+ ref: step['ref'],
107
+ action: step['action'],
108
+ dispatched: null,
109
+ timedOut: true,
110
+ error: err instanceof Error ? err.message : 'step timed out',
111
+ });
112
+ break;
113
+ }
114
+ }
115
+ const completed = stalledAt ?? inputSteps.length;
116
+ if (completed > 0) {
117
+ session.lastAct.markActed(since, undefined, undefined);
118
+ }
119
+ if (deps.recordings.active().length > 0 && stalledAt === undefined) {
120
+ deps.recordings.capture(compileSequenceStep(args, { count: inputSteps.length, steps: stepResults }));
121
+ }
122
+ return withControl(session, {
123
+ since,
124
+ dispatched: completed > 0,
125
+ completed,
126
+ ...(stalledAt !== undefined ? { stalled_at: stalledAt } : {}),
127
+ steps: stepResults,
128
+ ...healthEnvelope(session),
129
+ });
130
+ }
131
+ finally {
132
+ session.finishAction();
133
+ }
134
+ },
135
+ };
@@ -0,0 +1,14 @@
1
+ import type { Session } from '../session/session.js';
2
+ import { type TargetResolution } from './resolve-target.js';
3
+ /**
4
+ * Resolve an action's element: an explicit `ref`, or a `target` query resolved in the SAME call.
5
+ *
6
+ * Requiring a ref meant every verification paid a `reticle_query` turn first just to learn one
7
+ * string, and the advertised tool surface is re-sent on every turn — measured on the wire, a
8
+ * two-turn verification spent 10,756 of 11,235 tokens on schema and 479 on the actual answers. The
9
+ * lookup still happens; it just stops costing a round trip through the model.
10
+ *
11
+ * `ref` wins when both are given, because it is the more specific instruction and silently
12
+ * preferring the query would act on something the caller did not name.
13
+ */
14
+ export declare function resolveActTarget(session: Session, args: Record<string, unknown>): Promise<TargetResolution>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Turn what the caller named into a ref: `ref` outright, or `target` via one page query.
3
+ *
4
+ * Split out of act-tools.ts when it crossed the 1000-line cap. Chosen deliberately over the ACT
5
+ * dispatcher, which looks like the more obvious seam and is not: `dispatch-attribution` asserts
6
+ * file-by-file that anything sending an ACT also opens an attribution window, so moving the
7
+ * dispatch out of the file that opens the window would have weakened a real invariant to satisfy a
8
+ * line count. This resolves a TARGET and dispatches only QUERY, so that guard is untouched.
9
+ */
10
+ import { ReticleCommand } from '@reticlehq/core';
11
+ import { normalizeQueryArgs } from './query-shape.js';
12
+ import { resolveTargetRef } from './resolve-target.js';
13
+ import { asRecord, asString } from './tools-helpers.js';
14
+ /**
15
+ * Resolve an action's element: an explicit `ref`, or a `target` query resolved in the SAME call.
16
+ *
17
+ * Requiring a ref meant every verification paid a `reticle_query` turn first just to learn one
18
+ * string, and the advertised tool surface is re-sent on every turn — measured on the wire, a
19
+ * two-turn verification spent 10,756 of 11,235 tokens on schema and 479 on the actual answers. The
20
+ * lookup still happens; it just stops costing a round trip through the model.
21
+ *
22
+ * `ref` wins when both are given, because it is the more specific instruction and silently
23
+ * preferring the query would act on something the caller did not name.
24
+ */
25
+ export async function resolveActTarget(session, args) {
26
+ const ref = asString(args['ref']);
27
+ if (ref !== undefined && ref.length > 0)
28
+ return { kind: 'ref', ref };
29
+ const target = args['target'];
30
+ if (target === undefined) {
31
+ return {
32
+ kind: 'error',
33
+ message: 'pass `ref` (from reticle_query/reticle_snapshot) or `target` (e.g. { testid } or { role, name }).',
34
+ };
35
+ }
36
+ const q = normalizeQueryArgs(asRecord(target));
37
+ const out = await session.command(ReticleCommand.QUERY, {
38
+ by: q['by'],
39
+ value: q['value'],
40
+ name: q['name'],
41
+ scope: q['scope'],
42
+ });
43
+ if (!out.ok)
44
+ return { kind: 'error', message: out.error ?? 'target query failed' };
45
+ const elements = asRecord(out.result)['elements'];
46
+ return resolveTargetRef(Array.isArray(elements) ? elements : []);
47
+ }
@@ -1,2 +1,22 @@
1
- import { type ToolDef } from './tool-kit.js';
1
+ /**
2
+ * Action tools — reticle_act, reticle_act_sequence, reticle_act_and_wait. Split out of tools.ts to keep
3
+ * that file under the line cap and assembled back into the tool list there via ...ACT_TOOLS; the
4
+ * native-input attempt itself lives in real-input-attempt.ts for the same reason.
5
+ */
6
+ import type { Session } from '../session/session.js';
7
+ import { z } from 'zod';
8
+ import { type ToolDef, type ToolDeps } from './tool-kit.js';
9
+ /**
10
+ * Single dispatch point for every ACT and ACT_SEQUENCE command.
11
+ *
12
+ * This is the seam the reviewer asked for: instead of wiring rewriteUploadArgs at three separate
13
+ * call sites (reticle_act, reticle_act_and_wait, reticle_act_sequence) we intercept once here,
14
+ * which also covers flow-replay, crawl, and any future dispatch site that goes through this helper.
15
+ *
16
+ * captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
17
+ * the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
18
+ * base64 to the browser as if it were an inline content call.
19
+ */
20
+ export declare function actCommand(deps: ToolDeps, session: Session, actArgs: Record<string, unknown>, timeoutMs?: number): Promise<import('@reticlehq/core').CommandResult>;
21
+ export declare const actionTypeEnum: z.ZodEnum<[string, ...string[]]>;
2
22
  export declare const ACT_TOOLS: ToolDef[];