@reticlehq/server 3.7.0 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (578) hide show
  1. package/SKILL.md +59 -68
  2. package/bin/reticle.js +9 -2
  3. package/dist/command/cli/adhoc-suite.js +1 -1
  4. package/dist/command/cli/adhoc-verdict.d.ts +12 -0
  5. package/dist/command/cli/adhoc-verdict.js +62 -4
  6. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  7. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  8. package/dist/command/cli/auth/cloud-session.d.ts +11 -19
  9. package/dist/command/cli/auth/cloud-session.js +23 -0
  10. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  11. package/dist/command/cli/cli-doctor.js +66 -21
  12. package/dist/command/cli/cli-flow-commands.js +53 -11
  13. package/dist/command/cli/cli-kill.d.ts +8 -0
  14. package/dist/command/cli/cli-kill.js +43 -3
  15. package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
  16. package/dist/command/cli/cli-parse-feedback.js +13 -1
  17. package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
  18. package/dist/command/cli/cli-parse-grammar.js +1 -6
  19. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  20. package/dist/command/cli/cli-parse-serve.js +124 -0
  21. package/dist/command/cli/cli-parse.d.ts +12 -11
  22. package/dist/command/cli/cli-parse.js +100 -123
  23. package/dist/command/cli/cli-usage.d.ts +0 -11
  24. package/dist/command/cli/cli-usage.js +43 -16
  25. package/dist/command/cli/cli-verify.d.ts +1 -1
  26. package/dist/command/cli/cli-verify.js +29 -14
  27. package/dist/command/cli/cloud-cli.js +27 -9
  28. package/dist/command/cli/cloud-kit.js +3 -3
  29. package/dist/command/cli/cloud-link.d.ts +1 -20
  30. package/dist/command/cli/cloud-link.js +2 -0
  31. package/dist/command/cli/cloud-login.d.ts +6 -2
  32. package/dist/command/cli/cloud-login.js +13 -41
  33. package/dist/command/cli/config/checkout.d.ts +10 -0
  34. package/dist/command/cli/config/checkout.js +78 -0
  35. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  36. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  37. package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
  38. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  39. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  40. package/dist/command/cli/drive/drive-attach.d.ts +5 -0
  41. package/dist/command/cli/drive/drive-attach.js +21 -1
  42. package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
  43. package/dist/command/cli/hook/codex-transcript.js +224 -0
  44. package/dist/command/cli/hook/episode-structure.d.ts +24 -0
  45. package/dist/command/cli/hook/episode-structure.js +138 -0
  46. package/dist/command/cli/hook/hook-command.d.ts +9 -0
  47. package/dist/command/cli/hook/hook-command.js +211 -0
  48. package/dist/command/cli/hook/hook-fast.d.ts +31 -0
  49. package/dist/command/cli/hook/hook-fast.js +136 -0
  50. package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
  51. package/dist/command/cli/hook/prompt-hook.js +199 -0
  52. package/dist/command/cli/hook/tool-hook.d.ts +21 -0
  53. package/dist/command/cli/hook/tool-hook.js +259 -0
  54. package/dist/command/cli/launch/cli-launch.d.ts +2 -0
  55. package/dist/command/cli/launch/cli-launch.js +22 -2
  56. package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
  57. package/dist/command/cli/mcp-command.d.ts +9 -0
  58. package/dist/command/cli/mcp-command.js +127 -41
  59. package/dist/command/cli/open-navigate.d.ts +43 -0
  60. package/dist/command/cli/open-navigate.js +85 -0
  61. package/dist/command/cli/ports/port-holder.d.ts +16 -4
  62. package/dist/command/cli/ports/port-holder.js +58 -12
  63. package/dist/command/cli/ports/resolve/cli-port.js +18 -2
  64. package/dist/command/cli/project-name.d.ts +1 -7
  65. package/dist/command/cli/project-name.js +1 -0
  66. package/dist/command/cli/report-command.d.ts +8 -2
  67. package/dist/command/cli/report-command.js +95 -18
  68. package/dist/command/cli/status-fields.d.ts +9 -2
  69. package/dist/command/cli/status-fields.js +148 -4
  70. package/dist/command/cli/try-command.d.ts +3 -4
  71. package/dist/command/cli/try-command.js +6 -11
  72. package/dist/command/cli/verify-results.d.ts +4 -1
  73. package/dist/command/cli/verify-results.js +3 -1
  74. package/dist/command/cli.d.ts +1 -7
  75. package/dist/command/cli.js +79 -160
  76. package/dist/command/daemon/daemon-resilience.d.ts +6 -1
  77. package/dist/command/daemon/daemon-resilience.js +31 -18
  78. package/dist/command/daemon/daemon.d.ts +11 -0
  79. package/dist/command/daemon/daemon.js +70 -2
  80. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
  81. package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
  82. package/dist/command/daemon/wake-decision.js +4 -2
  83. package/dist/command/daemon/win32-escape.d.ts +32 -0
  84. package/dist/command/daemon/win32-escape.js +119 -0
  85. package/dist/command/setup/agent-configs.d.ts +9 -0
  86. package/dist/command/setup/agent-configs.js +9 -0
  87. package/dist/command/setup/auto-approve.d.ts +10 -3
  88. package/dist/command/setup/auto-approve.js +51 -3
  89. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  90. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  91. package/dist/command/setup/bringup/ensure-daemon.js +4 -7
  92. package/dist/command/setup/init/init-host.js +6 -0
  93. package/dist/command/setup/init/init-port.js +5 -4
  94. package/dist/command/setup/init/init-runtime.js +7 -1
  95. package/dist/command/setup/node-effects.d.ts +8 -0
  96. package/dist/command/setup/node-effects.js +36 -4
  97. package/dist/command/setup/probe/dev-port.d.ts +26 -0
  98. package/dist/command/setup/probe/dev-port.js +117 -0
  99. package/dist/command/setup/probe/page-probe.d.ts +1 -1
  100. package/dist/command/setup/probe/page-probe.js +11 -3
  101. package/dist/command/setup/remaining-steps.d.ts +0 -7
  102. package/dist/command/setup/remaining-steps.js +3 -2
  103. package/dist/command/setup/run-setup.d.ts +11 -0
  104. package/dist/command/setup/run-setup.js +33 -5
  105. package/dist/command/setup/setup-command.d.ts +2 -0
  106. package/dist/command/setup/setup-command.js +22 -4
  107. package/dist/command/update/updater.d.ts +1 -6
  108. package/dist/command/update/updater.js +4 -5
  109. package/dist/command/update/version-seen.d.ts +24 -0
  110. package/dist/command/update/version-seen.js +65 -0
  111. package/dist/command/version/peer-announce.d.ts +9 -1
  112. package/dist/command/version/peer-announce.js +25 -2
  113. package/dist/command/version/sdk-fix.d.ts +5 -6
  114. package/dist/command/version/sdk-fix.js +17 -32
  115. package/dist/command/version/version-skew.d.ts +16 -1
  116. package/dist/command/version/version-skew.js +84 -10
  117. package/dist/features/crawl/crawl-tools.js +2 -2
  118. package/dist/features/crawl/crawl.js +2 -0
  119. package/dist/features/exhaust/ledger.d.ts +15 -96
  120. package/dist/features/exhaust/ledger.js +3 -3
  121. package/dist/features/harness/drive-runs.d.ts +28 -4
  122. package/dist/features/harness/drive-runs.js +99 -7
  123. package/dist/features/harness/drivers.d.ts +1 -1
  124. package/dist/features/harness/drivers.js +1 -1
  125. package/dist/features/harness/harness.d.ts +5 -0
  126. package/dist/features/harness/harness.js +24 -12
  127. package/dist/features/harness/platform/platform-drives.d.ts +7 -1
  128. package/dist/features/harness/platform/platform-drives.js +12 -7
  129. package/dist/features/harness/platform/refusal.d.ts +1 -1
  130. package/dist/features/harness/platform/refusal.js +4 -4
  131. package/dist/features/harness/platform/remote-drive.js +70 -28
  132. package/dist/features/harness/platform/server-driver.js +22 -1
  133. package/dist/features/harness/platform-config.d.ts +1 -10
  134. package/dist/features/harness/platform-config.js +0 -20
  135. package/dist/features/license/license.d.ts +2 -14
  136. package/dist/features/visual/step-shots.d.ts +33 -1
  137. package/dist/features/visual/step-shots.js +155 -1
  138. package/dist/features/visual/visual-tools.js +12 -4
  139. package/dist/hooks/coding-agents.d.ts +6 -0
  140. package/dist/hooks/coding-agents.js +24 -3
  141. package/dist/hooks/episode-stamp.d.ts +32 -0
  142. package/dist/hooks/episode-stamp.js +61 -0
  143. package/dist/hooks/hook-commands.js +19 -9
  144. package/dist/index.d.ts +5 -1
  145. package/dist/index.js +66 -24
  146. package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
  147. package/dist/judgement/app-graph/journal-steps.js +92 -0
  148. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  149. package/dist/judgement/domain/domain-model.js +1 -10
  150. package/dist/judgement/domain/domain-tools.js +4 -2
  151. package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
  152. package/dist/judgement/runs/artifact/run-store.js +153 -28
  153. package/dist/judgement/runs/default-run-id.d.ts +3 -1
  154. package/dist/judgement/runs/default-run-id.js +15 -3
  155. package/dist/judgement/runs/drive-run.d.ts +3 -3
  156. package/dist/judgement/runs/drive-run.js +11 -7
  157. package/dist/judgement/runs/run-ledger.d.ts +21 -0
  158. package/dist/judgement/runs/run-ledger.js +143 -0
  159. package/dist/judgement/runs/runner-port.d.ts +1 -1
  160. package/dist/judgement/runs/runner-port.js +8 -2
  161. package/dist/judgement/runs/verification-sync.d.ts +4 -3
  162. package/dist/judgement/runs/verification-sync.js +27 -5
  163. package/dist/language/flows/affected-tools.js +2 -1
  164. package/dist/language/flows/annotate-notes/annotate.js +8 -3
  165. package/dist/language/flows/annotate-tools.js +1 -1
  166. package/dist/language/flows/change/affected.d.ts +8 -0
  167. package/dist/language/flows/change/affected.js +20 -7
  168. package/dist/language/flows/decision.js +19 -4
  169. package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
  170. package/dist/language/flows/fields/flow-secret-field.js +67 -5
  171. package/dist/language/flows/flow-anchor.d.ts +5 -0
  172. package/dist/language/flows/flow-anchor.js +4 -0
  173. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  174. package/dist/language/flows/flow-cross-step.js +9 -0
  175. package/dist/language/flows/flow-expect-grammar.js +15 -10
  176. package/dist/language/flows/flow-intent.js +6 -1
  177. package/dist/language/flows/flow-journey.d.ts +8 -0
  178. package/dist/language/flows/flow-journey.js +13 -0
  179. package/dist/language/flows/flow-lease.d.ts +27 -0
  180. package/dist/language/flows/flow-lease.js +59 -0
  181. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  182. package/dist/language/flows/flow-replay-run.js +111 -310
  183. package/dist/language/flows/flow-replay.js +21 -19
  184. package/dist/language/flows/flow-replayable.d.ts +38 -0
  185. package/dist/language/flows/flow-replayable.js +179 -0
  186. package/dist/language/flows/flow-start-path.d.ts +108 -0
  187. package/dist/language/flows/flow-start-path.js +313 -0
  188. package/dist/language/flows/flow-step-runners.d.ts +23 -2
  189. package/dist/language/flows/flow-step-runners.js +191 -32
  190. package/dist/language/flows/flow-store-for-session.d.ts +8 -1
  191. package/dist/language/flows/flow-store-for-session.js +6 -0
  192. package/dist/language/flows/flow-tools.d.ts +2 -23
  193. package/dist/language/flows/flow-tools.js +63 -113
  194. package/dist/language/flows/flows.d.ts +4 -6
  195. package/dist/language/flows/flows.js +90 -15
  196. package/dist/language/flows/heal-run.d.ts +10 -4
  197. package/dist/language/flows/heal-run.js +26 -9
  198. package/dist/language/flows/recording/flake.d.ts +3 -27
  199. package/dist/language/flows/recording/flake.js +1 -1
  200. package/dist/language/flows/recording/recording-backtrack.js +1 -4
  201. package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
  202. package/dist/language/flows/recording/tape/recordings.js +9 -3
  203. package/dist/language/flows/replay.d.ts +25 -5
  204. package/dist/language/flows/replay.js +83 -16
  205. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  206. package/dist/language/flows/suite/coverage.d.ts +9 -0
  207. package/dist/language/flows/suite/coverage.js +12 -1
  208. package/dist/language/flows/suite-selection.d.ts +25 -0
  209. package/dist/language/flows/suite-selection.js +41 -9
  210. package/dist/machine/git-tracks.d.ts +6 -0
  211. package/dist/machine/git-tracks.js +36 -0
  212. package/dist/memory/cloud/background-sync.d.ts +25 -0
  213. package/dist/memory/cloud/background-sync.js +79 -0
  214. package/dist/memory/cloud/cloud-config.d.ts +12 -1
  215. package/dist/memory/cloud/cloud-config.js +39 -13
  216. package/dist/memory/cloud/cloud-sync.d.ts +3 -24
  217. package/dist/memory/cloud/cloud-sync.js +5 -2
  218. package/dist/memory/cloud/harness-config.d.ts +0 -7
  219. package/dist/memory/cloud/memory-scope.d.ts +19 -0
  220. package/dist/memory/cloud/memory-scope.js +48 -0
  221. package/dist/memory/cloud/sync-answer.d.ts +43 -0
  222. package/dist/memory/cloud/sync-answer.js +42 -0
  223. package/dist/memory/cloud/sync-cycle.d.ts +40 -10
  224. package/dist/memory/cloud/sync-cycle.js +97 -144
  225. package/dist/memory/cloud/sync-daemon.d.ts +50 -3
  226. package/dist/memory/cloud/sync-daemon.js +473 -83
  227. package/dist/memory/cloud/sync-describe.d.ts +28 -0
  228. package/dist/memory/cloud/sync-describe.js +92 -0
  229. package/dist/memory/cloud/sync-disk.d.ts +9 -1
  230. package/dist/memory/cloud/sync-disk.js +137 -33
  231. package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
  232. package/dist/memory/cloud/sync-flow-versions.js +42 -0
  233. package/dist/memory/impact/impact-store.js +32 -15
  234. package/dist/memory/intent/intent-shard.d.ts +41 -266
  235. package/dist/memory/intent/intent-tools.js +20 -61
  236. package/dist/memory/intent/record-request.d.ts +27 -0
  237. package/dist/memory/intent/record-request.js +88 -0
  238. package/dist/memory/intent/settled-words.js +9 -1
  239. package/dist/memory/journal/drive-flow.d.ts +3 -0
  240. package/dist/memory/journal/drive-flow.js +11 -41
  241. package/dist/memory/journal/envelope-store.js +1 -1
  242. package/dist/memory/journal/envelope.d.ts +6 -154
  243. package/dist/memory/journal/episode-log.d.ts +107 -0
  244. package/dist/memory/journal/episode-log.js +302 -0
  245. package/dist/memory/journal/journal-recorder.d.ts +7 -0
  246. package/dist/memory/journal/journal-recorder.js +22 -9
  247. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  248. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  249. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
  250. package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
  251. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
  252. package/dist/memory/journal/self-observation.js +3 -1
  253. package/dist/memory/journal/session-end.js +23 -9
  254. package/dist/memory/journal/session-journal.js +39 -20
  255. package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
  256. package/dist/memory/project/artifact-root-resolver.js +68 -23
  257. package/dist/memory/project/artifact-root.d.ts +17 -3
  258. package/dist/memory/project/artifact-root.js +47 -9
  259. package/dist/memory/project/fs/fs-port.d.ts +5 -0
  260. package/dist/memory/project/fs/fs-port.js +13 -0
  261. package/dist/memory/project/learned-routes.d.ts +3 -4
  262. package/dist/memory/project/learned-routes.js +3 -11
  263. package/dist/memory/project/link-directory.js +5 -2
  264. package/dist/memory/project/root-claims.d.ts +3 -1
  265. package/dist/memory/project/root-claims.js +41 -7
  266. package/dist/memory/project/session-root.d.ts +1 -1
  267. package/dist/memory/project/session-root.js +1 -15
  268. package/dist/memory/project/sync-status.js +5 -6
  269. package/dist/memory/recall/memory-tools.js +2 -2
  270. package/dist/memory/recall/platform-memory.d.ts +3 -1
  271. package/dist/memory/recall/platform-memory.js +9 -1
  272. package/dist/memory/recall/project-memory.js +15 -19
  273. package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
  274. package/dist/portal/bridge/auth-failure-reason.js +19 -0
  275. package/dist/portal/bridge/bridge.d.ts +19 -4
  276. package/dist/portal/bridge/bridge.js +150 -177
  277. package/dist/portal/bridge/harness-request.d.ts +15 -0
  278. package/dist/portal/bridge/harness-request.js +19 -0
  279. package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
  280. package/dist/portal/bridge/origin/origin-follow.js +110 -0
  281. package/dist/portal/bridge/pairing-token.d.ts +6 -0
  282. package/dist/portal/bridge/pairing-token.js +47 -16
  283. package/dist/portal/bridge/protocol-skew.d.ts +27 -2
  284. package/dist/portal/bridge/protocol-skew.js +66 -2
  285. package/dist/portal/bridge/session-nonces.d.ts +46 -0
  286. package/dist/portal/bridge/session-nonces.js +72 -0
  287. package/dist/portal/input/viewport-tools.d.ts +31 -0
  288. package/dist/portal/input/viewport-tools.js +106 -15
  289. package/dist/portal/pool/bounded-close.d.ts +23 -0
  290. package/dist/portal/pool/bounded-close.js +38 -0
  291. package/dist/portal/pool/browser-pool.d.ts +44 -39
  292. package/dist/portal/pool/browser-pool.js +247 -95
  293. package/dist/portal/pool/context-permissions.d.ts +9 -1
  294. package/dist/portal/pool/context-permissions.js +26 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +37 -0
  296. package/dist/portal/pool/lease-emulation.js +29 -0
  297. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  298. package/dist/portal/pool/playwright-launcher.js +74 -7
  299. package/dist/portal/pool/pool-contract.d.ts +23 -1
  300. package/dist/portal/pool/pool-lease.d.ts +128 -0
  301. package/dist/portal/pool/pool-lease.js +49 -0
  302. package/dist/portal/pool/zero-install.d.ts +8 -1
  303. package/dist/portal/pool/zero-install.js +24 -2
  304. package/dist/portal/production/production-activation.d.ts +136 -0
  305. package/dist/portal/production/production-activation.js +173 -0
  306. package/dist/portal/production/production-drive.d.ts +52 -0
  307. package/dist/portal/production/production-drive.js +301 -0
  308. package/dist/portal/production/production-hello.d.ts +23 -0
  309. package/dist/portal/production/production-hello.js +23 -0
  310. package/dist/portal/realm/web-realm.js +42 -15
  311. package/dist/portal/session/control-envelope.d.ts +1 -1
  312. package/dist/portal/session/dev-server/served-document.d.ts +0 -5
  313. package/dist/portal/session/dev-server/served-document.js +6 -8
  314. package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
  315. package/dist/portal/session/first-run-wiring.d.ts +3 -36
  316. package/dist/portal/session/first-run-wiring.js +10 -103
  317. package/dist/portal/session/live-control-tools.js +61 -19
  318. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  319. package/dist/portal/session/no-session-next-action.js +40 -15
  320. package/dist/portal/session/no-session-watch.d.ts +7 -0
  321. package/dist/portal/session/no-session-watch.js +67 -23
  322. package/dist/portal/session/output-budget.d.ts +10 -0
  323. package/dist/portal/session/output-budget.js +16 -0
  324. package/dist/portal/session/presence/session-lease.d.ts +2 -0
  325. package/dist/portal/session/presence/session-lease.js +8 -0
  326. package/dist/portal/session/recorded-gaps.d.ts +15 -11
  327. package/dist/portal/session/recorded-gaps.js +39 -18
  328. package/dist/portal/session/serving-directory.d.ts +24 -2
  329. package/dist/portal/session/serving-directory.js +93 -5
  330. package/dist/portal/session/session-info.d.ts +26 -0
  331. package/dist/portal/session/session-info.js +20 -0
  332. package/dist/portal/session/session-manager.d.ts +35 -3
  333. package/dist/portal/session/session-manager.js +69 -14
  334. package/dist/portal/session/session-successor.js +1 -9
  335. package/dist/portal/session/session-tools.js +22 -4
  336. package/dist/portal/session/session.d.ts +10 -10
  337. package/dist/portal/session/session.js +37 -29
  338. package/dist/portal/session/zero-install-first-call.d.ts +7 -2
  339. package/dist/portal/session/zero-install-first-call.js +43 -20
  340. package/dist/start-wiring.d.ts +2 -2
  341. package/dist/start-wiring.js +17 -3
  342. package/dist/status-payload.d.ts +11 -1
  343. package/dist/status-payload.js +7 -1
  344. package/dist/surface/agent-presence-grace.d.ts +11 -0
  345. package/dist/surface/agent-presence-grace.js +34 -0
  346. package/dist/surface/http-server.d.ts +12 -1
  347. package/dist/surface/http-server.js +64 -15
  348. package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
  349. package/dist/surface/mcp/faults/mcp-outage.js +19 -1
  350. package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
  351. package/dist/surface/mcp/mcp-proxy.js +194 -267
  352. package/dist/surface/mcp/mcp.d.ts +20 -3
  353. package/dist/surface/mcp/mcp.js +88 -25
  354. package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
  355. package/dist/surface/mcp/proxy/drive-calls.js +114 -5
  356. package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
  357. package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
  358. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
  359. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
  360. package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
  361. package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
  362. package/dist/surface/mcp/server-instructions.js +35 -16
  363. package/dist/surface/mcp/shared-params.d.ts +8 -0
  364. package/dist/surface/mcp/shared-params.js +15 -1
  365. package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
  366. package/dist/surface/mcp/sse-frame-parser.js +18 -0
  367. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  368. package/dist/surface/mcp/surface-vocabulary.js +13 -0
  369. package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
  370. package/dist/surface/mcp/tool-catalog-cache.js +14 -4
  371. package/dist/surface/tools/account-tool.d.ts +4 -3
  372. package/dist/surface/tools/account-tool.js +20 -31
  373. package/dist/surface/tools/act/act-danger.d.ts +2 -0
  374. package/dist/surface/tools/act/act-danger.js +41 -14
  375. package/dist/surface/tools/act/act-observation.d.ts +11 -0
  376. package/dist/surface/tools/act/act-observation.js +33 -0
  377. package/dist/surface/tools/act/act-preflight.js +10 -3
  378. package/dist/surface/tools/act/act-sequence-retry.js +2 -1
  379. package/dist/surface/tools/act/act-target.js +19 -5
  380. package/dist/surface/tools/act/durable.js +1 -1
  381. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
  382. package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
  383. package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
  384. package/dist/surface/tools/act/unsettled-find.js +71 -0
  385. package/dist/surface/tools/act-sequence-tool.js +53 -24
  386. package/dist/surface/tools/act-tools.d.ts +2 -3
  387. package/dist/surface/tools/act-tools.js +49 -47
  388. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  389. package/dist/surface/tools/agent/for-the-agent.js +41 -3
  390. package/dist/surface/tools/assert/assert-grade.js +8 -3
  391. package/dist/surface/tools/assert/assert-verdict.js +4 -2
  392. package/dist/surface/tools/browser-tools.js +7 -4
  393. package/dist/surface/tools/chat-drives.js +50 -25
  394. package/dist/surface/tools/coverage-tools.js +1 -1
  395. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  396. package/dist/surface/tools/dynamic-tools.js +89 -34
  397. package/dist/surface/tools/empty-session-list.d.ts +18 -25
  398. package/dist/surface/tools/empty-session-list.js +67 -38
  399. package/dist/surface/tools/error-recovery.d.ts +17 -7
  400. package/dist/surface/tools/error-recovery.js +53 -20
  401. package/dist/surface/tools/explore-tools.d.ts +10 -0
  402. package/dist/surface/tools/explore-tools.js +72 -19
  403. package/dist/surface/tools/feedback-tools.js +23 -2
  404. package/dist/surface/tools/gap-novelty.d.ts +6 -0
  405. package/dist/surface/tools/gap-novelty.js +9 -0
  406. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  407. package/dist/surface/tools/harness-explore.d.ts +1 -1
  408. package/dist/surface/tools/harness-explore.js +6 -4
  409. package/dist/surface/tools/harness-gate.d.ts +43 -21
  410. package/dist/surface/tools/harness-gate.js +55 -81
  411. package/dist/surface/tools/harness-script.d.ts +2 -0
  412. package/dist/surface/tools/harness-script.js +11 -6
  413. package/dist/surface/tools/harness-toolset.js +3 -4
  414. package/dist/surface/tools/invoke-tool.d.ts +0 -8
  415. package/dist/surface/tools/invoke-tool.js +164 -178
  416. package/dist/surface/tools/lease-hint.d.ts +9 -0
  417. package/dist/surface/tools/lease-hint.js +22 -3
  418. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  419. package/dist/surface/tools/lease-readiness.d.ts +55 -0
  420. package/dist/surface/tools/lease-readiness.js +150 -2
  421. package/dist/surface/tools/lease-tools.d.ts +3 -75
  422. package/dist/surface/tools/lease-tools.js +124 -188
  423. package/dist/surface/tools/map-tools.d.ts +20 -0
  424. package/dist/surface/tools/map-tools.js +145 -0
  425. package/dist/surface/tools/merge-tools.js +11 -7
  426. package/dist/surface/tools/next-step.js +6 -3
  427. package/dist/surface/tools/observe-tools.js +46 -35
  428. package/dist/surface/tools/platform-moment.d.ts +3 -12
  429. package/dist/surface/tools/platform-moment.js +12 -24
  430. package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
  431. package/dist/surface/tools/read/complete-snapshot.js +13 -2
  432. package/dist/surface/tools/read/query-paginate.js +6 -0
  433. package/dist/surface/tools/read/query-shape.d.ts +9 -0
  434. package/dist/surface/tools/read/query-shape.js +15 -0
  435. package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
  436. package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
  437. package/dist/surface/tools/read-tools.js +5 -5
  438. package/dist/surface/tools/real-input-attempt.d.ts +11 -0
  439. package/dist/surface/tools/real-input-attempt.js +206 -38
  440. package/dist/surface/tools/reconcile-tools.js +21 -8
  441. package/dist/surface/tools/reticle-result.d.ts +3 -0
  442. package/dist/surface/tools/reticle-result.js +8 -1
  443. package/dist/surface/tools/run-report.d.ts +22 -0
  444. package/dist/surface/tools/run-report.js +141 -0
  445. package/dist/surface/tools/session-ports.d.ts +57 -0
  446. package/dist/surface/tools/session-ports.js +102 -0
  447. package/dist/surface/tools/tool-kit.d.ts +58 -4
  448. package/dist/surface/tools/tool-kit.js +140 -6
  449. package/dist/surface/tools/tool-surface.d.ts +2 -0
  450. package/dist/surface/tools/tool-surface.js +45 -0
  451. package/dist/surface/tools/tools.js +49 -87
  452. package/dist/telemetry/automation-hint.d.ts +5 -0
  453. package/dist/telemetry/automation-hint.js +7 -0
  454. package/dist/telemetry/cli-telemetry.d.ts +22 -0
  455. package/dist/telemetry/cli-telemetry.js +80 -11
  456. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  457. package/dist/telemetry/daemon-telemetry.js +9 -2
  458. package/dist/telemetry/feedback-cli.d.ts +1 -1
  459. package/dist/telemetry/feedback-cli.js +8 -3
  460. package/dist/telemetry/feedback.d.ts +1 -1
  461. package/dist/telemetry/feedback.js +51 -4
  462. package/dist/telemetry/harness-run.d.ts +3 -3
  463. package/dist/telemetry/harness-run.js +18 -7
  464. package/dist/telemetry/hud-events.d.ts +1 -1
  465. package/dist/telemetry/hud-metrics.d.ts +6 -3
  466. package/dist/telemetry/hud-metrics.js +20 -8
  467. package/dist/telemetry/install-source.js +1 -1
  468. package/dist/telemetry/mcp-connection.d.ts +1 -1
  469. package/dist/telemetry/mcp-connection.js +21 -2
  470. package/dist/telemetry/onboarding-firsts.d.ts +6 -1
  471. package/dist/telemetry/onboarding-firsts.js +41 -1
  472. package/dist/telemetry/proxy-telemetry.d.ts +42 -0
  473. package/dist/telemetry/proxy-telemetry.js +70 -1
  474. package/dist/telemetry/session-metrics.d.ts +1 -3
  475. package/dist/telemetry/session-metrics.js +16 -12
  476. package/dist/telemetry/telemetry.d.ts +9 -1
  477. package/dist/telemetry/telemetry.js +16 -1
  478. package/dist/telemetry/verification-of.d.ts +3 -1
  479. package/dist/telemetry/verification-of.js +7 -1
  480. package/dist/wire-journal.js +12 -2
  481. package/docs/README.md +4 -2
  482. package/docs/actions.mdx +7 -6
  483. package/docs/adapters.md +2 -1
  484. package/docs/agent-cheatsheet.md +19 -5
  485. package/docs/architecture.md +13 -10
  486. package/docs/autodrive.md +6 -5
  487. package/docs/benchmarks.md +2 -2
  488. package/docs/capabilities.mdx +1 -1
  489. package/docs/cli/affected.mdx +1 -1
  490. package/docs/cli/cloud.mdx +6 -6
  491. package/docs/cli/doctor.mdx +3 -1
  492. package/docs/cli/feedback.mdx +11 -7
  493. package/docs/cli/gate.mdx +1 -1
  494. package/docs/cli/help.mdx +1 -1
  495. package/docs/cli/init.mdx +20 -16
  496. package/docs/cli/mcp.mdx +5 -2
  497. package/docs/cli/open.mdx +5 -2
  498. package/docs/cli/report.mdx +1 -1
  499. package/docs/cli/restart.mdx +1 -1
  500. package/docs/cli/rollback.mdx +4 -4
  501. package/docs/cli/serve.mdx +7 -5
  502. package/docs/cli/setup.mdx +1 -1
  503. package/docs/cli/status.mdx +6 -2
  504. package/docs/cli/stop.mdx +3 -3
  505. package/docs/cli/telemetry.mdx +5 -1
  506. package/docs/cli/try.mdx +8 -8
  507. package/docs/cli/update.mdx +8 -5
  508. package/docs/cli/verify.mdx +12 -5
  509. package/docs/cli/version.mdx +1 -1
  510. package/docs/cli.mdx +10 -6
  511. package/docs/debugging.md +1 -1
  512. package/docs/deploy-checks.md +8 -6
  513. package/docs/desktop.mdx +14 -18
  514. package/docs/enterprise.md +6 -6
  515. package/docs/environment.mdx +5 -3
  516. package/docs/faq.mdx +9 -6
  517. package/docs/first-drive.md +19 -9
  518. package/docs/flows.md +3 -4
  519. package/docs/for-agents.md +1 -1
  520. package/docs/frameworks.mdx +34 -11
  521. package/docs/getting-started.md +46 -29
  522. package/docs/http-transport.md +2 -2
  523. package/docs/human-control.md +8 -8
  524. package/docs/index.mdx +2 -2
  525. package/docs/install-agentic.mdx +18 -19
  526. package/docs/install-manual.mdx +8 -4
  527. package/docs/integration-patterns.md +5 -5
  528. package/docs/multi-agent-testing.md +7 -5
  529. package/docs/packages/browser.mdx +34 -2
  530. package/docs/packages/core.mdx +2 -1
  531. package/docs/packages/electron.mdx +15 -3
  532. package/docs/packages/eslint-plugin.mdx +1 -1
  533. package/docs/packages/next.mdx +17 -5
  534. package/docs/packages/react.mdx +8 -1
  535. package/docs/packages/server.mdx +3 -3
  536. package/docs/packages/tauri.mdx +3 -3
  537. package/docs/packages/vite-plugin.mdx +1 -1
  538. package/docs/packages.mdx +19 -6
  539. package/docs/platform-integration.md +12 -4
  540. package/docs/predicates.mdx +18 -7
  541. package/docs/production-mode.md +108 -0
  542. package/docs/prompt-capture.md +99 -0
  543. package/docs/quickstart.mdx +14 -12
  544. package/docs/recipes.mdx +9 -8
  545. package/docs/required-checks.md +3 -2
  546. package/docs/skill-file.mdx +4 -3
  547. package/docs/skill-setup.md +2 -2
  548. package/docs/skill.md +62 -70
  549. package/docs/state-files.md +1 -0
  550. package/docs/state-management.mdx +11 -9
  551. package/docs/system-map.md +14 -13
  552. package/docs/telemetry.md +32 -24
  553. package/docs/testing.md +9 -5
  554. package/docs/tools/act-and-wait.mdx +17 -13
  555. package/docs/tools/act-sequence.mdx +40 -66
  556. package/docs/tools/act.mdx +7 -5
  557. package/docs/tools/assert.mdx +1 -1
  558. package/docs/tools/look.mdx +1 -1
  559. package/docs/tools/navigate.mdx +1 -1
  560. package/docs/tools/network.mdx +13 -11
  561. package/docs/tools/overview.mdx +3 -3
  562. package/docs/tools/query.mdx +3 -3
  563. package/docs/tools/session-and-feedback.mdx +9 -6
  564. package/docs/tools/sessions.mdx +7 -0
  565. package/docs/tools/snapshot.mdx +9 -7
  566. package/docs/tools/tools-and-run.mdx +11 -10
  567. package/docs/tools/verify.mdx +1 -1
  568. package/docs/troubleshooting.mdx +21 -9
  569. package/docs/usage.md +58 -43
  570. package/docs/use-cases.mdx +2 -2
  571. package/docs/vs-chrome-devtools-mcp.mdx +5 -5
  572. package/docs/vs-playwright-mcp.mdx +5 -4
  573. package/docs/what-is-recorded.md +12 -7
  574. package/docs/what-is-reticle.mdx +2 -2
  575. package/docs/why-reticle.mdx +1 -1
  576. package/package.json +9 -12
  577. package/dist/command/dev/stale-issue-guard.d.ts +0 -34
  578. package/dist/command/dev/stale-issue-guard.js +0 -69
@@ -11,10 +11,10 @@
11
11
  */
12
12
  import { z } from 'zod';
13
13
  import { timeoutMsSchema } from './args/numeric-bounds.js';
14
- import { compileSequenceStep, pathOf } from '../../language/flows/replay.js';
14
+ import { compileSequenceStep, pathOf, wroteSince } from '../../language/flows/replay.js';
15
15
  import { DEFAULT_SEQUENCE_STEP_TIMEOUT_MS } from '../../language/flows/flow-step-runners.js';
16
16
  import { sequenceStepArgs } from './act/act-preflight.js';
17
- import { REPLAY_PROGRAM_VERSION, ReticleTool, Verified, VerifiedReason, } from '@reticlehq/core';
17
+ import { REPLAY_PROGRAM_VERSION, ReticleTool, Verified, VerifiedReason, checkIntent, } from '@reticlehq/core';
18
18
  import { healthEnvelope } from '../../portal/session/session-health.js';
19
19
  import { pausedShortCircuit, pausedOutputShape, withControl, } from '../../portal/session/control-envelope.js';
20
20
  import { asRecord, isAbsenceDerived, isAdvisory } from '@reticlehq/core';
@@ -26,7 +26,7 @@ import { takeStepShot } from '../../features/visual/step-shots.js';
26
26
  import { actCommand } from './act-tools.js';
27
27
  import { PredicateSchema, waitForPredicate, } from '@reticlehq/engine/question/predicate/predicate.js';
28
28
  import { DeviationMode, gradeSequence, JOURNEY_RECORDING, offerToKeep, } from './act/sequence-grade.js';
29
- import { stepEffect } from '@reticlehq/engine/evidence/step-effect.js';
29
+ import { stepEffect, appScope } from '@reticlehq/engine/evidence/step-effect.js';
30
30
  // resolveActTarget moved out of act-tools into its own module on this branch; #706 was written
31
31
  // against the older layout where act-tools re-exported it.
32
32
  import { resolveActTarget } from './act/act-target.js';
@@ -34,6 +34,7 @@ import { gradeOfPredicate } from './assert/assert-grade.js';
34
34
  import { describeWaitTarget } from '@reticlehq/engine/evidence/unsettled.js';
35
35
  import { sourceOf } from './tools-helpers.js';
36
36
  import { confirmedByDeclaration } from './act/act-danger.js';
37
+ import { unreachableTargetNote } from './act/act-observation.js';
37
38
  /**
38
39
  * The step's effect record, best-effort.
39
40
  *
@@ -43,9 +44,11 @@ import { confirmedByDeclaration } from './act/act-danger.js';
43
44
  * INSIDE the step loop, be caught as a step failure, and abort the rest of a journey that was
44
45
  * running perfectly. The drive is the product; the description of it is not.
45
46
  */
46
- function effectOf(session, since) {
47
+ function effectOf(session, since, expect) {
47
48
  try {
48
- return stepEffect(session.eventsSince(since), { since, until: session.elapsed() });
49
+ // A failure the step declared is its expected result, as it is for `act_and_wait`'s `until`.
50
+ const declared = PredicateSchema.safeParse(expect);
51
+ return stepEffect(session.eventsSince(since), { since, until: session.elapsed() }, { ...appScope(session), ...(declared.success ? { declared: [declared.data] } : {}) });
49
52
  }
50
53
  catch {
51
54
  return {};
@@ -58,12 +61,19 @@ function stepVerdictEffect(check) {
58
61
  ? { verified: Verified.NO, reason: VerifiedReason.CONTRADICTED }
59
62
  : { verified: Verified.YES, reason: undefined }
60
63
  : check.undecided
61
- ? { verified: Verified.UNKNOWN, reason: VerifiedReason.OBSERVATION_LOST }
64
+ ? {
65
+ verified: Verified.UNKNOWN,
66
+ reason: true === check.unreachable
67
+ ? VerifiedReason.INCONCLUSIVE
68
+ : VerifiedReason.OBSERVATION_LOST,
69
+ }
62
70
  : { verified: Verified.NO, reason: VerifiedReason.ASSERTION_FAILED };
63
71
  const source = sourceOf(check.source);
64
72
  return {
65
73
  claim: describeWaitTarget(check.expect),
66
74
  verified,
75
+ // A step's sentence: the step names no intent of its own, so it is built from its expect.
76
+ ...checkIntent(check.expect, check),
67
77
  ...(source === undefined ? {} : { source: `${source.file}:${String(source.line)}` }),
68
78
  ...(check.expected === undefined ? {} : { expected: check.expected }),
69
79
  ...(check.observed === undefined ? {} : { observed: check.observed }),
@@ -112,7 +122,7 @@ export const ACT_SEQUENCE_TOOL = {
112
122
  description: "Drive a WHOLE journey in ONE round-trip, with NO snapshot first. Name each step's element by {testid} | {label} | {role,name} | {text} in `target` and Reticle resolves it AT THE MOMENT THAT STEP RUNS — so a control that does not exist yet (a modal an earlier step opens, a row it creates) is still addressable, and waits up to timeout_ms to appear. This is the fast path: snapshot -> act -> snapshot -> act costs a model turn per step and is the slowest thing an agent can do. Give each step an `expect` and the sequence stops at the first one that does not hold, returning the un-run `tail` verbatim so you re-plan only the failure. Returns per-step effects[] (see reticle_act).",
113
123
  inputSchema: {
114
124
  steps: z
115
- .array(z.record(z.unknown()))
125
+ .array(z.record(z.string(), z.unknown()))
116
126
  .describe('Ordered list of { ref | target, action, args?, expect? } objects. Each step is equivalent to one reticle_act call, and takes its arguments either way: `{ ref, action: "fill", value: "…" }` flat, as reticle_act does, or nested as `args: { value }`. Give `ref` from a snapshot/query, or `target` ({ testid } | { label } | { role, name } | { text }) to resolve in this call. Put confirmDangerous:true in a destructive step args object. `expect` is the same predicate shape as reticle_act_and_wait `until`, and it is what makes a step PROVE something: a step without one is driven, not verified, and the result says so. Naming the consequence is also FASTER — a named consequence is detected the instant it fires, where waiting for the page to settle can only conclude by waiting for silence.'),
117
127
  // A plain number, not boolean|number: a zod union serialises to a JSON-Schema `anyOf` that
118
128
  // cost 174 B on a surface re-sent every turn, against 81 B of headroom. One spelling is also
@@ -153,14 +163,14 @@ export const ACT_SEQUENCE_TOOL = {
153
163
  /** How many steps declared a consequence, of how many were driven. Never averaged away. */
154
164
  coverage: z.object({ declared: z.number(), total: z.number() }).optional(),
155
165
  /** Steps never run, verbatim, so a caller re-plans the failure rather than the whole journey. */
156
- tail: z.array(z.record(z.unknown())).optional(),
166
+ tail: z.array(z.record(z.string(), z.unknown())).optional(),
157
167
  /**
158
168
  * Each step carries the same effect record a REPLAYED step carries: `window` (the
159
169
  * `reticle_observe { since, until }` drill address), `digest` (what the app did, as counts) and
160
170
  * `contradictions` (channels that disagree, present even when the step passed). Declared here
161
171
  * because an undeclared field is stripped from structuredContent and would be silently lost.
162
172
  */
163
- steps: z.array(z.record(z.unknown())).optional(),
173
+ steps: z.array(z.record(z.string(), z.unknown())).optional(),
164
174
  result: z.unknown().optional(),
165
175
  session: z
166
176
  .object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
@@ -274,7 +284,7 @@ export const ACT_SEQUENCE_TOOL = {
274
284
  */
275
285
  const describe = () => ({
276
286
  ...describeStepResult(step, asRecord(outcome.result)),
277
- ...effectOf(session, stepSince),
287
+ ...effectOf(session, stepSince, step['expect']),
278
288
  });
279
289
  const deciding = (step) => (step.contradictions ?? [])
280
290
  .map((c) => c.kind)
@@ -287,12 +297,15 @@ export const ACT_SEQUENCE_TOOL = {
287
297
  * satisfy step four's assertion, which is a false green built out of correct parts.
288
298
  */
289
299
  const parsed = PredicateSchema.safeParse(step['expect']);
300
+ // A click no person could have made decides nothing, whatever followed it.
301
+ const unreachable = unreachableTargetNote(outcome.result);
290
302
  if (!parsed.success) {
291
303
  const described = describe();
292
304
  const contradicted = deciding(described);
293
305
  expectations.push({
294
306
  declared: false,
295
307
  ...(0 === contradicted.length ? {} : { contradicted }),
308
+ ...(unreachable === undefined ? {} : { undecided: unreachable }),
296
309
  });
297
310
  await pushStep(described);
298
311
  }
@@ -304,29 +317,35 @@ export const ACT_SEQUENCE_TOOL = {
304
317
  const described = describe();
305
318
  const contradicted = deciding(described);
306
319
  const disagreement = 0 === contradicted.length ? {} : { contradicted };
307
- const held = true === verdict.pass;
320
+ const held = true === verdict.pass && unreachable === undefined;
308
321
  // A tab that went away (an external checkout page) or a predicate that could not be
309
322
  // read decided nothing: unknown, never a miss blamed on the app.
310
- const undecided = !held && (true === verdict.observationLost || verdict.inconclusive !== undefined);
323
+ const undecided = unreachable !== undefined ||
324
+ (!held && (true === verdict.observationLost || verdict.inconclusive !== undefined));
311
325
  // One check per declared step, journaled as act_and_wait journals its own, so the
312
326
  // session's result, its run file and the dashboard all count it. See sequence-journal.ts.
313
327
  journalStep(session, { step: i, expect: step['expect'] }, stepVerdictEffect({
314
328
  expect: parsed.data,
315
329
  held,
316
330
  undecided,
331
+ ...(unreachable === undefined ? {} : { unreachable: true }),
317
332
  contradicted,
318
333
  expected: verdict.expected,
319
334
  observed: held ? undefined : (verdict.observed ?? verdict.failureReason),
320
335
  source: asRecord(outcome.result)['source'],
336
+ evidence: verdict.evidence,
337
+ assertion: verdict.assertion,
321
338
  }));
322
339
  expectations.push({
323
340
  declared: true,
324
341
  held,
325
342
  ...(undecided
326
343
  ? {
327
- undecided: true === verdict.observationLost
328
- ? `${verdict.failureReason ?? 'the observation was lost'} (the page left)`
329
- : (verdict.failureReason ?? 'the predicate could not be read'),
344
+ undecided: unreachable !== undefined
345
+ ? unreachable
346
+ : true === verdict.observationLost
347
+ ? `${verdict.failureReason ?? 'the observation was lost'} (the page left)`
348
+ : (verdict.failureReason ?? 'the predicate could not be read'),
330
349
  }
331
350
  : {}),
332
351
  ...disagreement,
@@ -386,19 +405,29 @@ export const ACT_SEQUENCE_TOOL = {
386
405
  // in the ambient tape. A stalled plan keeps only the prefix whose steps actually ran.
387
406
  let journey;
388
407
  if (completed > 0) {
389
- // A sub-step keeps its `expect` only if it held — same rule as act_and_wait, so a flow
390
- // never replays an expectation that was never once observed to hold.
391
- const proved = inputSteps.slice(0, completed).map((raw, i) => {
392
- const step = asRecord(raw);
408
+ // On the ambient tape a sub-step keeps its `expect` only if it held — same rule as
409
+ // act_and_wait, so an auto-saved flow never replays a claim that was never once observed to
410
+ // hold. A recording somebody opened keeps every claim they declared: dropping a refuted one
411
+ // there saved a flow that replayed green on the very defect it had caught.
412
+ const ran = inputSteps.slice(0, completed).map(asRecord);
413
+ const proved = ran.map((step, i) => {
393
414
  const { expect: _expect, ...rest } = step;
394
415
  return true === expectations[i]?.held ? step : rest;
395
416
  });
396
- const recorded = compileSequenceStep({ ...args, steps: proved }, {
397
- count: completed,
398
- steps: stepResults.slice(0, completed),
399
- });
417
+ const compiled = (steps) => {
418
+ const step = compileSequenceStep({ ...args, steps }, { count: completed, steps: stepResults.slice(0, completed) });
419
+ // The journey sent a write request: saved `writes`, so a replay does not repeat it unasked.
420
+ if (wroteSince(session, since))
421
+ step.writes = true;
422
+ return step;
423
+ };
424
+ const recorded = compiled(proved);
400
425
  journey = recorded;
401
- deps.recordings.capture(pageBefore === undefined ? recorded : { ...recorded, page: pageBefore }, undefined, session.id);
426
+ const onPage = (step) => pageBefore === undefined ? step : { ...step, page: pageBefore };
427
+ // Every step was on Reticle's own panel: nothing of the app's journey to record.
428
+ const onApp = asRecord(recorded.args)['steps'];
429
+ if (Array.isArray(onApp) && 0 < onApp.length)
430
+ deps.recordings.capture(onPage(compiled(ran)), undefined, session.id, onPage(recorded));
402
431
  deps.recordings.markEnded(pathOf(session.url), session.id);
403
432
  }
404
433
  /*
@@ -3,9 +3,8 @@ import { type ToolDef, type ToolDeps } from './tool-kit.js';
3
3
  /**
4
4
  * Single dispatch point for every ACT and ACT_SEQUENCE command.
5
5
  *
6
- * This is the seam the reviewer asked for: instead of wiring rewriteUploadArgs at three separate
7
- * call sites (reticle_act, reticle_act_and_wait, reticle_act_sequence) we intercept once here,
8
- * which also covers flow-replay, crawl, and any future dispatch site that goes through this helper.
6
+ * reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
7
+ * the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
9
8
  *
10
9
  * captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
11
10
  * the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
@@ -13,9 +13,9 @@ import { aliasParam } from './args/alias-args.js';
13
13
  import { resolveSessionWithin } from '../../portal/session/timing/resolve-within.js';
14
14
  import { WALL_CLOCK } from '../../portal/session/timing/wall-clock.js';
15
15
  import { timeoutMsSchema } from './args/numeric-bounds.js';
16
- import { captureAct, captureVerdictedAct, pathOf } from '../../language/flows/replay.js';
16
+ import { captureAct, captureVerdictedAct, pathOf, wroteSince } from '../../language/flows/replay.js';
17
17
  import { durableArg, durableOutput, reloadAndRecheck, withDurability } from './act/durable.js';
18
- import { ActionType, ActionWarning, ReticleCommand, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, Verified, VerifiedReason, PredicateKind, } from '@reticlehq/core';
18
+ import { ActionType, ActionWarning, ReticleCommand, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, Verified, VerifiedReason, PredicateKind, checkIntent, } from '@reticlehq/core';
19
19
  import { leanActResult, mutatedWithin } from './act/act-view.js';
20
20
  import { ReticleTool } from '@reticlehq/core';
21
21
  import { buildReactionReport, summarizeReaction } from '@reticlehq/engine/question/reaction.js';
@@ -25,7 +25,7 @@ import { causalSummary } from '../../judgement/capsule/causal-summary.js';
25
25
  import { findContradictions } from '@reticlehq/engine/disagreement/contradictions.js';
26
26
  import { crashedRuleNotes } from '@reticlehq/engine/disagreement/contradiction-folds.js';
27
27
  import { gapsForAction } from '@reticlehq/engine/evidence/instrumentation-gaps.js';
28
- import { withGapNovelty } from './gap-novelty.js';
28
+ import { engineBlindSpotsOutput, withGapNovelty } from './gap-novelty.js';
29
29
  import { noteSessionGaps } from '@reticlehq/engine/evidence/gap-ledger.js';
30
30
  import { isChangeUndeclared } from '@reticlehq/engine/evidence/undeclared-change.js';
31
31
  import { intentDebt, ledgerFor } from '../../memory/intent/open-intents.js';
@@ -37,16 +37,15 @@ import { inFlightRequestLabels, repeatedRequestLabels } from './act/settle-in-fl
37
37
  import { finishAfterMatch } from './act/after-match.js';
38
38
  import { noteProved } from './act/proved-controls.js';
39
39
  import { decideVerified } from '@reticlehq/engine/evidence/verified.js';
40
- import { honestyForVerdict } from '@reticlehq/engine/evidence/honesty.js';
40
+ import { buildHonestyBlock, honestyForVerdict } from '@reticlehq/engine/evidence/honesty.js';
41
41
  import { declaredExpectations, declaresBodyIndependentChannel, } from '@reticlehq/engine/question/declared.js';
42
42
  import { describeWaitTarget, namedNetIsInFlight } from '@reticlehq/engine/evidence/unsettled.js';
43
43
  import { saveFailedAssertCapsule } from './act-capsule.js';
44
44
  import { blastRadius, buildDivergenceCapsule, wireCapsule } from '../../judgement/capsule/capsule.js';
45
45
  import { predicateToExpectedLinks } from '@reticlehq/engine/question/predicate/predicate-to-links.js';
46
- import { buildHonestyBlock } from '@reticlehq/engine/evidence/honesty.js';
47
46
  import { absenceBlindSpotNote, buildCoverageStatement, blindSpotsFromState, transportGapNote, Coverage, impeachesCapture, } from '@reticlehq/engine/evidence/blind-spots.js';
48
47
  import { acceptedWriteLabels } from '@reticlehq/engine/evidence/accepted-write.js';
49
- import { unreadWriteLabels } from '@reticlehq/engine/evidence/unread-outcome.js';
48
+ import { unreadWriteLabels, unreadWriteReason } from '@reticlehq/engine/evidence/unread-outcome.js';
50
49
  import { evaluatePredicate, waitForPredicate, provenExpectedLinks, PredicateSchema, } from '@reticlehq/engine/question/predicate/predicate.js';
51
50
  import { sessionVerdictFacts } from '../../portal/session/session-verdict-facts.js';
52
51
  import { currentOf, healthEnvelope, refuseIfThrottled } from '../../portal/session/session-health.js';
@@ -55,16 +54,17 @@ import { asNumber, asRecord, asString } from '@reticlehq/core';
55
54
  import { sourceOf } from './tools-helpers.js';
56
55
  import { confirmedByDeclaration } from './act/act-danger.js';
57
56
  import { dispatchAct, preflightAct } from './act/act-preflight.js';
58
- import { checkNet, disabledTargetNote, followLostObservation } from './act/act-observation.js';
57
+ import { actTargetNote, checkNet, followLostObservation } from './act/act-observation.js';
59
58
  import { intentArg, sessionIdShape } from './tool-kit.js';
60
59
  import { verdictIntentGap } from '@reticlehq/engine/evidence/verdict-intent-gap.js';
61
60
  import { asActionType, gradeOf } from './act/act-helpers.js';
62
61
  import { resolveActTarget } from './act/act-target.js';
63
62
  import { screenRequestFindings, withAdvisories } from './act/screen-request.js';
64
63
  import { tryRealInput, rewriteUploadArgs, HOVER_NEEDS_POINTER_MSG } from './real-input-attempt.js';
64
+ import { sessionRoot } from '../../memory/project/session-root.js';
65
65
  import { gradeOfPredicate } from './assert/assert-grade.js';
66
66
  import { readAlreadyTrue } from './act/already-true.js';
67
- import { noteSourceSeen } from '../../portal/session/recorded-gaps.js';
67
+ import { engineBlindSpotsField, noteSourceSeen } from '../../portal/session/recorded-gaps.js';
68
68
  /**
69
69
  * The action vocabulary, derived from ActionType — never retyped: a hand-copied list once omitted
70
70
  * blur, upload and drag. The schema refuses an unknown action before any session is resolved.
@@ -74,32 +74,32 @@ const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
74
74
  /**
75
75
  * Single dispatch point for every ACT and ACT_SEQUENCE command.
76
76
  *
77
- * This is the seam the reviewer asked for: instead of wiring rewriteUploadArgs at three separate
78
- * call sites (reticle_act, reticle_act_and_wait, reticle_act_sequence) we intercept once here,
79
- * which also covers flow-replay, crawl, and any future dispatch site that goes through this helper.
77
+ * reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
78
+ * the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
80
79
  *
81
80
  * captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
82
81
  * the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
83
82
  * base64 to the browser as if it were an inline content call.
84
83
  */
85
84
  export async function actCommand(deps, session, actArgs, timeoutMs) {
86
- const rewritten = await rewriteUploadArgs(deps, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
85
+ const rewritten = await rewriteUploadArgs({ fs: deps.fs, reticleRoot: sessionRoot(deps, session.id) }, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
87
86
  // Sequence and act_and_wait dispatch through here without the ACT handler's tryRealInput.
88
87
  // A synthetic hover reports dispatched/settled while CSS :hover never applies — drive a real
89
- // pointer when one is available, otherwise refuse rather than lie.
90
- if (ActionType.HOVER === actArgs['action']) {
88
+ // pointer when one is available, otherwise refuse rather than lie. A press on a lease takes its
89
+ // real keyboard, as reticle_act does: a synthetic Tab moves no focus.
90
+ const hover = ActionType.HOVER === actArgs['action'];
91
+ if (hover || (ActionType.PRESS === actArgs['action'] && deps.realInput === undefined)) {
91
92
  const ref = asString(actArgs['ref']);
92
- if (ref === undefined)
93
+ if (hover && ref === undefined)
93
94
  throw new Error(HOVER_NEEDS_POINTER_MSG);
94
- const real = await tryRealInput(deps, session, ref, ActionType.HOVER, actArgs);
95
- if (real.result === undefined)
95
+ const action = hover ? ActionType.HOVER : ActionType.PRESS;
96
+ const real = await tryRealInput(deps, session, ref ?? '', action, actArgs);
97
+ if (hover && real.result === undefined)
96
98
  throw new Error(HOVER_NEEDS_POINTER_MSG);
97
- return {
98
- kind: 'command_result',
99
- id: 'hover',
100
- ok: true,
101
- result: { dispatched: true, settled: real.settled, ...asRecord(real.result) },
102
- };
99
+ if (real.result !== undefined) {
100
+ const result = { dispatched: true, settled: real.settled, ...asRecord(real.result) };
101
+ return { kind: 'command_result', id: action, ok: true, result };
102
+ }
103
103
  }
104
104
  const bridgeArgs = { ...actArgs, args: rewritten };
105
105
  // What the acted element shows (test id, source) is noted in `Session.command`, Harness acts too.
@@ -109,19 +109,19 @@ export const ACT_TOOLS = [
109
109
  {
110
110
  name: ReticleTool.ACT,
111
111
  example: { ref: 'e42', action: 'fill', args: { value: 'hello' } },
112
- description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. effect.alreadyAtValue=true (check/uncheck only) means the box already read as the requested state, so NOTHING was dispatched and the app was never told — the DOM property is not evidence the application holds that value, so assert the app\'s own state (a signal, a request, a derived control), not the box. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. Full model (real-input, throttled tabs, `reticle drive`): node_modules/@reticlehq/server/docs/usage.md §18.',
112
+ description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. effect.alreadyAtValue=true (check/uncheck only) means the box already read as the requested state, so NOTHING was dispatched and the app was never told — the DOM property is not evidence the application holds that value, so assert the app\'s own state (a signal, a request, a derived control), not the box. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. On a leased tab a press uses the real keyboard: Tab moves focus, and a press with a ref focuses that element first, so Enter or Space presses it as a person would. Full model (real-input, throttled tabs, `reticle drive`): node_modules/@reticlehq/server/docs/usage.md §18.',
113
113
  inputSchema: {
114
114
  ref: z
115
115
  .string()
116
116
  .optional()
117
117
  .describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
118
118
  target: z
119
- .record(z.unknown())
119
+ .record(z.string(), z.unknown())
120
120
  .optional()
121
121
  .describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
122
122
  action: actionTypeEnum.describe('Action to perform.'),
123
123
  args: z
124
- .record(z.unknown())
124
+ .record(z.string(), z.unknown())
125
125
  .optional()
126
126
  .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 or the key 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 press: { keys: ["Control","k"] } holds several keys down TOGETHER (pressed in order, released in reverse) and { code } names the physical key — both stay on the in-page dispatcher, the only path that can express them. 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.'),
127
127
  refuseWhenThrottled: z
@@ -224,7 +224,7 @@ export const ACT_TOOLS = [
224
224
  // Keep what only this call measured, so the observe that judges this window can ask whether
225
225
  // anything happened INSIDE the target — the one fact that separates a dead control from a
226
226
  // page that was merely busy with something else.
227
- session.lastAct.markActed(since, action, mutatedWithin(r), asString(args['ref']));
227
+ session.lastAct.markActed(since, action, mutatedWithin(r), targetRef.ref);
228
228
  return withControl(session, {
229
229
  since,
230
230
  inputMode: InputMode.SYNTHETIC,
@@ -264,12 +264,12 @@ export const ACT_TOOLS = [
264
264
  .optional()
265
265
  .describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
266
266
  target: z
267
- .record(z.unknown())
267
+ .record(z.string(), z.unknown())
268
268
  .optional()
269
269
  .describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
270
270
  action: actionTypeEnum.describe('Action to perform.'),
271
271
  args: z
272
- .record(z.unknown())
272
+ .record(z.string(), z.unknown())
273
273
  .optional()
274
274
  .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.'),
275
275
  predicate: PredicateSchema.optional().describe('Alias for `until`.'),
@@ -289,6 +289,7 @@ export const ACT_TOOLS = [
289
289
  durable: durableOutput,
290
290
  effect: z
291
291
  .unknown()
292
+ .optional()
292
293
  .describe('The reticle_act result (dispatched, settled, inputMode, etc.).'),
293
294
  verdict: z.object({
294
295
  pass: z.boolean(),
@@ -316,9 +317,11 @@ export const ACT_TOOLS = [
316
317
  }),
317
318
  trace: z
318
319
  .unknown()
320
+ .optional()
319
321
  .describe('Reaction digest: { window_ms, summary } of what the app did (DOM/network/route/console/signal counts). The full per-event timeline is one reticle_observe { since } away.'),
320
322
  summary: z
321
323
  .unknown()
324
+ .optional()
322
325
  .describe('Bounded causal summary: net {total,errors,headline}, consoleErrors, statePathsChanged, storageKeysChanged, stateDiffs [{path,from,to}], storageDiffs [{key,from,to}], route, signals, layoutShift, longTasks — real before→after diffs (capped), not just readings. THIS IS THE ANSWER TO "what did that click do": console, network, storage and state for this action are all here, so do NOT follow an act with reticle_console + reticle_network + reticle_state to find out — call them only to go deeper into something this block already pointed at. Every list is length-capped so the verdict can never be the field a client truncates; `elided` says which lists lost entries and how many. `stateUnwatched: true` means NO subscribable store is registered, so an empty stateDiffs means unwatched, NOT unchanged — no state conclusion is available until one is registered.'),
323
326
  // Promoted out of `effect` on RED only — the file:line the failure came from, the first thing a
324
327
  // repair wants. Undeclared, it was stripped on the validating profile exactly like the structured
@@ -351,8 +354,10 @@ export const ACT_TOOLS = [
351
354
  .array(z.unknown())
352
355
  .optional()
353
356
  .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 red that cannot name a file:line, a state assertion with no registered store, a DOM change no signal announced, a route change nothing signalled); never a survey of the page, so an entry is always work worth doing now. OMITTED when the app told Reticle everything it needed. Applying `fix` makes every later verdict on this app stronger, not just this one.'),
357
+ engineBlindSpots: engineBlindSpotsOutput,
354
358
  honesty: z
355
359
  .unknown()
360
+ .optional()
356
361
  .describe('The verdict trust block { grade, attribution, coverage, integrity, envelope? } — a green never looks stronger than this. Gate on grade ≥ net AND integrity.clean. Fields that were not measured are OMITTED rather than reported as zero, so treat an absent `envelope` as "not sampled", never as a failure.'),
357
362
  since: z
358
363
  .number()
@@ -451,7 +456,7 @@ export const ACT_TOOLS = [
451
456
  // Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement
452
457
  // also stops the spread below from inheriting an earlier reticle_act's action and
453
458
  // mutation count.
454
- session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)), asString(args['ref']));
459
+ session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)), resolved.ref);
455
460
  }
456
461
  // Honesty: floor the predicate at this act's cursor so a stale buffered event can't satisfy it.
457
462
  const predicateStarted = session.elapsed();
@@ -504,17 +509,12 @@ export const ACT_TOOLS = [
504
509
  ? undefined
505
510
  : buildDivergenceCapsule(links, windowEvents, bufferLost);
506
511
  /*
507
- * The blast radius travels on a GREEN too, which is the only verdict where it is news.
508
- *
509
- * On a red the capsule already carries it and the fault is the headline. On a green nothing
510
- * carried it at all — and "the consequence I declared held, AND this action also posted
511
- * somewhere I never mentioned" is exactly the finding a passing verdict buries. A click that
512
- * works and also fires a DELETE is a green that did extra damage.
512
+ * The blast radius goes on a GREEN too. On a red the capsule carries it. On a green, a click
513
+ * that works and also sends a DELETE did extra damage, and no other field shows that.
514
+ * It is attached only when it is not empty, because its presence is the signal. The full
515
+ * capsule stays red-only: its divergence walk and causal summary answer a red's question.
513
516
  *
514
- * One pass over a window already in hand, and only attached when it is non-empty: a field
515
- * that is always present teaches a reader to skim it, and the whole value here is that its
516
- * presence is the signal. The full capsule stays red-only — the divergence walk and the
517
- * causal summary are the expensive halves and answer a question a green does not have.
517
+ * One pass over a window that is already in hand.
518
518
  */
519
519
  const greenRadius = verdict.pass ? blastRadius(links, windowEvents) : [];
520
520
  // Grade from what the verdict PROVED, not what it declared. A green anyOf holds on one branch, so
@@ -644,8 +644,8 @@ export const ACT_TOOLS = [
644
644
  });
645
645
  const outcomeUnread = unreadWriteLabels(windowEvents);
646
646
  const stillInFlight = inFlightRequestLabels(windowEvents, session.url, session.background);
647
- // A click on a disabled control cannot cause anything: a miss there is not the app's.
648
- const inconclusive = verdict.inconclusive ?? disabledTargetNote(verdict.pass, actResult?.result);
647
+ // A click on a disabled control cannot cause anything, nor one no person could make.
648
+ const inconclusive = verdict.inconclusive ?? actTargetNote(verdict.pass, actResult?.result);
649
649
  const { decision, durable } = await withDurability(args['durable'], until, decideVerified({
650
650
  pass: verdict.pass,
651
651
  // Threaded rather than looked up: decideVerified is pure and has no session.
@@ -673,7 +673,9 @@ export const ACT_TOOLS = [
673
673
  honesty,
674
674
  contradictions,
675
675
  ...(0 === outcomePending.length ? {} : { outcomePending }),
676
- ...(outcomeUnread.length > 0 ? { outcomeUnread } : {}),
676
+ ...(outcomeUnread.length > 0
677
+ ? { outcomeUnread, outcomeUnreadReason: unreadWriteReason(windowEvents) }
678
+ : {}),
677
679
  // `settled` is genuinely optional: a wait that declared no predicate never measured it, and
678
680
  // passing `false` there would report "never settled" about something never asked to settle.
679
681
  ...(settledOutcome === undefined ? {} : { settled: settledOutcome }),
@@ -752,6 +754,7 @@ export const ACT_TOOLS = [
752
754
  verdictEffect = {
753
755
  claim: describeWaitTarget(until),
754
756
  verified: decision.verified,
757
+ ...checkIntent(until, verdict, asString(args['intent'])),
755
758
  ...(actedSourceLabel === undefined ? {} : { source: actedSourceLabel }),
756
759
  ...checkWords(verdict),
757
760
  // TRUE here, and false on the `assert` path, and the difference is the point. This tool
@@ -796,19 +799,18 @@ export const ACT_TOOLS = [
796
799
  // where an absence made this very verdict weaker — never as a survey of the page.
797
800
  /*
798
801
  * …and, on a pass, whether anybody said what this verdict was FOR.
799
- *
800
802
  * Intent capture was reachable and unasked-for: the argument sits on this very tool, and
801
803
  * the only nudge lived on `flow_save` — which a build-mode agent may never reach. An
802
804
  * optional capability nobody is told about is one nobody uses, measured on `bodies` this
803
805
  * same week.
804
806
  */
805
- // Remedy once per session, facts every time — see gap-novelty.ts. `no-source-mapping`
806
- // shipped 11 identical copies of its fix text in one measured drive.
807
+ // Remedy once per session, facts every time: see gap-novelty.ts for the measurement.
807
808
  ...(gaps.length > 0 || intentGap !== undefined
808
809
  ? {
809
810
  instrumentationGaps: withGapNovelty(session.id, intentGap === undefined ? gaps : [...gaps, intentGap]),
810
811
  }
811
812
  : {}),
813
+ ...engineBlindSpotsField(session.id, until, args['intent'], openIntents),
812
814
  // Cross-channel disagreement, reported WITH the action that caused it.
813
815
  //
814
816
  // This is the one finding here a human structurally cannot make — they watch one channel,
@@ -832,7 +834,7 @@ export const ACT_TOOLS = [
832
834
  }
833
835
  finally {
834
836
  if (dispatched !== undefined)
835
- captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait, recordedVerdict, session.id);
837
+ captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait, recordedVerdict, session.id, wroteSince(acted, actedSince));
836
838
  deps.recordings.markEnded(pathOf(currentOf(deps.sessions, session).url), session.id);
837
839
  acted.finishAction(verdictEffect, settledOutcome, true === settledOutcome ? acted.elapsed() - actedSince : undefined);
838
840
  }
@@ -75,6 +75,6 @@ export declare function shapeForAgent(tool: string, args: Record<string, unknown
75
75
  */
76
76
  export declare function withCompactEnvelope<T extends {
77
77
  name: string;
78
- inputSchema: z.ZodRawShape;
79
- outputSchema?: z.ZodRawShape;
78
+ inputSchema: Record<string, z.ZodType>;
79
+ outputSchema?: Record<string, z.ZodType>;
80
80
  }>(tools: T[]): T[];
@@ -7,15 +7,53 @@
7
7
  * which was already shaped. Everything here runs AFTER the verdict was decided and after telemetry
8
8
  * read the full result; none of it can change a verdict.
9
9
  */
10
- import { ReticleTool } from '@reticlehq/core';
10
+ import { existsSync, readFileSync } from 'node:fs';
11
+ import { AgentRules, ReticleTool } from '@reticlehq/core';
11
12
  import { addAppNote, readAppNotes } from './app-notes.js';
12
13
  import { shapeForAgent, wantsFull } from './compact-envelope.js';
13
14
  import { learnFromVerdict } from './app-notes-learning.js';
14
15
  import { reteachFor } from './reteach.js';
15
16
  import { staleBuildNotice } from './build-staleness.js';
16
17
  import { PRIMER_POINTER, foldNotices } from './notices.js';
17
- import { dirname } from 'node:path';
18
+ import { dirname, join } from 'node:path';
18
19
  import { keychainNoticeOnce, projectReader } from '../../../command/cli/doctor/doctor-signing-line.js';
20
+ const GIT_DIR = '.git';
21
+ /** A file's text, or empty when it cannot be read: a pointer is never worth a failed answer. */
22
+ function textOf(path) {
23
+ try {
24
+ return readFileSync(path, 'utf8');
25
+ }
26
+ catch {
27
+ return '';
28
+ }
29
+ }
30
+ /** Whether `dir`, or a folder above it up to the repository root, has a rules file with the section. */
31
+ function rulesSectionAbove(dir) {
32
+ for (let at = dir;; at = dirname(at)) {
33
+ for (const file of AgentRules.FILES) {
34
+ if (textOf(join(at, file)).includes(AgentRules.BEGIN)) {
35
+ return true;
36
+ }
37
+ }
38
+ if (existsSync(join(at, GIT_DIR)) || dirname(at) === at) {
39
+ return false;
40
+ }
41
+ }
42
+ }
43
+ /** Read once per agent session: the pointer is said once, on the first answer. */
44
+ const sectionByAttach = new Map();
45
+ /**
46
+ * Only where `init` wrote the section. In an unwired project the pointer named a file that did not
47
+ * exist, so the agent was sent to read nothing.
48
+ */
49
+ function primerPointerFor(attach, project) {
50
+ let has = sectionByAttach.get(attach);
51
+ if (has === undefined) {
52
+ has = project !== undefined && rulesSectionAbove(project);
53
+ sectionByAttach.set(attach, has);
54
+ }
55
+ return has ? [PRIMER_POINTER] : [];
56
+ }
19
57
  const isRecord = (value) => 'object' === typeof value && null !== value && !Array.isArray(value);
20
58
  export function forTheAgent(answer) {
21
59
  const { name, args, attach, root } = answer;
@@ -37,7 +75,7 @@ export function forTheAgent(answer) {
37
75
  return foldNotices(shaped, attach, answer.fold, [
38
76
  ...(stale === undefined ? [] : [stale]),
39
77
  ...(keychain === undefined ? [] : [keychain]),
40
- PRIMER_POINTER,
78
+ ...primerPointerFor(attach, project),
41
79
  ...notes,
42
80
  ...reteachFor(attach, name, args, shaped),
43
81
  ]);
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Pure: no IO, no clock.
12
12
  */
13
- import { compareSourceClauses, isConsequenceKind, isPresenceKind, PredicateKind, } from '@reticlehq/core';
13
+ import { compareSourceClauses, ElementState, isConsequenceKind, isPresenceKind, PredicateKind, } from '@reticlehq/core';
14
14
  import { HonestyGrade, strongerGrade, weakerGrade } from '@reticlehq/engine/evidence/honesty.js';
15
15
  export const PRESENCE_ONLY_ADVICE = 'This predicate only checks element/text presence, not an observable consequence. A locator healed to the wrong element (or a stale render) can satisfy it while the feature is broken. Prefer a { signal } or { net } assertion (or allOf it with one) so green means the feature actually worked.';
16
16
  function walk(predicate, negated = false) {
@@ -43,7 +43,7 @@ function walk(predicate, negated = false) {
43
43
  };
44
44
  }
45
45
  /**
46
- * An element predicate that checks the element's CONTENT, not merely that it is there.
46
+ * An element predicate that checks its content or state, not merely that it is there.
47
47
  *
48
48
  * The presence nudge exists because "a locator healed to the wrong element, or a stale render, can
49
49
  * satisfy this while the feature is broken". That is exactly true of `{ element, role, name }` and
@@ -58,7 +58,12 @@ function walk(predicate, negated = false) {
58
58
  function assertsElementContent(predicate) {
59
59
  if (predicate.kind !== PredicateKind.ELEMENT)
60
60
  return false;
61
- return predicate.query?.value !== undefined || predicate.query?.text !== undefined;
61
+ return (predicate.query?.value !== undefined ||
62
+ predicate.query?.text !== undefined ||
63
+ (predicate.state !== undefined &&
64
+ predicate.state !== ElementState.PRESENT &&
65
+ predicate.state !== ElementState.VISIBLE &&
66
+ predicate.state !== ElementState.HIDDEN));
62
67
  }
63
68
  /**
64
69
  * True when the predicate asserts ONLY element/text presence with no signal/net consequence anywhere