@reticlehq/server 2.11.0 → 2.13.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 (513) hide show
  1. package/SKILL.md +93 -111
  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 -14
  5. package/dist/bridge/bridge.js +248 -165
  6. package/dist/bridge/bridge.test-harness.d.ts +2 -0
  7. package/dist/bridge/bridge.test-harness.js +8 -1
  8. package/dist/bridge/pairing-token.d.ts +5 -0
  9. package/dist/bridge/pairing-token.js +28 -0
  10. package/dist/bridge/protocol-skew.d.ts +37 -0
  11. package/dist/bridge/protocol-skew.js +45 -0
  12. package/dist/capsule/capsule-store.d.ts +8 -7
  13. package/dist/capsule/capsule-store.js +1 -1
  14. package/dist/capsule/causal-summary.d.ts +2 -2
  15. package/dist/capsule/causal-summary.js +7 -2
  16. package/dist/chromium-launch-options.d.ts +28 -0
  17. package/dist/chromium-launch-options.js +29 -0
  18. package/dist/cli/cli-doctor.js +39 -1
  19. package/dist/cli/cli-flow-commands.d.ts +3 -1
  20. package/dist/cli/cli-flow-commands.js +34 -4
  21. package/dist/cli/cli-kill.d.ts +2 -1
  22. package/dist/cli/cli-launch.d.ts +11 -1
  23. package/dist/cli/cli-launch.js +59 -10
  24. package/dist/cli/cli-parse.d.ts +17 -1
  25. package/dist/cli/cli-parse.js +238 -12
  26. package/dist/cli/cli-update-commands.js +20 -1
  27. package/dist/cli/cli-verify.d.ts +2 -1
  28. package/dist/cli/cli-verify.js +5 -4
  29. package/dist/cli/cloud-cli.js +428 -253
  30. package/dist/cli/cloud-keystore.d.ts +37 -0
  31. package/dist/cli/cloud-keystore.js +97 -0
  32. package/dist/cli/cloud-kit.d.ts +37 -0
  33. package/dist/cli/cloud-kit.js +121 -0
  34. package/dist/cli/cloud-login.d.ts +17 -0
  35. package/dist/cli/cloud-login.js +183 -0
  36. package/dist/cli/cloud-session.d.ts +48 -0
  37. package/dist/cli/cloud-session.js +53 -0
  38. package/dist/cli/config-discovery.d.ts +2 -1
  39. package/dist/cli/config-discovery.js +1 -0
  40. package/dist/cli/daemon-start-options.d.ts +32 -0
  41. package/dist/cli/daemon-start-options.js +38 -0
  42. package/dist/cli/device-flow.d.ts +76 -0
  43. package/dist/cli/device-flow.js +56 -0
  44. package/dist/cli/doctor-rows.d.ts +12 -1
  45. package/dist/cli/doctor-rows.js +12 -1
  46. package/dist/cli/drive-attach.d.ts +13 -0
  47. package/dist/cli/drive-attach.js +18 -0
  48. package/dist/cli/drive-command.js +7 -3
  49. package/dist/cli/gate-exit.d.ts +21 -0
  50. package/dist/cli/gate-exit.js +21 -0
  51. package/dist/cli/gate-hook-message.d.ts +33 -0
  52. package/dist/cli/gate-hook-message.js +46 -0
  53. package/dist/cli/mcp-command.d.ts +25 -0
  54. package/dist/cli/mcp-command.js +174 -0
  55. package/dist/cli/project-name.d.ts +30 -0
  56. package/dist/cli/project-name.js +44 -0
  57. package/dist/cli/sibling-ports.d.ts +37 -0
  58. package/dist/cli/sibling-ports.js +56 -0
  59. package/dist/cli/status-next-action.d.ts +14 -0
  60. package/dist/cli/status-next-action.js +4 -4
  61. package/dist/cli.d.ts +1 -0
  62. package/dist/cli.js +167 -186
  63. package/dist/cloud/cloud-config.d.ts +24 -2
  64. package/dist/cloud/cloud-config.js +64 -5
  65. package/dist/cloud/cloud-sync.d.ts +16 -5
  66. package/dist/cloud/cloud-sync.js +64 -1
  67. package/dist/cloud/sync-cycle.d.ts +110 -0
  68. package/dist/cloud/sync-cycle.js +270 -0
  69. package/dist/cloud/sync-daemon.d.ts +69 -0
  70. package/dist/cloud/sync-daemon.js +260 -0
  71. package/dist/cloud/sync-disk.d.ts +9 -0
  72. package/dist/cloud/sync-disk.js +191 -0
  73. package/dist/cloud/sync-hash.d.ts +2 -0
  74. package/dist/cloud/sync-hash.js +35 -0
  75. package/dist/crawl/crawl-tools.js +5 -3
  76. package/dist/crawl/crawl.d.ts +12 -13
  77. package/dist/crawl/crawl.js +25 -3
  78. package/dist/daemon/daemon-resolve.d.ts +122 -0
  79. package/dist/daemon/daemon-resolve.js +187 -0
  80. package/dist/daemon/dev-servers.d.ts +15 -0
  81. package/dist/daemon/dev-servers.js +68 -0
  82. package/dist/daemon/free-port.d.ts +29 -0
  83. package/dist/daemon/free-port.js +55 -0
  84. package/dist/daemon/heartbeat.d.ts +0 -4
  85. package/dist/daemon/heartbeat.js +2 -2
  86. package/dist/daemon/wake-decision.d.ts +32 -0
  87. package/dist/daemon/wake-decision.js +38 -0
  88. package/dist/dev/stale-issue-guard.d.ts +0 -2
  89. package/dist/dev/stale-issue-guard.js +1 -1
  90. package/dist/domain/domain-tools.js +2 -2
  91. package/dist/events/contradictions.d.ts +59 -0
  92. package/dist/events/contradictions.js +253 -27
  93. package/dist/events/declared.d.ts +17 -0
  94. package/dist/events/declared.js +43 -1
  95. package/dist/events/echo-mismatch.js +65 -1
  96. package/dist/events/event-filters.d.ts +8 -0
  97. package/dist/events/event-filters.js +19 -2
  98. package/dist/events/observed-in-window.d.ts +12 -0
  99. package/dist/events/observed-in-window.js +17 -0
  100. package/dist/events/predicate-asks.d.ts +13 -0
  101. package/dist/events/predicate-asks.js +22 -0
  102. package/dist/events/predicate-eval.js +117 -27
  103. package/dist/events/predicate-parse.d.ts +0 -6
  104. package/dist/events/predicate-parse.js +43 -3
  105. package/dist/events/predicate-precheck.d.ts +8 -0
  106. package/dist/events/predicate-precheck.js +41 -0
  107. package/dist/events/predicate-route.d.ts +14 -0
  108. package/dist/events/predicate-route.js +36 -8
  109. package/dist/events/predicate-schema.d.ts +44 -0
  110. package/dist/events/predicate-schema.js +126 -23
  111. package/dist/events/predicate.d.ts +20 -0
  112. package/dist/events/predicate.js +77 -6
  113. package/dist/events/split-text-miss.d.ts +30 -0
  114. package/dist/events/split-text-miss.js +44 -0
  115. package/dist/flows/coverage.d.ts +0 -8
  116. package/dist/flows/coverage.js +1 -1
  117. package/dist/flows/decision.d.ts +5 -1
  118. package/dist/flows/decision.js +33 -7
  119. package/dist/flows/flake.d.ts +6 -8
  120. package/dist/flows/flake.js +1 -1
  121. package/dist/flows/flow-intent.d.ts +52 -0
  122. package/dist/flows/flow-intent.js +123 -0
  123. package/dist/flows/flow-memory-consult.d.ts +55 -0
  124. package/dist/flows/flow-memory-consult.js +38 -0
  125. package/dist/flows/flow-replay-run.d.ts +18 -7
  126. package/dist/flows/flow-replay-run.js +263 -23
  127. package/dist/flows/flow-replay.js +11 -2
  128. package/dist/flows/flow-step-runners.d.ts +8 -0
  129. package/dist/flows/flow-step-runners.js +8 -2
  130. package/dist/flows/flow-store-for-session.d.ts +31 -0
  131. package/dist/flows/flow-store-for-session.js +33 -0
  132. package/dist/flows/flow-success.js +15 -3
  133. package/dist/flows/flow-tools.js +87 -33
  134. package/dist/flows/flows.d.ts +14 -1
  135. package/dist/flows/flows.js +502 -24
  136. package/dist/flows/heal-run.js +5 -2
  137. package/dist/flows/predicate-to-expect.d.ts +17 -12
  138. package/dist/flows/predicate-to-expect.js +36 -15
  139. package/dist/flows/recordings.d.ts +13 -1
  140. package/dist/flows/recordings.js +17 -2
  141. package/dist/flows/replay.d.ts +22 -2
  142. package/dist/flows/replay.js +28 -2
  143. package/dist/flows/server-verify.js +16 -2
  144. package/dist/flows/verify-change-tools.js +9 -3
  145. package/dist/honesty/blind-spots.d.ts +51 -15
  146. package/dist/honesty/blind-spots.js +64 -4
  147. package/dist/honesty/feature-capture.d.ts +150 -0
  148. package/dist/honesty/feature-capture.js +233 -0
  149. package/dist/honesty/honesty.d.ts +24 -0
  150. package/dist/honesty/honesty.js +25 -1
  151. package/dist/honesty/instrumentation-gaps.d.ts +39 -6
  152. package/dist/honesty/instrumentation-gaps.js +88 -5
  153. package/dist/honesty/tool-hit-rate.d.ts +86 -0
  154. package/dist/honesty/tool-hit-rate.js +90 -0
  155. package/dist/honesty/undeclared-change.d.ts +51 -0
  156. package/dist/honesty/undeclared-change.js +56 -0
  157. package/dist/honesty/verified.d.ts +16 -0
  158. package/dist/honesty/verified.js +84 -5
  159. package/dist/http-server.d.ts +0 -1
  160. package/dist/http-server.js +13 -1
  161. package/dist/hunt/hunt-report.d.ts +0 -2
  162. package/dist/hunt/hunt-report.js +1 -1
  163. package/dist/impact/impact-recorder.d.ts +31 -8
  164. package/dist/impact/impact-recorder.js +104 -21
  165. package/dist/impact/impact-store.d.ts +13 -4
  166. package/dist/impact/impact-store.js +44 -3
  167. package/dist/index.d.ts +4 -1
  168. package/dist/index.js +113 -7
  169. package/dist/init/agent-rules.d.ts +30 -6
  170. package/dist/init/agent-rules.js +54 -13
  171. package/dist/init/astro-patch.d.ts +16 -0
  172. package/dist/init/astro-patch.js +28 -0
  173. package/dist/init/capabilities.d.ts +4 -3
  174. package/dist/init/capabilities.js +23 -3
  175. package/dist/init/closing-hint.d.ts +36 -0
  176. package/dist/init/closing-hint.js +120 -0
  177. package/dist/init/confirm.d.ts +27 -28
  178. package/dist/init/confirm.js +51 -11
  179. package/dist/init/cra.d.ts +34 -5
  180. package/dist/init/cra.js +96 -25
  181. package/dist/init/csp-check.js +17 -2
  182. package/dist/init/csp-doctor.d.ts +8 -1
  183. package/dist/init/csp-doctor.js +8 -3
  184. package/dist/init/dev-script.d.ts +50 -0
  185. package/dist/init/dev-script.js +66 -0
  186. package/dist/init/format-generated.d.ts +18 -0
  187. package/dist/init/format-generated.js +39 -0
  188. package/dist/init/install-hint.d.ts +9 -0
  189. package/dist/init/install-hint.js +29 -0
  190. package/dist/init/mcp-clients.d.ts +7 -0
  191. package/dist/init/mcp-clients.js +7 -0
  192. package/dist/init/mcp.d.ts +17 -6
  193. package/dist/init/mcp.js +27 -11
  194. package/dist/init/node-io.js +11 -1
  195. package/dist/init/plan-framework.d.ts +0 -5
  196. package/dist/init/plan-framework.js +147 -37
  197. package/dist/init/plan.d.ts +30 -37
  198. package/dist/init/plan.js +50 -60
  199. package/dist/init/preflight.d.ts +28 -0
  200. package/dist/init/preflight.js +38 -0
  201. package/dist/init/refresh-rules.d.ts +39 -0
  202. package/dist/init/refresh-rules.js +51 -0
  203. package/dist/init/run.d.ts +32 -35
  204. package/dist/init/run.js +151 -202
  205. package/dist/init/slash-command.d.ts +1 -1
  206. package/dist/init/snippets.js +90 -31
  207. package/dist/init/vite-config.d.ts +1 -1
  208. package/dist/init/vite-config.js +39 -25
  209. package/dist/init/workspace-apps.d.ts +17 -10
  210. package/dist/init/workspace-apps.js +110 -0
  211. package/dist/input/network-mock-tools.js +3 -6
  212. package/dist/input/real-input.d.ts +2 -0
  213. package/dist/input/real-input.js +28 -7
  214. package/dist/input/scroll-find.d.ts +7 -4
  215. package/dist/input/scroll-find.js +63 -25
  216. package/dist/input/scroll-tools.js +4 -6
  217. package/dist/input/viewport-tools.js +5 -4
  218. package/dist/intent/inline-intent.d.ts +37 -0
  219. package/dist/intent/inline-intent.js +193 -0
  220. package/dist/intent/intent-shard-store.d.ts +72 -0
  221. package/dist/intent/intent-shard-store.js +203 -0
  222. package/dist/intent/intent-shard.d.ts +411 -0
  223. package/dist/intent/intent-shard.js +176 -0
  224. package/dist/intent/intent-store.d.ts +49 -0
  225. package/dist/intent/intent-store.js +133 -0
  226. package/dist/intent/intent-subject.d.ts +45 -0
  227. package/dist/intent/intent-subject.js +177 -0
  228. package/dist/intent/intent-tools.d.ts +2 -0
  229. package/dist/intent/intent-tools.js +143 -0
  230. package/dist/intent/open-intents.d.ts +42 -0
  231. package/dist/intent/open-intents.js +40 -0
  232. package/dist/journal/envelope.d.ts +26 -26
  233. package/dist/journal/journal-recorder.d.ts +23 -0
  234. package/dist/journal/journal-recorder.js +35 -0
  235. package/dist/license/license-env.d.ts +29 -0
  236. package/dist/license/license-env.js +148 -0
  237. package/dist/loopback-agent.d.ts +31 -0
  238. package/dist/loopback-agent.js +57 -0
  239. package/dist/mcp/attach-memory.d.ts +83 -0
  240. package/dist/mcp/attach-memory.js +185 -0
  241. package/dist/mcp/client-identity.d.ts +31 -0
  242. package/dist/mcp/client-identity.js +51 -0
  243. package/dist/mcp/mcp-post-transport.d.ts +26 -0
  244. package/dist/mcp/mcp-post-transport.js +109 -0
  245. package/dist/mcp/mcp-proxy.d.ts +2 -8
  246. package/dist/mcp/mcp-proxy.js +64 -62
  247. package/dist/mcp/mcp.d.ts +2 -0
  248. package/dist/mcp/mcp.js +52 -24
  249. package/dist/mcp/proxy-backoff.d.ts +11 -0
  250. package/dist/mcp/proxy-backoff.js +13 -0
  251. package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
  252. package/dist/mcp/proxy-daemon-probe.js +7 -1
  253. package/dist/mcp/proxy-handshake.d.ts +23 -0
  254. package/dist/mcp/proxy-handshake.js +31 -0
  255. package/dist/mcp/server-instructions.js +45 -3
  256. package/dist/mcp/tool-catalog-cache.d.ts +16 -0
  257. package/dist/mcp/tool-catalog-cache.js +22 -0
  258. package/dist/memory/memory-tools.d.ts +2 -0
  259. package/dist/memory/memory-tools.js +82 -0
  260. package/dist/memory/project-memory.d.ts +34 -0
  261. package/dist/memory/project-memory.js +96 -0
  262. package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
  263. package/dist/oracles/flow-instrument-gaps.js +4 -5
  264. package/dist/oracles/propose-consequences.js +12 -3
  265. package/dist/oracles/self-instrument.d.ts +9 -9
  266. package/dist/oracles/self-instrument.js +19 -13
  267. package/dist/pool/browser-pool.d.ts +75 -5
  268. package/dist/pool/browser-pool.js +144 -5
  269. package/dist/pool/playwright-launcher.js +12 -1
  270. package/dist/project/fs-port.d.ts +3 -0
  271. package/dist/project/fs-port.js +3 -2
  272. package/dist/project/memory-fs.js +6 -1
  273. package/dist/project/project-tools.js +6 -35
  274. package/dist/project/reticle-dir.d.ts +17 -2
  275. package/dist/project/reticle-dir.js +22 -4
  276. package/dist/runs/context-tools.d.ts +2 -0
  277. package/dist/runs/context-tools.js +89 -0
  278. package/dist/runs/run-context.d.ts +40 -0
  279. package/dist/runs/run-context.js +158 -0
  280. package/dist/runs/run-diff.d.ts +2 -1
  281. package/dist/runs/run-store.d.ts +10 -0
  282. package/dist/runs/run-store.js +10 -0
  283. package/dist/runs/verification-sync.d.ts +0 -11
  284. package/dist/runs/verification-sync.js +24 -3
  285. package/dist/runs/verify-server.d.ts +8 -1
  286. package/dist/runs/verify-server.js +14 -2
  287. package/dist/session/command-timeout.d.ts +5 -2
  288. package/dist/session/command-timeout.js +5 -4
  289. package/dist/session/dev-server-probe.d.ts +0 -8
  290. package/dist/session/dev-server-probe.js +1 -1
  291. package/dist/session/last-act.d.ts +7 -1
  292. package/dist/session/last-act.js +2 -2
  293. package/dist/session/lease-visibility.d.ts +67 -0
  294. package/dist/session/lease-visibility.js +76 -0
  295. package/dist/session/live-control-tools.js +1 -42
  296. package/dist/session/no-session-diagnosis.d.ts +33 -0
  297. package/dist/session/no-session-diagnosis.js +82 -24
  298. package/dist/session/no-session-next-action.d.ts +12 -0
  299. package/dist/session/no-session-next-action.js +77 -6
  300. package/dist/session/no-session-watch.d.ts +18 -6
  301. package/dist/session/no-session-watch.js +125 -75
  302. package/dist/session/output-budget.js +4 -1
  303. package/dist/session/pending-commands.d.ts +11 -1
  304. package/dist/session/pending-commands.js +12 -2
  305. package/dist/session/resolve-within.d.ts +34 -0
  306. package/dist/session/resolve-within.js +53 -0
  307. package/dist/session/session-health.d.ts +9 -0
  308. package/dist/session/session-health.js +23 -0
  309. package/dist/session/session-info.d.ts +18 -0
  310. package/dist/session/session-info.js +11 -0
  311. package/dist/session/session-manager.d.ts +14 -0
  312. package/dist/session/session-manager.js +111 -4
  313. package/dist/session/session-mirror.d.ts +16 -0
  314. package/dist/session/session-mirror.js +22 -0
  315. package/dist/session/session-recommendation.d.ts +19 -5
  316. package/dist/session/session-recommendation.js +25 -9
  317. package/dist/session/session-successor.d.ts +37 -0
  318. package/dist/session/session-successor.js +113 -0
  319. package/dist/session/session-tools.js +2 -2
  320. package/dist/session/session.d.ts +53 -3
  321. package/dist/session/session.js +162 -9
  322. package/dist/session/wall-clock.d.ts +12 -0
  323. package/dist/session/wall-clock.js +14 -0
  324. package/dist/setup/agent-configs.d.ts +96 -0
  325. package/dist/setup/agent-configs.js +333 -0
  326. package/dist/setup/agent-io.d.ts +9 -0
  327. package/dist/setup/agent-io.js +16 -0
  328. package/dist/setup/agent-writer.d.ts +51 -0
  329. package/dist/setup/agent-writer.js +115 -0
  330. package/dist/setup/approval-migration.d.ts +47 -0
  331. package/dist/setup/approval-migration.js +68 -0
  332. package/dist/setup/auto-approve.d.ts +85 -0
  333. package/dist/setup/auto-approve.js +150 -0
  334. package/dist/setup/bridge-port.d.ts +15 -0
  335. package/dist/setup/bridge-port.js +24 -0
  336. package/dist/setup/desktop-shape.d.ts +57 -0
  337. package/dist/setup/desktop-shape.js +63 -0
  338. package/dist/setup/dev-server-wait.d.ts +60 -0
  339. package/dist/setup/dev-server-wait.js +65 -0
  340. package/dist/setup/drive-agent.d.ts +71 -0
  341. package/dist/setup/drive-agent.js +171 -0
  342. package/dist/setup/drive-plan.d.ts +68 -0
  343. package/dist/setup/drive-plan.js +130 -0
  344. package/dist/setup/ensure-daemon.d.ts +29 -0
  345. package/dist/setup/ensure-daemon.js +58 -0
  346. package/dist/setup/init-runtime.d.ts +47 -0
  347. package/dist/setup/init-runtime.js +160 -0
  348. package/dist/setup/interrupt.d.ts +25 -0
  349. package/dist/setup/interrupt.js +40 -0
  350. package/dist/setup/license-key.d.ts +39 -0
  351. package/dist/setup/license-key.js +72 -0
  352. package/dist/setup/listeners.d.ts +37 -0
  353. package/dist/setup/listeners.js +85 -0
  354. package/dist/setup/node-effects.d.ts +60 -0
  355. package/dist/setup/node-effects.js +210 -0
  356. package/dist/setup/page-probe.d.ts +39 -0
  357. package/dist/setup/page-probe.js +49 -0
  358. package/dist/setup/relaunch.d.ts +36 -0
  359. package/dist/setup/relaunch.js +57 -0
  360. package/dist/setup/remaining-steps.d.ts +19 -0
  361. package/dist/setup/remaining-steps.js +31 -0
  362. package/dist/setup/run-setup.d.ts +99 -0
  363. package/dist/setup/run-setup.js +187 -0
  364. package/dist/setup/session-pick.d.ts +47 -0
  365. package/dist/setup/session-pick.js +51 -0
  366. package/dist/setup/setup-command.d.ts +45 -0
  367. package/dist/setup/setup-command.js +199 -0
  368. package/dist/setup/setup-options.d.ts +74 -0
  369. package/dist/setup/setup-options.js +67 -0
  370. package/dist/setup/transcripts.d.ts +16 -0
  371. package/dist/setup/transcripts.js +43 -0
  372. package/dist/status-payload.d.ts +14 -1
  373. package/dist/status-payload.js +23 -1
  374. package/dist/telemetry/automation-hint.d.ts +2 -1
  375. package/dist/telemetry/daemon-telemetry.d.ts +8 -1
  376. package/dist/telemetry/daemon-telemetry.js +52 -5
  377. package/dist/telemetry/error-class.js +1 -1
  378. package/dist/telemetry/feedback-context.d.ts +9 -1
  379. package/dist/telemetry/feedback-context.js +60 -29
  380. package/dist/telemetry/feedback-local.d.ts +15 -0
  381. package/dist/telemetry/feedback-local.js +56 -0
  382. package/dist/telemetry/feedback-outbox.d.ts +2 -1
  383. package/dist/telemetry/feedback.d.ts +11 -0
  384. package/dist/telemetry/feedback.js +19 -6
  385. package/dist/telemetry/init-telemetry.d.ts +2 -0
  386. package/dist/telemetry/init-telemetry.js +2 -0
  387. package/dist/telemetry/install-source.d.ts +14 -0
  388. package/dist/telemetry/install-source.js +30 -0
  389. package/dist/telemetry/license-activation.d.ts +7 -1
  390. package/dist/telemetry/license-activation.js +9 -5
  391. package/dist/telemetry/mcp-connection.js +7 -0
  392. package/dist/telemetry/project-profile.d.ts +12 -9
  393. package/dist/telemetry/project-profile.js +12 -7
  394. package/dist/telemetry/proxy-telemetry.d.ts +3 -0
  395. package/dist/telemetry/proxy-telemetry.js +21 -0
  396. package/dist/telemetry/run-telemetry.d.ts +0 -2
  397. package/dist/telemetry/run-telemetry.js +1 -1
  398. package/dist/telemetry/session-metrics.d.ts +12 -0
  399. package/dist/telemetry/session-metrics.js +35 -1
  400. package/dist/telemetry/telemetry.js +17 -2
  401. package/dist/telemetry/tool-refused.d.ts +3 -1
  402. package/dist/telemetry/tool-refused.js +34 -2
  403. package/dist/telemetry/verification-of.js +2 -2
  404. package/dist/tools/act-capsule.d.ts +10 -0
  405. package/dist/tools/act-capsule.js +8 -2
  406. package/dist/tools/act-danger.d.ts +2 -1
  407. package/dist/tools/act-danger.js +11 -3
  408. package/dist/tools/act-observation.d.ts +41 -0
  409. package/dist/tools/act-observation.js +36 -0
  410. package/dist/tools/act-preflight.d.ts +20 -0
  411. package/dist/tools/act-preflight.js +98 -0
  412. package/dist/tools/act-sequence-retry.d.ts +45 -0
  413. package/dist/tools/act-sequence-retry.js +58 -0
  414. package/dist/tools/act-sequence-tool.d.ts +13 -0
  415. package/dist/tools/act-sequence-tool.js +135 -0
  416. package/dist/tools/act-target.d.ts +14 -0
  417. package/dist/tools/act-target.js +47 -0
  418. package/dist/tools/act-tools.d.ts +21 -1
  419. package/dist/tools/act-tools.js +196 -204
  420. package/dist/tools/assert-source.d.ts +22 -0
  421. package/dist/tools/assert-source.js +53 -0
  422. package/dist/tools/assert-verdict.d.ts +20 -3
  423. package/dist/tools/assert-verdict.js +58 -20
  424. package/dist/tools/browser-tools.js +6 -22
  425. package/dist/tools/complete-snapshot.d.ts +48 -0
  426. package/dist/tools/complete-snapshot.js +75 -0
  427. package/dist/tools/coverage-tools.d.ts +10 -1
  428. package/dist/tools/coverage-tools.js +123 -69
  429. package/dist/tools/dynamic-tools.js +53 -13
  430. package/dist/tools/error-recovery.d.ts +25 -14
  431. package/dist/tools/error-recovery.js +78 -9
  432. package/dist/tools/feedback-tools.d.ts +1 -1
  433. package/dist/tools/feedback-tools.js +2 -2
  434. package/dist/tools/invoke-tool.js +121 -11
  435. package/dist/tools/lease-hint.d.ts +10 -0
  436. package/dist/tools/lease-hint.js +53 -4
  437. package/dist/tools/lease-tools.d.ts +35 -5
  438. package/dist/tools/lease-tools.js +191 -13
  439. package/dist/tools/merged-name-redirect.d.ts +13 -0
  440. package/dist/tools/merged-name-redirect.js +22 -0
  441. package/dist/tools/navigate-arrival.d.ts +0 -2
  442. package/dist/tools/navigate-arrival.js +1 -1
  443. package/dist/tools/numeric-bounds.d.ts +100 -0
  444. package/dist/tools/numeric-bounds.js +125 -0
  445. package/dist/tools/observe-tools.js +109 -65
  446. package/dist/tools/read-tools.js +31 -8
  447. package/dist/tools/real-input-attempt.d.ts +32 -0
  448. package/dist/tools/real-input-attempt.js +212 -2
  449. package/dist/tools/reconcile-tools.js +22 -8
  450. package/dist/tools/resolve-target.d.ts +0 -7
  451. package/dist/tools/sdk-marker-probe.d.ts +29 -0
  452. package/dist/tools/sdk-marker-probe.js +57 -0
  453. package/dist/tools/snapshot-delta.d.ts +1 -1
  454. package/dist/tools/tool-kit.d.ts +24 -0
  455. package/dist/tools/tool-kit.js +21 -0
  456. package/dist/tools/tool-names.d.ts +5 -0
  457. package/dist/tools/tool-names.js +5 -0
  458. package/dist/tools/tool-surface.d.ts +85 -6
  459. package/dist/tools/tool-surface.js +122 -2
  460. package/dist/tools/tools-helpers.d.ts +19 -0
  461. package/dist/tools/tools-helpers.js +46 -0
  462. package/dist/tools/tools.d.ts +2 -0
  463. package/dist/tools/tools.js +78 -12
  464. package/dist/tools/unadvertised-help.js +4 -4
  465. package/dist/tools/verify-next-baton.d.ts +53 -0
  466. package/dist/tools/verify-next-baton.js +52 -0
  467. package/dist/update/reticle-deps.d.ts +9 -0
  468. package/dist/update/reticle-deps.js +27 -0
  469. package/dist/update/sdk-sync.d.ts +1 -2
  470. package/dist/update/sdk-sync.js +1 -21
  471. package/dist/update/update-nudge.d.ts +25 -10
  472. package/dist/update/update-nudge.js +32 -3
  473. package/dist/update/updater.d.ts +1 -1
  474. package/dist/version/peer-announce.js +4 -2
  475. package/dist/version/sdk-fix.d.ts +47 -0
  476. package/dist/version/sdk-fix.js +127 -0
  477. package/dist/version/version-nudge.d.ts +14 -0
  478. package/dist/version/version-nudge.js +21 -0
  479. package/dist/version/version-skew.d.ts +38 -3
  480. package/dist/version/version-skew.js +83 -7
  481. package/dist/visual/visual-store.d.ts +6 -6
  482. package/dist/visual/visual-store.js +18 -16
  483. package/dist/visual/visual-tools.js +57 -12
  484. package/docs/README.md +2 -1
  485. package/docs/cli/cloud.mdx +1 -1
  486. package/docs/cli/doctor.mdx +2 -0
  487. package/docs/cli/serve.mdx +4 -2
  488. package/docs/cli/verify.mdx +4 -5
  489. package/docs/cli.mdx +7 -3
  490. package/docs/desktop.mdx +1 -1
  491. package/docs/docs.json +2 -2
  492. package/docs/gates.md +1 -1
  493. package/docs/getting-started.md +19 -3
  494. package/docs/index.mdx +9 -6
  495. package/docs/install-agentic.mdx +38 -12
  496. package/docs/install-manual.mdx +1 -1
  497. package/docs/packages/browser.mdx +2 -2
  498. package/docs/packages/server.mdx +1 -1
  499. package/docs/packages.mdx +8 -6
  500. package/docs/platform-integration.md +17 -0
  501. package/docs/predicates.mdx +8 -0
  502. package/docs/reticle-manual.md +106 -0
  503. package/docs/skill-file.mdx +3 -3
  504. package/docs/telemetry-contract.md +108 -4
  505. package/docs/tools-act-sequence.mdx +16 -0
  506. package/docs/tools-tools-and-run.mdx +2 -4
  507. package/docs/troubleshooting.mdx +9 -0
  508. package/docs/usage.md +4 -3
  509. package/package.json +4 -3
  510. package/dist/init/cursor.d.ts +0 -24
  511. package/dist/init/cursor.js +0 -80
  512. package/dist/session/session-readiness.d.ts +0 -34
  513. package/dist/session/session-readiness.js +0 -36
@@ -5,21 +5,29 @@
5
5
  import { noteEmptyRead } from './observed-nothing.js';
6
6
  import { z } from 'zod';
7
7
  import { aliasParam } from './alias-args.js';
8
- import { CONSOLE_LEVELS, ReticleCommand, DEFAULT_ASSERT_TIMEOUT_MS, PredicateKind, } from '@reticlehq/core';
8
+ import { CONSOLE_LEVELS, ReticleCommand, DEFAULT_ASSERT_TIMEOUT_MS, PredicateKind, Verified, } from '@reticlehq/core';
9
9
  import { ReticleTool } from './tool-names.js';
10
+ import { countSchema, cursorSchema, httpStatusSchema, timeoutMsSchema, windowMsSchema, } from './numeric-bounds.js';
10
11
  import { buildReactionReport } from '../events/reaction.js';
11
12
  import { findContradictions } from '../events/contradictions.js';
12
13
  import { evaluatePredicate, waitForPredicate, PredicateSchema } from '../events/predicate.js';
14
+ import { resolveSessionWithin } from '../session/resolve-within.js';
15
+ import { WALL_CLOCK } from '../session/wall-clock.js';
13
16
  import { parsePredicate } from '../events/predicate-parse.js';
14
- import { matchNet, matchConsole, isConsoleEvent, eventMatchesFilters, netEmptyHint, consoleEmptyHint, reconcileNet, projectNetCall, projectConsoleLog, } from '../events/event-filters.js';
17
+ import { matchNet, matchConsole, isConsoleEvent, eventMatchesFilters, netEmptyHint, consoleEmptyHint, reconcileNet, projectNetCall, projectConsoleLog, withoutUrlRaw, } from '../events/event-filters.js';
15
18
  import { applyEventBudget, costHint, withSizeCost, DEFAULT_QUERY_LIMIT, } from '../session/output-budget.js';
16
- import { healthEnvelope, bufferEnvelope } from '../session/session-health.js';
19
+ import { annotateStarvedFailure, healthEnvelope, bufferEnvelope, } from '../session/session-health.js';
17
20
  import { assertsDerivedIpcStatus, DERIVED_IPC_STATUS_ADVICE, isPresenceOnlyAssertion, PRESENCE_ONLY_ADVICE, } from './assert-grade.js';
18
21
  import { assertVerdict } from './assert-verdict.js';
22
+ import { assertSource } from './assert-source.js';
23
+ import { isChangeUndeclared } from '../honesty/undeclared-change.js';
24
+ import { openSessionIntents } from '../intent/open-intents.js';
25
+ import { dischargeInlineIntent, inlineVerdictId, linkInlineIntent, } from '../intent/inline-intent.js';
19
26
  import { bodiesNotCaptured } from '../honesty/uncaptured-bodies.js';
20
27
  import { withControl } from '../session/control-envelope.js';
21
- import { asString, asNumber } from './tools-helpers.js';
22
- import { sessionIdShape, commandOrThrow } from './tool-kit.js';
28
+ import { asString, asNumber, asRecord } from './tools-helpers.js';
29
+ import { intentArg, sessionIdShape, commandOrThrow } from './tool-kit.js';
30
+ import { gradeOfPredicate } from './assert-grade.js';
23
31
  /**
24
32
  * Evidence-completeness block: present on observe/network/console only when the ring buffer has
25
33
  * evicted events, so a "no such event" answer is distinguishable from "I dropped it" (issue #27).
@@ -31,20 +39,20 @@ const bufferOutputShape = {
31
39
  .describe('Present only when the event buffer evicted events — a negative result may then be a false negative.'),
32
40
  };
33
41
  /**
34
- * Where to look when a failure has no element.
42
+ * The file:line an assertion may report — see `assertSource`.
35
43
  *
36
- * "the signal never fired", "the request was never made", "the store did not change" have no DOM node
37
- * to map to a component, so the file:line that covers element failures leaves exactly the failures
38
- * that most need explaining with nowhere to send the agent. The handler that should have fired the
39
- * signal lives with the control that was clicked, and the act path captured that control's source —
40
- * so a failing assertion can point there instead of at nothing.
41
- *
42
- * RED only: on a pass this is noise on the path the agent walks most.
44
+ * Neither `reticle_assert` nor `reticle_wait_for` drives anything, so the last act's source is about
45
+ * some earlier action and not about this verdict. The pointer comes from the assertion's own matched
46
+ * evidence; the last driven control is borrowed only for a RED whose predicate has no DOM clause at
47
+ * all, which is the failure that genuinely has no element to point at.
43
48
  */
44
- function lastActSourceOnFailure(session, pass) {
45
- if (pass)
46
- return {};
47
- const source = session.lastAct.source();
49
+ function assertionSource(session, predicate, verdict) {
50
+ const source = assertSource({
51
+ predicate,
52
+ evidence: verdict.evidence,
53
+ pass: verdict.pass,
54
+ lastActSource: session.lastAct.source(),
55
+ });
48
56
  return source === undefined ? {} : { source };
49
57
  }
50
58
  /**
@@ -78,21 +86,17 @@ export const OBSERVE_TOOLS = [
78
86
  example: { since: 0 },
79
87
  description: 'Return the timeline of everything the app did in a window (DOM/network/route/console/animation/signal), with a summary. Use after an action. Pass `max_events` to cap the timeline to the most recent N (older events are dropped and counted in cost.droppedOldest). Every result carries a `cost:{events,bytes}` hint so you can self-budget your next call.',
80
88
  inputSchema: {
81
- window_ms: z
82
- .number()
83
- .positive()
89
+ window_ms: windowMsSchema
84
90
  // A non-positive window silently produced a FUTURE cursor, so the tool returned zero events
85
91
  // and echoed the nonsense value back — indistinguishable from a genuinely quiet page. An
86
92
  // agent that fumbles this argument gets a clean "nothing happened" instead of being told the
87
93
  // question was malformed, which is the exact confusion this layer exists to refuse.
88
94
  .optional()
89
95
  .describe('Time window to look back, in ms (must be > 0). Default: 2000. Ignored when `since` is provided.'),
90
- since: z
91
- .number()
96
+ since: cursorSchema
92
97
  .optional()
93
98
  .describe('Cursor from a prior reticle_act or reticle_observe call. Scopes the event window to exactly that span.'),
94
- until: z
95
- .number()
99
+ until: cursorSchema
96
100
  .optional()
97
101
  .describe('Upper cursor bound. With `since`, returns the span "between action A and B".'),
98
102
  actionId: z
@@ -105,9 +109,7 @@ export const OBSERVE_TOOLS = [
105
109
  .describe('Event type allowlist — the cheapest way to shrink a large timeline. Use a bucket name — ' +
106
110
  'dom | net | route | console | animation | signal | perf | state | storage — or a raw ' +
107
111
  'type (e.g. "net.request"). Omit to return all types.'),
108
- max_events: z
109
- .number()
110
- .nonnegative()
112
+ max_events: countSchema
111
113
  .optional()
112
114
  .describe('Cap the timeline to the most recent N events. Older events are counted in cost.droppedOldest.'),
113
115
  ...sessionIdShape,
@@ -179,11 +181,16 @@ export const OBSERVE_TOOLS = [
179
181
  // never asked about.
180
182
  const actCursor = session.lastAct.cursor();
181
183
  const judgingTheAct = actCursor !== undefined && actCursor >= since;
182
- const contradictions = findContradictions(filtered, judgingTheAct ? { ...session.lastAct.effect(), actionSince: actCursor } : {});
184
+ const contradictions = findContradictions(filtered, {
185
+ currentDocumentId: session.currentDocumentId,
186
+ currentEditEpoch: session.currentEditEpoch,
187
+ appOrigin: session.url,
188
+ ...(judgingTheAct ? { ...session.lastAct.effect(), actionSince: actCursor } : {}),
189
+ });
183
190
  // carry session health — a throttled tab means the observed timeline may be incomplete.
184
191
  return withControl(session, {
185
192
  ...report,
186
- events: report.events.map(withoutConstantSessionId),
193
+ events: report.events.map((e) => withoutUrlRaw(withoutConstantSessionId(e))),
187
194
  ...(contradictions.length > 0 ? { contradictions } : {}),
188
195
  cost: costHint(report, budgeted.length, droppedOldest),
189
196
  ...healthEnvelope(session),
@@ -199,9 +206,10 @@ export const OBSERVE_TOOLS = [
199
206
  predicate: PredicateSchema.optional().describe('Predicate to wait for: { signal }, { net }, { element }, { kind: "net", ok: false } (assert on the OUTCOME — the honest field for IPC, which has no status code), { kind: "state", store, path, equals } (assert a registered store\'s value directly — the source of truth no DOM read can reach; equals takes a literal or { $gte | $contains | $length } pattern), { kind: "settled", quietMs } (deterministic network + DOM idle — prefer this over a fixed sleep), or a combination via allOf/anyOf.'),
200
207
  // Same concept, the neighbouring tool's name. See alias-args.ts.
201
208
  until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
202
- timeout_ms: z.number().optional().describe('Maximum wait in milliseconds. Default: 4000.'),
203
- since: z
204
- .number()
209
+ timeout_ms: timeoutMsSchema
210
+ .optional()
211
+ .describe('Maximum wait in milliseconds. Default: 4000. Capped at 55000: your MCP client aborts the request before a longer wait can return, so a bound above this would be advertised and not deliverable. To outlast it, poll — several short waits, each of which returns a verdict.'),
212
+ since: cursorSchema
205
213
  .optional()
206
214
  .describe('Cursor from a prior reticle_act — scopes the wait to events after that act.'),
207
215
  ...sessionIdShape,
@@ -214,6 +222,10 @@ export const OBSERVE_TOOLS = [
214
222
  .boolean()
215
223
  .optional()
216
224
  .describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
225
+ inconclusive: z
226
+ .string()
227
+ .optional()
228
+ .describe('The wait could not be graded as a product failure — e.g. the tab is throttled and may never have rendered. The verdict is UNKNOWN, not "the UI is absent".'),
217
229
  session: z
218
230
  .object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
219
231
  .optional(),
@@ -233,20 +245,25 @@ export const OBSERVE_TOOLS = [
233
245
  source: z
234
246
  .string()
235
247
  .optional()
236
- .describe('On a FAILING assertion, the `file:line` of the control last acted on — where the code that should have produced the missing signal/request/state change lives. Present only when an act preceded this assertion.'),
248
+ .describe('Where the code behind this verdict lives, as `file:line`. For an element/text assertion it is the matched element itself; for a FAILING signal/net/state assertion — which has no element to point at — it is the control last acted on, where the handler that should have fired lives. OMITTED when neither is known: this tool never borrows an unrelated location.'),
237
249
  },
238
250
  handler: async (deps, args) => {
239
- const session = deps.sessions.resolve(asString(args['sessionId']));
251
+ const waitBudget = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
252
+ // Spend the budget waiting for the APP as well as for the predicate. See resolve-within.
253
+ const session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), waitBudget, WALL_CLOCK);
240
254
  // `until` is act_and_wait's name for this — see alias-args.ts.
241
255
  const predicate = parsePredicate(aliasParam(args, 'predicate', ['until'])['predicate']);
242
256
  // Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
243
257
  const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
244
- const verdict = await waitForPredicate(session, predicate, asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS, since);
258
+ const verdict = await waitForPredicate(session, predicate, waitBudget, since);
245
259
  // match reticle_assert — wrap with control + session health (throttle matters most while blocking)
246
260
  // and the buffer envelope, so a verdict reached over an evicted window says so.
247
261
  return withControl(session, {
248
- ...verdict,
249
- ...lastActSourceOnFailure(session, verdict.pass),
262
+ // #537's starved-wait note wraps the verdict (it RETURNS the verdict), so it stands where
263
+ // `...verdict` did. The source line is #533's `assertionSource`, which superseded
264
+ // `lastActSourceOnFailure` — an assert used to be blamed on the previous act's file:line.
265
+ ...annotateStarvedFailure(session, verdict),
266
+ ...assertionSource(session, predicate, verdict),
250
267
  ...healthEnvelope(session),
251
268
  ...bufferEnvelope(session),
252
269
  });
@@ -255,27 +272,27 @@ export const OBSERVE_TOOLS = [
255
272
  {
256
273
  name: ReticleTool.ASSERT,
257
274
  example: { predicate: { kind: PredicateKind.SIGNAL, name: 'todos:loaded' } },
258
- description: 'Evaluate a predicate (optionally waiting up to timeout_ms). Returns { pass, evidence, failureReason? }. The end of every verify loop. Prefer a { signal } or { net } consequence over { element }/{ text } presence — a passing presence-only assertion returns `advice` because a wrong/healed element can fake it. By default it only counts events since your last act, so a stale buffered signal can never fake a pass; pass `since` (an observe/act cursor) to set the window explicitly.',
275
+ description: 'Evaluate a predicate (optionally waiting up to timeout_ms). Returns { pass, evidence, failureReason? }. The end of every verify loop. CHECKING SEVERAL THINGS? Put them in ONE call with { kind: "allOf", predicates: [...] } — it returns one verdict naming whichever member failed, and one call costs one round trip where N calls cost N. Prefer a { signal } or { net } consequence over { element }/{ text } presence — a passing presence-only assertion returns `advice` because a wrong/healed element can fake it. By default it only counts events since your last act, so a stale buffered signal can never fake a pass; pass `since` (an observe/act cursor) to set the window explicitly.',
259
276
  inputSchema: {
260
277
  predicate: PredicateSchema.optional().describe(
261
278
  // Every kind, each with the field that carries its argument. Five of the nine were
262
279
  // undocumented here, including `route` — and "did submitting the login form navigate away"
263
280
  // is the most common thing an agent wants to assert. A field report reached us from an agent
264
281
  // that guessed `urlContains` on route (net's spelling) and got unrecognized_keys.
265
- 'Predicate to evaluate. Kinds: { signal, name } { net, urlContains|method|status|count|bodyContains } ' +
282
+ 'Predicate to evaluate. Kinds: { signal, name|dataMatches|count } ' +
283
+ '{ net, urlContains|method|status|count|bodyContains } ' +
266
284
  '{ state, path|equals } { route, pathname (exact) | contains (path+query+hash) } ' +
267
285
  '{ element, testid|role|text } { text } { console, level|contains|absent } { animation, name } ' +
268
286
  '{ settled } — combine with { allOf | anyOf | not }. Prefer a signal/net/state consequence ' +
269
287
  'over element/text presence.'),
270
288
  until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
271
- timeout_ms: z
272
- .number()
289
+ timeout_ms: timeoutMsSchema
273
290
  .optional()
274
- .describe('If > 0, wait up to this many milliseconds before failing. Default: 0 (evaluate once).'),
275
- since: z
276
- .number()
291
+ .describe('If > 0, wait up to this many milliseconds before failing. Default: 0 (evaluate once). Capped at 55000: your MCP client aborts the request before a longer wait can return, so a bound above this would be advertised and not deliverable. To outlast it, poll — several short waits, each of which returns a verdict.'),
292
+ since: cursorSchema
277
293
  .optional()
278
294
  .describe('Cursor from a prior reticle_act — scopes the assertion to events after that act.'),
295
+ intent: intentArg,
279
296
  ...sessionIdShape,
280
297
  },
281
298
  outputSchema: {
@@ -286,6 +303,10 @@ export const OBSERVE_TOOLS = [
286
303
  .boolean()
287
304
  .optional()
288
305
  .describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
306
+ inconclusive: z
307
+ .string()
308
+ .optional()
309
+ .describe('The assertion could not be graded as a product failure — e.g. the tab is throttled and may never have rendered. The verdict is UNKNOWN, not "the UI is absent".'),
289
310
  advice: z
290
311
  .string()
291
312
  .optional()
@@ -309,7 +330,7 @@ export const OBSERVE_TOOLS = [
309
330
  source: z
310
331
  .string()
311
332
  .optional()
312
- .describe('On a FAILING assertion, the `file:line` of the control last acted on — where the code that should have produced the missing signal/request/state change lives. Present only when an act preceded this assertion.'),
333
+ .describe('Where the code behind this verdict lives, as `file:line`. For an element/text assertion it is the matched element itself; for a FAILING signal/net/state assertion — which has no element to point at — it is the control last acted on, where the handler that should have fired lives. OMITTED when neither is known: this tool never borrows an unrelated location.'),
313
334
  coverage: z
314
335
  .string()
315
336
  .optional()
@@ -324,12 +345,16 @@ export const OBSERVE_TOOLS = [
324
345
  .describe('What the APP did not tell Reticle, and the one change that would fix it — each entry is { kind, missing, cost, fix, source?, ref? }. Reported ONLY where an absence made THIS verdict weaker: a failing assertion with no source to point at, or a state assertion against an app that registers no store. Never a survey of the page, so an entry is always work worth doing now. OMITTED when the app told Reticle everything it needed.'),
325
346
  },
326
347
  handler: async (deps, args) => {
327
- const session = deps.sessions.resolve(asString(args['sessionId']));
348
+ const timeout = asNumber(args['timeout_ms']) ?? 0;
349
+ // Spend the budget waiting for the APP as well as for the predicate. See resolve-within.
350
+ const session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), timeout, WALL_CLOCK);
328
351
  // `until` is act_and_wait's name for this — see alias-args.ts.
329
352
  const predicate = parsePredicate(aliasParam(args, 'predicate', ['until'])['predicate']);
330
- const timeout = asNumber(args['timeout_ms']) ?? 0;
331
353
  // Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
332
354
  const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
355
+ // Declared BEFORE the verdict, so the undeclared-change read below finds it open and stays
356
+ // quiet on THIS verdict rather than on the next one. Discharged after that read.
357
+ const intentId = await linkInlineIntent(deps, asString(args['sessionId']), asString(args['intent']), PredicateKind.SETTLED === predicate.kind ? undefined : predicate);
333
358
  const verdict = timeout > 0
334
359
  ? await waitForPredicate(session, predicate, timeout, since)
335
360
  : await evaluatePredicate(session, predicate, since);
@@ -345,16 +370,43 @@ export const OBSERVE_TOOLS = [
345
370
  : assertsDerivedIpcStatus(predicate)
346
371
  ? { advice: DERIVED_IPC_STATUS_ADVICE }
347
372
  : {};
348
- const { decision, contradictions, coverage, gaps } = await assertVerdict(session, predicate, verdict.pass, since, verdict.inconclusive, verdict.observationLost);
373
+ // Asked of every verdict drawn after an observed edit, not once per edit — see
374
+ // isChangeUndeclared for why repeating it is disclosure rather than nagging.
375
+ const changeUndeclared = await isChangeUndeclared(session.currentEditEpoch, () => openSessionIntents(deps, asString(args['sessionId'])));
376
+ const { decision, contradictions, coverage, gaps, verdictEffect } = await assertVerdict(session, predicate, verdict.pass, verdict.evidence, since, verdict.inconclusive, verdict.observationLost, changeUndeclared);
377
+ // The assertion IS the proof attempt, so a green one discharges the intent it was drawn for. A
378
+ // red proved nothing, and an unbound intent refuses discharge anyway — see inline-intent.ts.
379
+ // The id is checked HERE rather than only inside the helper so a caller that declared no intent
380
+ // touches nothing at all, not even the clock.
381
+ if (intentId !== undefined && Verified.YES === decision['verified']) {
382
+ await dischargeInlineIntent(deps, asString(args['sessionId']), intentId, {
383
+ verdictId: inlineVerdictId(ReticleTool.ASSERT, deps.now()),
384
+ grade: gradeOfPredicate(predicate),
385
+ at: deps.now(),
386
+ },
387
+ /*
388
+ * An assertion has no element of its own — it observes, it does not act. The file it names
389
+ * is the one the LAST action touched, which is the code path that produced the state being
390
+ * asserted about. Already remembered on the session for exactly this reason: an assertion
391
+ * whose failure has nothing to point at still needs to name a file.
392
+ */
393
+ session.lastAct.source());
394
+ }
395
+ // Journal the verdict so a LATER turn can read what this one proved. A verdict that lives only
396
+ // in the response lives only in the agent's context window, which is the copy a compaction
397
+ // destroys — see runs/run-context.ts. Recorded WITHOUT an attribution window: this tool drives
398
+ // nothing, so no event it observed was caused by it.
399
+ session.recordAction(ReticleTool.ASSERT, asRecord(args), verdictEffect);
349
400
  return withControl(session, {
350
401
  ...decision,
351
- ...verdict,
402
+ ...annotateStarvedFailure(session, verdict),
352
403
  ...(contradictions.length > 0 ? { contradictions } : {}),
353
404
  // What the app did not tell Reticle, on the same rule the act path uses.
354
405
  ...(gaps.length > 0 ? { instrumentationGaps: gaps } : {}),
355
406
  ...advice,
356
407
  ...coverage,
357
- ...lastActSourceOnFailure(session, verdict.pass),
408
+ // The SAME pointer the journal keeps, not a second lookup — one verdict, one file:line.
409
+ ...(verdictEffect.source === undefined ? {} : { source: verdictEffect.source }),
358
410
  ...healthEnvelope(session),
359
411
  ...bufferEnvelope(session),
360
412
  });
@@ -365,12 +417,10 @@ export const OBSERVE_TOOLS = [
365
417
  example: { urlContains: '/api/todos', method: 'POST' },
366
418
  description: 'Filtered list of network calls. Fast path for "did POST /x return 200?". A zero-match filter returns a `hint` { totalInWindow, present[] } of the calls that DID fire, so a miss is diagnosable. Desktop IPC (`ipc://`) has no status code — the 200/500 there is derived, so filter on `ok` for those.',
367
419
  inputSchema: {
368
- since: z
369
- .number()
420
+ since: cursorSchema
370
421
  .optional()
371
422
  .describe('Cursor from a prior reticle_act — scopes the query to requests fired after that act.'),
372
- until: z
373
- .number()
423
+ until: cursorSchema
374
424
  .optional()
375
425
  .describe('Upper cursor bound — with `since`, the span between two acts.'),
376
426
  actionId: z
@@ -382,14 +432,12 @@ export const OBSERVE_TOOLS = [
382
432
  .optional()
383
433
  .describe('HTTP method filter: GET | POST | PUT | DELETE | PATCH etc.'),
384
434
  urlContains: z.string().optional().describe('Substring that the request URL must contain.'),
385
- status: z.number().optional().describe('HTTP status code filter (e.g. 200, 404, 500).'),
435
+ status: httpStatusSchema.optional().describe('HTTP status code filter (e.g. 200, 404, 500).'),
386
436
  ok: z
387
437
  .boolean()
388
438
  .optional()
389
439
  .describe('Outcome filter: false keeps only calls that FAILED, true only those that succeeded. The filter to use for desktop IPC (`ipc://`), whose status code is derived. A still-pending call matches neither.'),
390
- limit: z
391
- .number()
392
- .nonnegative()
440
+ limit: countSchema
393
441
  .optional()
394
442
  .describe('Keep only the most recent N matching calls (older are dropped and counted in droppedOldest) — cuts tokens on a wide window. Defaults to 200 when omitted; pass a higher number for more, or scope with since/until.'),
395
443
  bodies: z
@@ -457,21 +505,17 @@ export const OBSERVE_TOOLS = [
457
505
  level: consoleLevelEnum
458
506
  .optional()
459
507
  .describe(`Log level filter: ${CONSOLE_LEVEL_LIST}. Omit to return all levels.`),
460
- since: z
461
- .number()
508
+ since: cursorSchema
462
509
  .optional()
463
510
  .describe('Cursor from a prior reticle_act — scopes the query to log entries after that act.'),
464
- until: z
465
- .number()
511
+ until: cursorSchema
466
512
  .optional()
467
513
  .describe('Upper cursor bound — with `since`, the span between two acts.'),
468
514
  actionId: z
469
515
  .string()
470
516
  .optional()
471
517
  .describe('Keep only log entries attributed to this action — "what did action N log".'),
472
- limit: z
473
- .number()
474
- .nonnegative()
518
+ limit: countSchema
475
519
  .optional()
476
520
  .describe('Keep only the most recent N matching entries (older are dropped and counted in droppedOldest) — cuts tokens when a page spams the console. Defaults to 200 when omitted; pass a higher number for more, or scope with since/until.'),
477
521
  ...sessionIdShape,
@@ -4,8 +4,9 @@
4
4
  */
5
5
  import { resolveAnnotateTarget } from '../flows/annotate-target.js';
6
6
  import { z } from 'zod';
7
- import { EventType, ReticleCommand, REPLAY_PROGRAM_VERSION, SnapshotMode } from '@reticlehq/core';
7
+ import { EventType, ReticleCommand, REPLAY_PROGRAM_VERSION, SnapshotMode, StorageArea, } from '@reticlehq/core';
8
8
  import { ReticleTool } from './tool-names.js';
9
+ import { advanceMsSchema, depthSchema } from './numeric-bounds.js';
9
10
  import { proposeConsequences } from '../oracles/propose-consequences.js';
10
11
  import { replayProgram } from '../flows/replay.js';
11
12
  import { diffLines } from '../project/baselines.js';
@@ -15,6 +16,26 @@ import { buildReactionReport, summarizeReaction } from '../events/reaction.js';
15
16
  import { asString, asNumber, parseInteractive } from './tools-helpers.js';
16
17
  import { sessionIdShape, commandOrThrow, snapshotTree } from './tool-kit.js';
17
18
  import { bufferEnvelope } from '../session/session-health.js';
19
+ /** The route part of a session URL. A host belongs to the machine, not to the journey. */
20
+ /**
21
+ * The page a recording started on, as a NAVIGABLE path: pathname + hash.
22
+ *
23
+ * The hash matters and the pathname alone is not enough. Under a hash router every page has the
24
+ * document pathname `/`, so a recording made on `#/posts/12` stored `/`, the replay's start-path
25
+ * comparison saw `/` on both sides and never warned about drift, and the navigate it suggests
26
+ * pointed at the default route rather than the recorded one.
27
+ */
28
+ function pathnameOf(url) {
29
+ if (url === undefined)
30
+ return undefined;
31
+ try {
32
+ const parsed = new URL(url);
33
+ return `${parsed.pathname}${parsed.hash}`;
34
+ }
35
+ catch {
36
+ return undefined;
37
+ }
38
+ }
18
39
  /**
19
40
  * What record-stop says about a step that compiled to no anchor at all.
20
41
  *
@@ -141,7 +162,10 @@ export const READ_TOOLS = [
141
162
  const session = deps.sessions.resolve(asString(args['sessionId']));
142
163
  const name = asString(args['recordingName']) ?? 'default';
143
164
  const cursor = session.elapsed();
144
- deps.recordings.start(name, cursor);
165
+ // Where the journey begins, so a saved flow can navigate here before step 1 instead of
166
+ // replaying from wherever the page happens to be. Pathname only: a host or port belongs to
167
+ // the machine that recorded it, not to the journey.
168
+ deps.recordings.start(name, cursor, pathnameOf(session.url));
145
169
  return Promise.resolve({ recordingName: name, since: cursor });
146
170
  },
147
171
  },
@@ -181,6 +205,7 @@ export const READ_TOOLS = [
181
205
  name,
182
206
  version: REPLAY_PROGRAM_VERSION,
183
207
  steps: rec.steps,
208
+ ...(rec.startPath === undefined ? {} : { startPath: rec.startPath }),
184
209
  };
185
210
  deps.recordings.saveCompiled(program);
186
211
  const unstable = rec.steps.filter((s) => !s.stable).length;
@@ -282,8 +307,7 @@ export const READ_TOOLS = [
282
307
  .boolean()
283
308
  .optional()
284
309
  .describe('Freeze the fake clock. Time stops advancing until advanceMs or reset.'),
285
- advanceMs: z
286
- .number()
310
+ advanceMs: advanceMsSchema
287
311
  .optional()
288
312
  .describe('Fast-forward time by this many milliseconds — triggers debounces, toasts, auto-dismiss timers.'),
289
313
  reset: z.boolean().optional().describe('Restore the real clock.'),
@@ -318,10 +342,9 @@ export const READ_TOOLS = [
318
342
  .string()
319
343
  .optional()
320
344
  .describe("Dot-path into the store (e.g. 'captionCache.v3'). Numeric array indices are supported."),
321
- depth: z
322
- .number()
345
+ depth: depthSchema
323
346
  .optional()
324
- .describe('Collapse anything deeper than N levels to a size marker — avoids huge outputs for large stores.'),
347
+ .describe('Collapse anything deeper than N levels to a size marker — avoids huge outputs for large stores. A whole number of levels, 1 or more.'),
325
348
  ...sessionIdShape,
326
349
  },
327
350
  outputSchema: {
@@ -513,7 +536,7 @@ export const READ_TOOLS = [
513
536
  'diagnosable.',
514
537
  inputSchema: {
515
538
  area: z
516
- .enum(['local', 'session', 'cookies'])
539
+ .nativeEnum(StorageArea)
517
540
  .optional()
518
541
  .describe('Scope to one storage area. Omit to read all three.'),
519
542
  key: z
@@ -5,10 +5,32 @@
5
5
  * Split out of act-tools.ts along its natural seam: the act tools care only about the outcome
6
6
  * (`result` defined = it went native), never about provider availability, box resolution,
7
7
  * drag-target inspection or the reason taxonomy.
8
+ *
9
+ * Also hosts `rewriteUploadArgs` — the daemon-side path that lets an agent name a file on disk
10
+ * and have its REAL bytes reach the browser's `<input type="file">`. The browser SDK cannot read
11
+ * the filesystem; the daemon can. The rewrite happens here, before the ACT command crosses the
12
+ * bridge, so the browser side sees a normal `{ content, name, type }` call and `assertUploadArgs`
13
+ * keeps its invariant (no fabricated bytes, no silently-dropped keys).
14
+ *
15
+ * Trust boundary: scoped to the project root (one level above `deps.reticleRoot`), resolved
16
+ * through `realpath` so symlinks cannot escape it. Sensitive files (.env*, .git/, *.pem, id_*,
17
+ * .npmrc) are denied with a message that says why. The cap is derived from the bridge's own
18
+ * MAX_MESSAGE_BYTES with the base64 4/3 inflation factor applied, so the encoded payload always
19
+ * fits in one WebSocket frame.
8
20
  */
9
21
  import { ActionType, InputModeReason } from '@reticlehq/core';
10
22
  import type { Session } from '../session/session.js';
11
23
  import { type ToolDeps } from './tool-kit.js';
24
+ /**
25
+ * If the action is `upload` AND the inner args carry `path`, read the file from disk and rewrite
26
+ * the args to `{ content, name, type, __base64: true }` before the ACT command reaches the browser.
27
+ *
28
+ * Returns the (possibly rewritten) args object. All other actions are returned unchanged.
29
+ *
30
+ * This is the SINGLE interception point — called from session.command() so flow replay, crawl,
31
+ * and every other ACT dispatch site are covered without per-site wiring.
32
+ */
33
+ export declare function rewriteUploadArgs(deps: Pick<ToolDeps, 'fs' | 'reticleRoot'>, action: string, innerArgs: Record<string, unknown>): Promise<Record<string, unknown>>;
12
34
  interface RealActResult {
13
35
  /** Defined only on a successful native action; `undefined` means the synthetic path runs. */
14
36
  result: unknown;
@@ -18,11 +40,21 @@ interface RealActResult {
18
40
  /** Why we went synthetic despite a configured provider (field bug #2: never a silent fallback). */
19
41
  reason?: InputModeReason;
20
42
  }
43
+ /**
44
+ * Hover without a native pointer is a false success: synthetic mouseover reports dispatched and
45
+ * settled while CSS `:hover` never applies. Same refusal shape as contenteditable — name the gap
46
+ * rather than pretend the action ran.
47
+ */
48
+ export declare const HOVER_NEEDS_POINTER_MSG = "cannot hover without a real pointer \u2014 CSS :hover only applies to a native mouse move, never to a synthetic mouseover";
21
49
  /**
22
50
  * Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
23
51
  * `reason` when a provider is configured) whenever the synthetic path should run — no matching
24
52
  * page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
25
53
  * flagged with `fellBack`. `result` is defined only on a real success.
54
+ *
55
+ * Hover is the exception: it never returns synthetic. CSS `:hover` is not applied by
56
+ * `dispatchEvent`, so a synthetic success is the defect. The call either drives a real pointer
57
+ * or throws.
26
58
  */
27
59
  export declare function tryRealInput(deps: ToolDeps, session: Session, ref: string, action: ActionType, args: Record<string, unknown>): Promise<RealActResult>;
28
60
  export {};