@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
@@ -1,15 +1,11 @@
1
- import { normalizeQueryArgs } from './query-shape.js';
2
- import { resolveTargetRef } from './resolve-target.js';
3
- /**
4
- * Action tools — reticle_act, reticle_act_sequence, reticle_act_and_wait. Split out of tools.ts to keep
5
- * that file under the line cap and assembled back into the tool list there via ...ACT_TOOLS; the
6
- * native-input attempt itself lives in real-input-attempt.ts for the same reason.
7
- */
8
1
  import { z } from 'zod';
9
2
  import { aliasParam } from './alias-args.js';
10
- import { captureAct, compileSequenceStep } from '../flows/replay.js';
3
+ import { resolveSessionWithin } from '../session/resolve-within.js';
4
+ import { WALL_CLOCK } from '../session/wall-clock.js';
5
+ import { ACT_SEQUENCE_TOOL } from './act-sequence-tool.js';
6
+ import { timeoutMsSchema } from './numeric-bounds.js';
7
+ import { captureAct } from '../flows/replay.js';
11
8
  import { ActionType, ActionWarning, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, ReticleCommand, Verified, VerifiedReason, PredicateKind, } from '@reticlehq/core';
12
- import { assertNativeInputSupported } from './act-danger.js';
13
9
  import { leanActResult, mutatedWithin } from './act-view.js';
14
10
  import { ReticleTool } from './tool-names.js';
15
11
  import { buildReactionReport, summarizeReaction } from '../events/reaction.js';
@@ -18,28 +14,70 @@ import { causalSummary } from '../capsule/causal-summary.js';
18
14
  import { findContradictions } from '../events/contradictions.js';
19
15
  import { gapsForAction } from '../honesty/instrumentation-gaps.js';
20
16
  import { noteSessionGaps } from '../honesty/gap-ledger.js';
17
+ import { isChangeUndeclared } from '../honesty/undeclared-change.js';
18
+ import { intentDebt, openSessionIntents } from '../intent/open-intents.js';
19
+ import { dischargeInlineIntent, inlineVerdictId, linkInlineIntent, } from '../intent/inline-intent.js';
21
20
  import { declaresState } from '../events/predicate-asks.js';
22
21
  import { isStateUnwatched } from '../honesty/blind-spots.js';
23
22
  import { inFlightRequestLabels, repeatedRequestLabels, waitForInFlight, } from './settle-in-flight.js';
24
23
  import { waitForReaction } from './react-grace.js';
25
24
  import { decideVerified } from '../honesty/verified.js';
26
- import { declaredExpectations } from '../events/declared.js';
25
+ import { honestyForVerdict } from '../honesty/honesty.js';
26
+ import { declaredExpectations, declaresBodyIndependentChannel } from '../events/declared.js';
27
27
  import { readsDomState } from '../honesty/already-true.js';
28
28
  import { describeWaitTarget } from '../honesty/unsettled.js';
29
29
  import { saveFailedAssertCapsule } from './act-capsule.js';
30
30
  import { buildDivergenceCapsule } from '../capsule/capsule.js';
31
31
  import { predicateToExpectedLinks } from '../capsule/predicate-to-links.js';
32
32
  import { buildHonestyBlock } from '../honesty/honesty.js';
33
- import { buildCoverageStatement, blindSpotsFromState, transportGapNote, Coverage, impeachesCapture, } from '../honesty/blind-spots.js';
33
+ import { absenceBlindSpotNote, buildCoverageStatement, blindSpotsFromState, transportGapNote, Coverage, impeachesCapture, } from '../honesty/blind-spots.js';
34
34
  import { hasAcceptedWrite } from '../honesty/accepted-write.js';
35
35
  import { unreadWriteLabels } from '../honesty/unread-outcome.js';
36
36
  import { evaluatePredicate, waitForPredicate, provenExpectedLinks, PredicateSchema, } from '../events/predicate.js';
37
37
  import { healthEnvelope, refuseIfThrottled } from '../session/session-health.js';
38
38
  import { pausedShortCircuit, pausedOutputShape, withControl, PAUSED_NO_VERDICT, } from '../session/control-envelope.js';
39
39
  import { asString, asNumber, asRecord, sourceOf } from './tools-helpers.js';
40
- import { sessionIdShape } from './tool-kit.js';
40
+ import { dispatchAct, preflightAct } from './act-preflight.js';
41
+ import { followLostObservation } from './act-observation.js';
42
+ import { intentArg, sessionIdShape } from './tool-kit.js';
41
43
  import { asActionType, gradeOf } from './act-helpers.js';
42
- import { tryRealInput } from './real-input-attempt.js';
44
+ import { resolveActTarget } from './act-target.js';
45
+ import { tryRealInput, rewriteUploadArgs, HOVER_NEEDS_POINTER_MSG } from './real-input-attempt.js';
46
+ /**
47
+ * Single dispatch point for every ACT and ACT_SEQUENCE command.
48
+ *
49
+ * This is the seam the reviewer asked for: instead of wiring rewriteUploadArgs at three separate
50
+ * call sites (reticle_act, reticle_act_and_wait, reticle_act_sequence) we intercept once here,
51
+ * which also covers flow-replay, crawl, and any future dispatch site that goes through this helper.
52
+ *
53
+ * captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
54
+ * the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
55
+ * base64 to the browser as if it were an inline content call.
56
+ */
57
+ export async function actCommand(deps, session, actArgs, timeoutMs) {
58
+ const rewritten = await rewriteUploadArgs(deps, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
59
+ // Sequence and act_and_wait dispatch through here without the ACT handler's tryRealInput.
60
+ // A synthetic hover reports dispatched/settled while CSS :hover never applies — drive a real
61
+ // pointer when one is available, otherwise refuse rather than lie.
62
+ if (ActionType.HOVER === actArgs['action']) {
63
+ const ref = asString(actArgs['ref']);
64
+ if (ref === undefined)
65
+ throw new Error(HOVER_NEEDS_POINTER_MSG);
66
+ const real = await tryRealInput(deps, session, ref, ActionType.HOVER, actArgs);
67
+ if (real.result === undefined)
68
+ throw new Error(HOVER_NEEDS_POINTER_MSG);
69
+ return {
70
+ kind: 'command_result',
71
+ id: 'hover',
72
+ ok: true,
73
+ result: { dispatched: true, settled: real.settled, ...asRecord(real.result) },
74
+ };
75
+ }
76
+ const bridgeArgs = { ...actArgs, args: rewritten };
77
+ return timeoutMs !== undefined
78
+ ? session.command(ReticleCommand.ACT, bridgeArgs, timeoutMs)
79
+ : session.command(ReticleCommand.ACT, bridgeArgs);
80
+ }
43
81
  /**
44
82
  * Narrow the wire's `action` to a real ActionType, or undefined.
45
83
  *
@@ -60,41 +98,7 @@ import { tryRealInput } from './real-input-attempt.js';
60
98
  */
61
99
  const ACTION_TYPE_VALUES = Object.values(ActionType);
62
100
  const ACTION_TYPE_LIST = ACTION_TYPE_VALUES.join(' | ');
63
- const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
64
- /**
65
- * Resolve an action's element: an explicit `ref`, or a `target` query resolved in the SAME call.
66
- *
67
- * Requiring a ref meant every verification paid a `reticle_query` turn first just to learn one
68
- * string, and the advertised tool surface is re-sent on every turn — measured on the wire, a
69
- * two-turn verification spent 10,756 of 11,235 tokens on schema and 479 on the actual answers. The
70
- * lookup still happens; it just stops costing a round trip through the model.
71
- *
72
- * `ref` wins when both are given, because it is the more specific instruction and silently
73
- * preferring the query would act on something the caller did not name.
74
- */
75
- async function resolveActTarget(session, args) {
76
- const ref = asString(args['ref']);
77
- if (ref !== undefined && ref.length > 0)
78
- return { kind: 'ref', ref };
79
- const target = args['target'];
80
- if (target === undefined) {
81
- return {
82
- kind: 'error',
83
- message: 'pass `ref` (from reticle_query/reticle_snapshot) or `target` (e.g. { testid } or { role, name }).',
84
- };
85
- }
86
- const q = normalizeQueryArgs(asRecord(target));
87
- const out = await session.command(ReticleCommand.QUERY, {
88
- by: q['by'],
89
- value: q['value'],
90
- name: q['name'],
91
- scope: q['scope'],
92
- });
93
- if (!out.ok)
94
- return { kind: 'error', message: out.error ?? 'target query failed' };
95
- const elements = asRecord(out.result)['elements'];
96
- return resolveTargetRef(Array.isArray(elements) ? elements : []);
97
- }
101
+ export const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
98
102
  export const ACT_TOOLS = [
99
103
  {
100
104
  name: ReticleTool.ACT,
@@ -113,7 +117,7 @@ export const ACT_TOOLS = [
113
117
  args: z
114
118
  .record(z.unknown())
115
119
  .optional()
116
- .describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt — a Cmd+K), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { native: true } to force a trusted native click, { holdMs: N } to keep the pointer DOWN for N ms (hold-to-confirm controls; effect.heldMs reports what was achieved), { confirmDangerous: true } to allow a potentially destructive control — a permission gate, NOT a duration.'),
120
+ .describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt — a Cmd+K), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { native: true } to force a trusted native click, { holdMs: N } to keep the pointer DOWN for N ms (hold-to-confirm controls; effect.heldMs reports what was achieved), { confirmDangerous: true } to allow a potentially destructive control — a permission gate, NOT a duration. For upload: { path } is a path on disk (absolute or relative to the project root; the daemon reads the file and delivers real bytes to the file picker — this is the way to verify document-ingestion flows); or { name, content?, type? } to supply inline bytes directly.'),
117
121
  refuseWhenThrottled: z
118
122
  .boolean()
119
123
  .optional()
@@ -179,7 +183,7 @@ export const ACT_TOOLS = [
179
183
  settledOutcome = real.settled ?? undefined;
180
184
  // Native input reports no synthetic effect block, so nothing measured in-target: undefined
181
185
  // (the weaker empty-window test), never a fabricated zero.
182
- session.lastAct.markActed(since, action, undefined);
186
+ session.lastAct.markActed(since, action, undefined, asString(args['ref']));
183
187
  return withControl(session, {
184
188
  since,
185
189
  inputMode: InputMode.REAL,
@@ -190,7 +194,9 @@ export const ACT_TOOLS = [
190
194
  ...healthEnvelope(session),
191
195
  });
192
196
  }
193
- const result = await session.command(ReticleCommand.ACT, {
197
+ // actCommand is the single interception point: it rewrites upload+path args to real bytes
198
+ // before any ACT command crosses the bridge, covering this call site and all others.
199
+ const result = await actCommand(deps, session, {
194
200
  ref: targetRef.ref,
195
201
  action: args['action'],
196
202
  args: args['args'] ?? {},
@@ -205,7 +211,7 @@ export const ACT_TOOLS = [
205
211
  // Keep what only this call measured, so the observe that judges this window can ask whether
206
212
  // anything happened INSIDE the target — the one fact that separates a dead control from a
207
213
  // page that was merely busy with something else.
208
- session.lastAct.markActed(since, action, mutatedWithin(r));
214
+ session.lastAct.markActed(since, action, mutatedWithin(r), asString(args['ref']));
209
215
  return withControl(session, {
210
216
  since,
211
217
  inputMode: InputMode.SYNTHETIC,
@@ -225,127 +231,6 @@ export const ACT_TOOLS = [
225
231
  }
226
232
  },
227
233
  },
228
- {
229
- name: ReticleTool.ACT_SEQUENCE,
230
- // The example is required for a core tool, and this one carries weight: the measured loop it
231
- // replaces is literally a login form driven as three separate reticle_act calls (98 clicks and
232
- // 21 fills inside looping sessions, 2026-08-10/11). Showing fill -> fill -> click is showing the
233
- // exact shape an agent otherwise spends three round trips on.
234
- example: {
235
- steps: [
236
- { ref: 'e12', action: 'fill', args: { value: 'a@b.com' } },
237
- { ref: 'e13', action: 'fill', args: { value: 'hunter2' } },
238
- { ref: 'e14', action: 'click' },
239
- ],
240
- },
241
- 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).',
242
- inputSchema: {
243
- steps: z
244
- .array(z.record(z.unknown()))
245
- .describe('Ordered list of { ref, action, args? } objects. Each step is equivalent to one reticle_act call; put confirmDangerous:true in a destructive step args object.'),
246
- timeout_ms: z
247
- .number()
248
- .optional()
249
- .describe('Per-step timeout in milliseconds. Default: 8000. Each step gets this budget independently.'),
250
- ...sessionIdShape,
251
- },
252
- outputSchema: {
253
- since: z.number(),
254
- dispatched: z.boolean(),
255
- completed: z.number(),
256
- stalled_at: z.number().optional(),
257
- steps: z.array(z.record(z.unknown())).optional(),
258
- result: z.unknown().optional(),
259
- session: z
260
- .object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
261
- .optional(),
262
- // Short-circuits to pausedShortCircuit while paused — declare its fields (drained-once guidance).
263
- ...pausedOutputShape,
264
- },
265
- handler: async (deps, args) => {
266
- const session = deps.sessions.resolve(asString(args['sessionId']));
267
- const paused = pausedShortCircuit(session);
268
- if (paused !== undefined)
269
- return paused;
270
- const since = session.elapsed();
271
- session.beginAction(ReticleTool.ACT_SEQUENCE, asRecord(args));
272
- try {
273
- const inputSteps = Array.isArray(args['steps']) ? args['steps'] : [];
274
- const perStepTimeout = 'number' === typeof args['timeout_ms'] ? args['timeout_ms'] : 8000;
275
- const stepResults = [];
276
- let stalledAt;
277
- // DIVERGENCE: live sends N individual ACT commands (for per-step timeout + progress);
278
- // replay sends one batched ACT_SEQUENCE command (flows/replay.ts:294). A bug in either is
279
- // invisible from the other — cover both when changing sequence semantics.
280
- for (let i = 0; i < inputSteps.length; i++) {
281
- const step = asRecord(inputSteps[i]);
282
- try {
283
- const result = await session.command(ReticleCommand.ACT, { ref: step['ref'], action: step['action'], args: step['args'] ?? {} }, perStepTimeout);
284
- if (!result.ok) {
285
- stalledAt = i;
286
- stepResults.push({
287
- ref: step['ref'],
288
- action: step['action'],
289
- dispatched: false,
290
- error: result.error ?? 'step failed',
291
- });
292
- break;
293
- }
294
- const r = asRecord(result.result);
295
- const stepResult = {
296
- ref: r['ref'] ?? step['ref'],
297
- action: r['action'] ?? step['action'],
298
- dispatched: r['dispatched'] ?? true,
299
- settled: r['settled'] ?? null,
300
- settleReason: r['settleReason'] ?? null,
301
- };
302
- if (r['testid'] !== undefined)
303
- stepResult['testid'] = r['testid'];
304
- if (r['component'] !== undefined)
305
- stepResult['component'] = r['component'];
306
- if (r['role'] !== undefined)
307
- stepResult['role'] = r['role'];
308
- if (r['name'] !== undefined)
309
- stepResult['name'] = r['name'];
310
- if (r['source'] !== undefined)
311
- stepResult['source'] = r['source'];
312
- if (r['warning'] !== undefined)
313
- stepResult['warning'] = r['warning'];
314
- stepResults.push(stepResult);
315
- }
316
- catch (err) {
317
- stalledAt = i;
318
- stepResults.push({
319
- ref: step['ref'],
320
- action: step['action'],
321
- dispatched: null,
322
- timedOut: true,
323
- error: err instanceof Error ? err.message : 'step timed out',
324
- });
325
- break;
326
- }
327
- }
328
- const completed = stalledAt ?? inputSteps.length;
329
- if (completed > 0) {
330
- session.lastAct.markActed(since, undefined, undefined);
331
- }
332
- if (deps.recordings.active().length > 0 && stalledAt === undefined) {
333
- deps.recordings.capture(compileSequenceStep(args, { count: inputSteps.length, steps: stepResults }));
334
- }
335
- return withControl(session, {
336
- since,
337
- dispatched: completed > 0,
338
- completed,
339
- ...(stalledAt !== undefined ? { stalled_at: stalledAt } : {}),
340
- steps: stepResults,
341
- ...healthEnvelope(session),
342
- });
343
- }
344
- finally {
345
- session.finishAction();
346
- }
347
- },
348
- },
349
234
  {
350
235
  name: ReticleTool.ACT_AND_WAIT,
351
236
  example: {
@@ -372,17 +257,17 @@ export const ACT_TOOLS = [
372
257
  args: z
373
258
  .record(z.unknown())
374
259
  .optional()
375
- .describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { confirmDangerous: true } for a potentially destructive control.'),
260
+ .describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { confirmDangerous: true } for a potentially destructive control. For upload: { path } is a path on disk (absolute or relative to project root; daemon reads real bytes) or { name, content?, type? } for inline bytes.'),
376
261
  predicate: PredicateSchema.optional().describe('Alias for `until` (the name reticle_assert / reticle_wait_for use).'),
377
262
  until: PredicateSchema.optional().describe('Predicate to wait for after the action completes (same shape as reticle_assert). OMIT to wait for the page to SETTLE — network + DOM idle — the deterministic default instead of a sleep. To assert a consequence AND settle, allOf them: { kind: "allOf", predicates: [<your predicate>, { kind: "settled" }] }.'),
378
- timeout_ms: z
379
- .number()
263
+ timeout_ms: timeoutMsSchema
380
264
  .optional()
381
265
  .describe('Maximum wait time in milliseconds. 0 = evaluate once without waiting. Default: 4000.'),
382
266
  refuseWhenThrottled: z
383
267
  .boolean()
384
268
  .optional()
385
269
  .describe('Throw if the tab is throttled. Default: false.'),
270
+ intent: intentArg,
386
271
  ...sessionIdShape,
387
272
  },
388
273
  outputSchema: {
@@ -397,6 +282,10 @@ export const ACT_TOOLS = [
397
282
  .boolean()
398
283
  .optional()
399
284
  .describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
285
+ inconclusive: z
286
+ .string()
287
+ .optional()
288
+ .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".'),
400
289
  // The STRUCTURED cause — observed / expected / assertion — is what the repair literature ranks
401
290
  // above the prose failureReason (structured feedback beat narrative by 10.5pp) and above a bare
402
291
  // pointer. `verdict` is `await waitForPredicate(...)`, whose EvalResult carries these on a
@@ -446,6 +335,10 @@ export const ACT_TOOLS = [
446
335
  since: z
447
336
  .number()
448
337
  .describe('Cursor for this act — pass to reticle_observe/reticle_assert for the full timeline.'),
338
+ sessionId: z
339
+ .string()
340
+ .optional()
341
+ .describe('The session that answered, when a full-document navigation replaced the one that was acted on. Absent when the original session survived.'),
449
342
  session: z
450
343
  .object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
451
344
  .optional(),
@@ -453,7 +346,12 @@ export const ACT_TOOLS = [
453
346
  ...pausedOutputShape,
454
347
  },
455
348
  handler: async (deps, args) => {
456
- const session = deps.sessions.resolve(asString(args['sessionId']));
349
+ // Spend the caller's budget waiting for the APP too, not only for the consequence. This tool
350
+ // is the one an agent reaches for straight after `init` and a dev-server restart, which is
351
+ // exactly when there is no session yet and one is seconds away. See resolve-within.
352
+ let session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS, WALL_CLOCK);
353
+ const acted = session;
354
+ const actedSessionId = session.id;
457
355
  // Live-control: refuse to drive the page (no act, no predicate eval) while paused.
458
356
  //
459
357
  // A VERDICT rides out with the refusal. This is the one tool here that promises `verified`,
@@ -472,20 +370,28 @@ export const ACT_TOOLS = [
472
370
  ? parsePredicate(withUntil['until'])
473
371
  : { kind: PredicateKind.SETTLED };
474
372
  const timeout = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
475
- // Before anything is driven: this path cannot honour a native-input request, and taking the
476
- // argument and ignoring it told the agent its trusted click had happened. See act-danger.
477
- assertNativeInputSupported(asRecord(args['args']));
373
+ // An intent declared here lands in the ledger BEFORE the verdict is drawn, which is what makes
374
+ // the undeclared-change gap silent on THIS verdict rather than the next one: it reads the
375
+ // ledger below and finds something open. The discharge comes after that read.
376
+ const intentId = await linkInlineIntent(deps, asString(args['sessionId']), asString(args['intent']), PredicateKind.SETTLED === until.kind ? undefined : until);
377
+ // Everything refusable without touching the page — see act-preflight.ts.
378
+ preflightAct(asRecord(args['args']), until);
478
379
  // Resolve `target` to a ref BEFORE the action window opens, so the lookup is not attributed to
479
380
  // the act and cannot be mistaken for something the action caused.
480
381
  const resolved = await resolveActTarget(session, args);
481
382
  if ('error' === resolved.kind)
482
383
  throw new Error(resolved.message);
483
- const since = session.elapsed();
384
+ let since = session.elapsed();
385
+ const actedSince = since;
484
386
  // The cursor + effect are marked after the act dispatches (below) — a refused act leaves none.
485
387
  // The attribution window stays open across the settle wait below, so post-dispatch async events
486
388
  // (the whole point of act_and_wait) attribute to this action. finishAction fires after the wait.
487
389
  session.beginAction(ReticleTool.ACT_AND_WAIT, asRecord(args));
488
390
  let settledOutcome;
391
+ // The verdict, written into the action record so a LATER turn can read what this one proved.
392
+ // A verdict that lives only in the response lives only in the agent's context window, which is
393
+ // exactly the copy a compaction destroys — see runs/run-context.ts.
394
+ let verdictEffect;
489
395
  // Was the declared consequence ALREADY TRUE? Only asked for predicates that read live DOM
490
396
  // state — event-based ones are floored at this act's cursor and cannot be satisfied by the
491
397
  // past, so they need no pre-check and pay nothing. One extra query, on the path where a green
@@ -494,22 +400,48 @@ export const ACT_TOOLS = [
494
400
  ? (await evaluatePredicate(session, until, since, false)).pass
495
401
  : false;
496
402
  try {
497
- const actResult = await session.command(ReticleCommand.ACT, {
403
+ // actCommand is the single interception point for upload+path rewrite.
404
+ //
405
+ // A replacement can land BETWEEN resolving the target and dispatching, and the tool used to
406
+ // throw that transport fact at the agent verbatim: no verdict at all, from the layer whose
407
+ // whole job is to answer in verdicts, worded as though the app were at fault. `dispatchAct`
408
+ // returns null instead (see act-preflight.ts for why a write is never re-sent), and the
409
+ // successor block below then asks whether the consequence held on the NEW document — a
410
+ // green if it did, an honest observation_lost if it did not.
411
+ const actResult = await dispatchAct(() => actCommand(deps, session, {
498
412
  ref: resolved.ref,
499
413
  action: args['action'],
500
414
  args: args['args'] ?? {},
501
- });
502
- if (!actResult.ok)
503
- throw new Error(actResult.error ?? 'act failed');
504
- captureAct(deps.recordings, args, actResult.result);
505
- // Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement also
506
- // stops the spread below from inheriting an earlier reticle_act's action and mutation count.
507
- session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)));
415
+ }));
416
+ if (actResult !== null) {
417
+ if (!actResult.ok)
418
+ throw new Error(actResult.error ?? 'act failed');
419
+ captureAct(deps.recordings, args, actResult.result);
420
+ // Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement
421
+ // also stops the spread below from inheriting an earlier reticle_act's action and
422
+ // mutation count.
423
+ session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)), asString(args['ref']));
424
+ }
508
425
  // Honesty: floor the predicate at this act's cursor so a stale buffered event can't satisfy it.
509
426
  const predicateStarted = session.elapsed();
510
- const verdict = timeout > 0
511
- ? await waitForPredicate(session, until, timeout, since)
512
- : await evaluatePredicate(session, until, since);
427
+ let verdict = null === actResult
428
+ ? { pass: false, observationLost: true }
429
+ : timeout > 0
430
+ ? await waitForPredicate(session, until, timeout, since)
431
+ : await evaluatePredicate(session, until, since);
432
+ // The SDK may have gone away mid-act — see act-observation.ts.
433
+ const followed = await followLostObservation({
434
+ sessions: deps.sessions,
435
+ session,
436
+ verdict,
437
+ timeout,
438
+ predicateStarted,
439
+ reevaluate: (next, budget) => waitForPredicate(next, until, budget, 0),
440
+ });
441
+ if (followed.followed)
442
+ since = 0;
443
+ session = followed.session;
444
+ verdict = followed.verdict;
513
445
  // The predicate resolves the INSTANT it holds, which on an optimistically-navigating app is
514
446
  // while the write is still in flight — so the verdict was taken over a window the app had not
515
447
  // finished, and came back `unknown / unsettled` asking the CALLER to re-check. A login that
@@ -539,7 +471,7 @@ export const ACT_TOOLS = [
539
471
  // moved after it — and short enough that a genuinely dropped response is still reported.
540
472
  await waitForReaction(session, since, spent(), sleep);
541
473
  }
542
- const r = asRecord(actResult.result);
474
+ const r = asRecord(actResult?.result);
543
475
  if ('boolean' === typeof r['settled'])
544
476
  settledOutcome = r['settled'];
545
477
  // Where the acted element is written. Captured at act time alongside the anchor, so it is
@@ -547,7 +479,8 @@ export const ACT_TOOLS = [
547
479
  const actedSource = sourceOf(r['source']);
548
480
  // Remembered on the session so a LATER assertion can name a file even when its failure has no
549
481
  // element to point at — a signal that never fired, a request that was never made.
550
- session.lastAct.markSource(actedSource === undefined ? undefined : `${actedSource.file}:${String(actedSource.line)}`);
482
+ const actedSourceLabel = actedSource === undefined ? undefined : `${actedSource.file}:${String(actedSource.line)}`;
483
+ session.lastAct.markSource(actedSourceLabel);
551
484
  const windowEvents = session.eventsSince(since);
552
485
  const trace = summarizeReaction(buildReactionReport(windowEvents, session.elapsed() - since));
553
486
  // The bounded Tier-1 causal summary — net/console/state/storage diffs the trace's counts miss.
@@ -565,8 +498,9 @@ export const ACT_TOOLS = [
565
498
  // stronger than this block. Grade from the strongest asserted consequence; integrity from evictions.
566
499
  // Coverage: cross-origin frames / other blind spots the SDK reported during this window mean the
567
500
  // verdict didn't see everything — say so, never imply full coverage.
568
- const spots = blindSpotsFromState(session.blindSpots());
501
+ const spots = blindSpotsFromState(session.blindSpots(), session.runtime);
569
502
  const coverage = buildCoverageStatement(spots);
503
+ const absenceBlindSpot = absenceBlindSpotNote(until, spots);
570
504
  // Nothing subscribed ⇒ the state channel is dark, and the summary must say so rather than
571
505
  // report an empty diff list that reads like a fact about the app. See CausalSummary.
572
506
  const stateUnwatched = isStateUnwatched(spots);
@@ -590,8 +524,11 @@ export const ACT_TOOLS = [
590
524
  ...(gapNote === undefined ? [] : [CaptureLoss.TRANSPORT_GAP]),
591
525
  ...(impeaching.note === undefined ? [] : [CaptureLoss.BLIND_SPOT]),
592
526
  ];
527
+ // Named because the discharge below records the same grade the verdict reports, rather than a
528
+ // second reading of the same evidence that could drift from it.
529
+ const grade = gradeOf(gradedLinks);
593
530
  const honesty = buildHonestyBlock({
594
- grade: gradeOf(gradedLinks),
531
+ grade,
595
532
  attribution: 'window',
596
533
  // Did the buffer lose scarce evidence FROM THIS WINDOW — not "did it evict anything while
597
534
  // the action ran", which was the previous rule and which is true on essentially every live
@@ -601,6 +538,7 @@ export const ACT_TOOLS = [
601
538
  // evictions that happened outside the window they impeached.
602
539
  truncated: bufferLost,
603
540
  coveragePartial: Coverage.PARTIAL === coverage.coverage,
541
+ ...(coverage.note === undefined ? {} : { coverageNote: coverage.note }),
604
542
  // Settlement no longer vetoes a declared consequence that held, so the fact is carried
605
543
  // here instead of only in the verdict it used to decide. Omitted when never measured.
606
544
  ...(settledOutcome === undefined ? {} : { settled: settledOutcome }),
@@ -613,7 +551,11 @@ export const ACT_TOOLS = [
613
551
  capsule,
614
552
  links,
615
553
  args,
616
- actResult,
554
+ // The session actually driven — after any navigation follow — so the capsule is filed
555
+ // against the codebase that produced the failure, not wherever the daemon stands.
556
+ root: session.artifactRoot,
557
+ // No dispatch result to capture when the transport was displaced mid-write.
558
+ actResult: actResult ?? {},
617
559
  ...(actedSource === undefined ? {} : { actedSource }),
618
560
  });
619
561
  // Pass the action: an EMPTY window then reads as "the target does not react" rather than as a
@@ -644,6 +586,9 @@ export const ACT_TOOLS = [
644
586
  // not evidence the destination rendered either — `alreadyTrue` decides that, once.
645
587
  renderProved: verdict.pass && !alreadyTrue && declared.rendersContent,
646
588
  ...session.lastAct.effect(),
589
+ currentDocumentId: session.currentDocumentId,
590
+ currentEditEpoch: session.currentEditEpoch,
591
+ appOrigin: session.url,
647
592
  });
648
593
  // The single field an agent reads. Everything below it is the evidence it was derived from;
649
594
  // this is the only one that has to be interpreted, and now it interprets itself.
@@ -656,6 +601,9 @@ export const ACT_TOOLS = [
656
601
  // overriding it — see `declaredConsequence`. An explicit `{ kind: "settled" }` is not a
657
602
  // declaration about the app's behaviour, it IS the idle wait, so it does not count.
658
603
  declaredConsequence: until.kind !== PredicateKind.SETTLED,
604
+ // A body-independent declaration that held is a channel the unread payload does not own.
605
+ // Omit when false: a net-only `until` must still hit `outcome_unread`.
606
+ ...(declaresBodyIndependentChannel(until) ? { independentOfBody: true } : {}),
659
607
  ...(alreadyTrue ? { alreadyTrue } : {}),
660
608
  // An assertion nobody could evaluate must not be reported as one the app failed.
661
609
  ...(verdict.inconclusive === undefined ? {} : { inconclusive: verdict.inconclusive }),
@@ -663,6 +611,7 @@ export const ACT_TOOLS = [
663
611
  // the measured false red: a reload mid-wait, graded assertion_failed at the clicked
664
612
  // component's own file and line.
665
613
  ...(true === verdict.observationLost ? { observationLost: true } : {}),
614
+ ...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
666
615
  honesty,
667
616
  contradictions,
668
617
  ...(outcomePending ? { outcomePending } : {}),
@@ -683,32 +632,72 @@ export const ACT_TOOLS = [
683
632
  // Computed once: the verdict block reports it, and the instrumentation gaps are a second
684
633
  // reading of the same evidence rather than a new observation.
685
634
  const actionSummary = causalSummary(windowEvents, { stateUnwatched });
635
+ // Asked of every verdict drawn after an observed edit, not once per edit — see
636
+ // isChangeUndeclared for why repeating it is disclosure rather than nagging.
637
+ // Read ONCE and used twice: `changeUndeclared` asks whether the ledger is empty, and the
638
+ // undischarged-intent gap asks how much it still holds. Two reads would be two chances for
639
+ // them to disagree about the same file.
640
+ const openIntents = await openSessionIntents(deps, asString(args['sessionId']));
641
+ const changeUndeclared = await isChangeUndeclared(session.currentEditEpoch, () => Promise.resolve(openIntents));
686
642
  const gaps = gapsForAction({
687
643
  pass: verdict.pass,
688
644
  proved: decision.verifiedReason === VerifiedReason.PROVED,
689
- sourceKnown: actedSource !== undefined,
645
+ changeUndeclared,
646
+ source: actedSourceLabel,
690
647
  ref: asString(args['ref']),
691
648
  stateAsked: declaresState(until),
692
649
  stateUnwatched,
650
+ // What the app DECLARED, so an under-instrumented one is told without having to be asked.
651
+ hasCapabilities: session.hasCapabilities,
652
+ // What the run still owes. A green that leaves this above zero is not the same as done.
653
+ // MINUS the one this verdict is about to discharge.
654
+ //
655
+ // The discharge happens below, after the gaps are built, so a straight `openIntents.length`
656
+ // counts the intent this very call proves. Measured live on the first drive: an inline
657
+ // intent was declared, asserted and PROVED by the same verdict, and the result still said
658
+ // "1 declared intent(s) are still unproved" while the ledger recorded it `proved`. A gap
659
+ // that fires on the one path doing everything right is noise, and noise is what gets
660
+ // filtered out — taking the honest gaps with it.
661
+ ...intentDebt(openIntents, intentId !== undefined && Verified.YES === decision.verified ? intentId : undefined, deps.now()),
693
662
  domMutated: (session.lastAct.effect().mutatedWithin ?? 0) > 0,
694
663
  signalsFired: actionSummary.signals.length,
695
664
  routeChanged: actionSummary.route !== undefined,
696
665
  routeSignalFired: actionSummary.signals.some((name) => name.startsWith('route')),
697
666
  });
667
+ // The verdict IS the proof attempt, so a green one discharges the intent it was drawn for.
668
+ // Only a green: a red proved nothing, and `dischargeIntent` refuses an unbound intent anyway,
669
+ // so a bare settle leaves it open rather than collecting a proof nothing earned. The id is
670
+ // checked here rather than only inside the helper so a caller that declared no intent touches
671
+ // nothing at all, not even the clock.
672
+ if (intentId !== undefined && Verified.YES === decision.verified) {
673
+ await dischargeInlineIntent(deps, asString(args['sessionId']), intentId, {
674
+ verdictId: inlineVerdictId(ReticleTool.ACT_AND_WAIT, deps.now()),
675
+ grade,
676
+ at: deps.now(),
677
+ },
678
+ // Where the acted element is written, so the record can name a file somebody would open
679
+ // to change the thing it describes.
680
+ actedSourceLabel);
681
+ }
682
+ verdictEffect = {
683
+ claim: describeWaitTarget(until),
684
+ verified: decision.verified,
685
+ ...(actedSourceLabel === undefined ? {} : { source: actedSourceLabel }),
686
+ };
698
687
  // Recorded on the session, so a later "am I done?" can answer with what is STILL missing
699
688
  // rather than with everything that was ever missing. An empty list closes a gap, which is
700
689
  // why it is noted rather than skipped.
701
690
  noteSessionGaps(session, gaps);
702
691
  return withControl(session, {
703
692
  ...decision,
704
- effect: leanActResult(actResult.result),
693
+ // An unobserved act has no effect to report, and inventing an empty one would read as
694
+ // "the page did nothing" — a claim about the app, from a call that never saw it.
695
+ ...(null === actResult ? {} : { effect: leanActResult(actResult.result) }),
705
696
  verdict,
706
697
  // Promoted out of `effect` on red only. On green nobody needs it and it is noise; on red it
707
698
  // is the first thing the agent wants, and burying a file:line inside the effect block is
708
699
  // most of the way to not reporting it at all.
709
- ...(verdict.pass || actedSource === undefined
710
- ? {}
711
- : { source: `${actedSource.file}:${String(actedSource.line)}` }),
700
+ ...(verdict.pass || actedSourceLabel === undefined ? {} : { source: actedSourceLabel }),
712
701
  trace,
713
702
  ...(capsuleSaved === undefined ? {} : { capsuleSaved }),
714
703
  // The window cannot say whether anything was WATCHING state — that is a level fact the
@@ -727,15 +716,18 @@ export const ACT_TOOLS = [
727
716
  // agent cannot miss it by not asking. Omitted entirely when clean, so a healthy action
728
717
  // pays nothing.
729
718
  ...(contradictions.length > 0 ? { contradictions } : {}),
730
- honesty,
719
+ honesty: honestyForVerdict(String(decision.verified), honesty),
731
720
  ...(capsule === undefined ? {} : { capsule }),
732
721
  since,
722
+ ...(session.id === actedSessionId ? {} : { sessionId: session.id }),
733
723
  ...healthEnvelope(session),
734
724
  });
735
725
  }
736
726
  finally {
737
- session.finishAction(undefined, settledOutcome, true === settledOutcome ? session.elapsed() - since : undefined);
727
+ acted.finishAction(verdictEffect, settledOutcome, true === settledOutcome ? acted.elapsed() - actedSince : undefined);
738
728
  }
739
729
  },
740
730
  },
731
+ // Split into its own module for size; still shipped as one of the acting tools.
732
+ ACT_SEQUENCE_TOOL,
741
733
  ];