@reticlehq/server 3.6.0 → 3.7.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 (614) hide show
  1. package/SKILL.md +122 -123
  2. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  3. package/dist/command/cli/adhoc-suite.js +42 -7
  4. package/dist/command/cli/adhoc-verdict.d.ts +18 -2
  5. package/dist/command/cli/adhoc-verdict.js +70 -6
  6. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  7. package/dist/command/cli/answers/gate-exit.js +45 -0
  8. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  9. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  10. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  11. package/dist/command/cli/auth/device-flow.js +17 -0
  12. package/dist/command/cli/cli-doctor.js +14 -0
  13. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  14. package/dist/command/cli/cli-flow-commands.js +28 -105
  15. package/dist/command/cli/cli-kill.js +3 -2
  16. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  17. package/dist/command/cli/cli-parse-grammar.js +75 -0
  18. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  19. package/dist/command/cli/cli-parse-verify.js +18 -0
  20. package/dist/command/cli/cli-parse.d.ts +19 -28
  21. package/dist/command/cli/cli-parse.js +82 -182
  22. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  23. package/dist/command/cli/cli-update-commands.js +61 -9
  24. package/dist/command/cli/cli-usage.d.ts +33 -0
  25. package/dist/command/cli/cli-usage.js +287 -0
  26. package/dist/command/cli/cli-verify.d.ts +34 -4
  27. package/dist/command/cli/cli-verify.js +81 -12
  28. package/dist/command/cli/cloud-cli.d.ts +13 -0
  29. package/dist/command/cli/cloud-cli.js +145 -333
  30. package/dist/command/cli/cloud-kit.d.ts +12 -0
  31. package/dist/command/cli/cloud-kit.js +41 -2
  32. package/dist/command/cli/cloud-link.d.ts +57 -0
  33. package/dist/command/cli/cloud-link.js +308 -0
  34. package/dist/command/cli/cloud-login.d.ts +15 -1
  35. package/dist/command/cli/cloud-login.js +67 -13
  36. package/dist/command/cli/context-command.d.ts +1 -0
  37. package/dist/command/cli/context-command.js +33 -0
  38. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  39. package/dist/command/cli/daemon-start-options.js +24 -3
  40. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  41. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  42. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  43. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  44. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  45. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  46. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  47. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  48. package/dist/command/cli/known-regression.d.ts +13 -0
  49. package/dist/command/cli/known-regression.js +34 -0
  50. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  51. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  52. package/dist/command/cli/lifecycle/daemon-lifecycle.js +11 -2
  53. package/dist/command/cli/mcp-command.d.ts +6 -0
  54. package/dist/command/cli/mcp-command.js +13 -5
  55. package/dist/command/cli/ports/port-holder.js +1 -1
  56. package/dist/command/cli/project-name.d.ts +29 -1
  57. package/dist/command/cli/project-name.js +107 -2
  58. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  59. package/dist/command/cli/setup-mcp-cli.js +29 -8
  60. package/dist/command/cli/status/status-lines.d.ts +1 -0
  61. package/dist/command/cli/status/status-lines.js +47 -2
  62. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  63. package/dist/command/cli/status/workspace-links.js +29 -0
  64. package/dist/command/cli/try-command.d.ts +96 -0
  65. package/dist/command/cli/try-command.js +362 -0
  66. package/dist/command/cli/tutorial.d.ts +0 -100
  67. package/dist/command/cli/tutorial.js +0 -178
  68. package/dist/command/cli/verify-results.d.ts +19 -0
  69. package/dist/command/cli/verify-results.js +29 -0
  70. package/dist/command/cli-onboarding.d.ts +0 -11
  71. package/dist/command/cli-onboarding.js +0 -15
  72. package/dist/command/cli.d.ts +14 -0
  73. package/dist/command/cli.js +103 -83
  74. package/dist/command/daemon/daemon-resilience.js +4 -4
  75. package/dist/command/daemon/daemon-resolve.d.ts +9 -1
  76. package/dist/command/daemon/daemon-resolve.js +49 -10
  77. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  78. package/dist/command/setup/bringup/bridge-port.js +13 -3
  79. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  80. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  81. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  82. package/dist/command/setup/init/agent-restart.js +28 -0
  83. package/dist/command/setup/init/init-port.d.ts +10 -1
  84. package/dist/command/setup/init/init-port.js +22 -2
  85. package/dist/command/setup/init/init-runtime.d.ts +12 -2
  86. package/dist/command/setup/init/init-runtime.js +96 -37
  87. package/dist/command/setup/node-effects.d.ts +2 -0
  88. package/dist/command/setup/node-effects.js +36 -8
  89. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  90. package/dist/command/setup/probe/existing-app.js +14 -0
  91. package/dist/command/setup/remaining-steps.js +1 -1
  92. package/dist/command/setup/run-setup.d.ts +29 -9
  93. package/dist/command/setup/run-setup.js +34 -28
  94. package/dist/command/setup/setup-command.d.ts +23 -0
  95. package/dist/command/setup/setup-command.js +57 -4
  96. package/dist/command/setup/setup-mcp.js +25 -2
  97. package/dist/command/setup/tauri-signing.d.ts +19 -0
  98. package/dist/command/setup/tauri-signing.js +79 -0
  99. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  100. package/dist/command/setup/terminal/listeners.js +37 -6
  101. package/dist/command/update/update-nudge.d.ts +9 -0
  102. package/dist/command/update/update-nudge.js +1 -1
  103. package/dist/command/update/updater.js +11 -15
  104. package/dist/command/version/version-nudge.js +3 -0
  105. package/dist/command/version/version-skew.d.ts +20 -1
  106. package/dist/command/version/version-skew.js +38 -2
  107. package/dist/features/crawl/crawl.js +14 -1
  108. package/dist/features/exhaust/ledger.d.ts +14 -14
  109. package/dist/features/harness/drive-report.d.ts +39 -5
  110. package/dist/features/harness/drive-report.js +271 -54
  111. package/dist/features/harness/drive-runs.d.ts +120 -0
  112. package/dist/features/harness/drive-runs.js +289 -0
  113. package/dist/features/harness/drivers.d.ts +1 -1
  114. package/dist/features/harness/drivers.js +1 -1
  115. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  116. package/dist/features/harness/explore/console-pages.js +146 -0
  117. package/dist/features/harness/explore/disparity.d.ts +19 -0
  118. package/dist/features/harness/explore/disparity.js +71 -0
  119. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  120. package/dist/features/harness/explore/fake-app.js +49 -0
  121. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  122. package/dist/features/harness/explore/goal-search.js +144 -0
  123. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  124. package/dist/features/harness/explore/page-tree.js +148 -0
  125. package/dist/features/harness/explore/site-map.d.ts +34 -0
  126. package/dist/features/harness/explore/site-map.js +150 -0
  127. package/dist/features/harness/goals.d.ts +68 -7
  128. package/dist/features/harness/goals.js +289 -36
  129. package/dist/features/harness/harness.d.ts +30 -1
  130. package/dist/features/harness/harness.js +141 -7
  131. package/dist/features/harness/platform/local-apps.d.ts +36 -3
  132. package/dist/features/harness/platform/local-apps.js +81 -5
  133. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  134. package/dist/features/harness/platform/persona-credentials.js +69 -0
  135. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  136. package/dist/features/harness/platform/platform-drives.js +114 -0
  137. package/dist/features/harness/platform/refusal.d.ts +52 -0
  138. package/dist/features/harness/platform/refusal.js +71 -0
  139. package/dist/features/harness/platform/remote-drive.d.ts +8 -2
  140. package/dist/features/harness/platform/remote-drive.js +22 -9
  141. package/dist/features/harness/platform/script.d.ts +57 -11
  142. package/dist/features/harness/platform/script.js +144 -12
  143. package/dist/features/harness/platform/server-driver.d.ts +17 -4
  144. package/dist/features/harness/platform/server-driver.js +29 -26
  145. package/dist/features/harness/platform-config.d.ts +38 -5
  146. package/dist/features/harness/platform-config.js +93 -8
  147. package/dist/features/harness/route-guess.d.ts +13 -0
  148. package/dist/features/harness/route-guess.js +49 -0
  149. package/dist/features/harness/script/script-run.d.ts +30 -1
  150. package/dist/features/harness/script/script-run.js +355 -48
  151. package/dist/features/license/license.d.ts +2 -2
  152. package/dist/features/visual/step-shots.d.ts +31 -0
  153. package/dist/features/visual/step-shots.js +231 -0
  154. package/dist/features/visual/visual-tools.js +22 -14
  155. package/dist/hooks/client-directory.d.ts +18 -0
  156. package/dist/hooks/client-directory.js +57 -0
  157. package/dist/hooks/coding-agents.d.ts +34 -0
  158. package/dist/hooks/coding-agents.js +117 -0
  159. package/dist/hooks/driven-by.d.ts +21 -2
  160. package/dist/hooks/driven-by.js +42 -2
  161. package/dist/hooks/hook-bus.d.ts +4 -0
  162. package/dist/hooks/hook-bus.js +18 -0
  163. package/dist/index.d.ts +1 -0
  164. package/dist/index.js +26 -183
  165. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  166. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  167. package/dist/judgement/capsule/causal-summary.js +33 -0
  168. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  169. package/dist/judgement/runs/artifact/build-verification-run.js +20 -4
  170. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  171. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  172. package/dist/judgement/runs/artifact/replay-mapping.js +25 -9
  173. package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
  174. package/dist/judgement/runs/artifact/run-store.js +175 -8
  175. package/dist/judgement/runs/context-tools.js +59 -1
  176. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  177. package/dist/judgement/runs/default-run-id.js +16 -0
  178. package/dist/judgement/runs/drive-run.d.ts +53 -5
  179. package/dist/judgement/runs/drive-run.js +234 -20
  180. package/dist/judgement/runs/resume.d.ts +44 -0
  181. package/dist/judgement/runs/resume.js +137 -0
  182. package/dist/judgement/runs/reticle-runner.js +5 -2
  183. package/dist/judgement/runs/runner-port.d.ts +5 -1
  184. package/dist/judgement/runs/runner-port.js +8 -2
  185. package/dist/judgement/runs/verification-sync.d.ts +2 -0
  186. package/dist/judgement/runs/verification-sync.js +36 -15
  187. package/dist/language/flows/decision.js +2 -1
  188. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  189. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  190. package/dist/language/flows/flow-anchor.d.ts +7 -2
  191. package/dist/language/flows/flow-anchor.js +10 -3
  192. package/dist/language/flows/flow-intent.d.ts +1 -0
  193. package/dist/language/flows/flow-journey.d.ts +6 -0
  194. package/dist/language/flows/flow-journey.js +20 -0
  195. package/dist/language/flows/flow-learning.d.ts +4 -0
  196. package/dist/language/flows/flow-learning.js +37 -3
  197. package/dist/language/flows/flow-replay-run.js +16 -18
  198. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  199. package/dist/language/flows/flow-replay.d.ts +18 -1
  200. package/dist/language/flows/flow-replay.js +22 -7
  201. package/dist/language/flows/flow-result.d.ts +22 -1
  202. package/dist/language/flows/flow-result.js +47 -2
  203. package/dist/language/flows/flow-step-runners.d.ts +2 -0
  204. package/dist/language/flows/flow-step-runners.js +12 -6
  205. package/dist/language/flows/flow-store-for-session.js +5 -1
  206. package/dist/language/flows/flow-tools.d.ts +10 -0
  207. package/dist/language/flows/flow-tools.js +61 -62
  208. package/dist/language/flows/flows.d.ts +16 -1
  209. package/dist/language/flows/flows.js +69 -10
  210. package/dist/language/flows/narrow-write.d.ts +7 -0
  211. package/dist/language/flows/narrow-write.js +36 -1
  212. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  213. package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
  214. package/dist/language/flows/recording/tape/recordings.js +60 -10
  215. package/dist/language/flows/replay.js +29 -6
  216. package/dist/language/flows/single-replay.d.ts +7 -0
  217. package/dist/language/flows/single-replay.js +26 -0
  218. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  219. package/dist/language/flows/verify-change-tools.js +200 -193
  220. package/dist/memory/cloud/cloud-config.d.ts +10 -1
  221. package/dist/memory/cloud/cloud-config.js +19 -5
  222. package/dist/memory/cloud/cloud-sync.js +3 -3
  223. package/dist/memory/cloud/harness-config.d.ts +49 -0
  224. package/dist/memory/cloud/harness-config.js +16 -20
  225. package/dist/memory/cloud/memory-scope.d.ts +17 -0
  226. package/dist/memory/cloud/memory-scope.js +22 -0
  227. package/dist/memory/cloud/sync-cycle.d.ts +32 -4
  228. package/dist/memory/cloud/sync-cycle.js +113 -12
  229. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  230. package/dist/memory/cloud/sync-daemon.js +114 -4
  231. package/dist/memory/cloud/sync-disk.js +26 -2
  232. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  233. package/dist/memory/cloud/sync-screenshots.js +105 -0
  234. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  235. package/dist/memory/cloud/unsynced-roots.js +166 -0
  236. package/dist/memory/impact/account-watch.d.ts +16 -1
  237. package/dist/memory/impact/account-watch.js +26 -1
  238. package/dist/memory/impact/impact-store.d.ts +1 -4
  239. package/dist/memory/impact/impact-store.js +32 -42
  240. package/dist/memory/intent/inline-intent.d.ts +1 -0
  241. package/dist/memory/intent/intent-shard-store.js +16 -4
  242. package/dist/memory/intent/intent-shard.d.ts +12 -0
  243. package/dist/memory/intent/intent-store.d.ts +1 -0
  244. package/dist/memory/intent/intent-tools.js +42 -2
  245. package/dist/memory/intent/open-intents.d.ts +6 -0
  246. package/dist/memory/intent/open-intents.js +10 -1
  247. package/dist/memory/intent/settled-words.d.ts +24 -0
  248. package/dist/memory/intent/settled-words.js +130 -0
  249. package/dist/memory/journal/drive-flow.d.ts +16 -0
  250. package/dist/memory/journal/drive-flow.js +34 -2
  251. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  252. package/dist/memory/journal/drive-run-flush.js +20 -5
  253. package/dist/memory/journal/journal-recorder.js +46 -3
  254. package/dist/memory/journal/on-disk/retention.d.ts +5 -0
  255. package/dist/memory/journal/on-disk/retention.js +27 -2
  256. package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
  257. package/dist/memory/journal/session-end.d.ts +15 -1
  258. package/dist/memory/journal/session-end.js +38 -7
  259. package/dist/memory/project/artifact-root-resolver.js +33 -5
  260. package/dist/memory/project/artifact-root.d.ts +4 -3
  261. package/dist/memory/project/artifact-root.js +2 -2
  262. package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
  263. package/dist/memory/project/dir/reticle-dir.js +23 -2
  264. package/dist/memory/project/link-directory.d.ts +15 -0
  265. package/dist/memory/project/link-directory.js +44 -0
  266. package/dist/memory/project/root-claims.d.ts +6 -0
  267. package/dist/memory/project/root-claims.js +39 -0
  268. package/dist/memory/project/session-root.d.ts +2 -0
  269. package/dist/memory/project/session-root.js +9 -1
  270. package/dist/memory/project/sync-status.d.ts +46 -0
  271. package/dist/memory/project/sync-status.js +135 -1
  272. package/dist/memory/recall/memory-tools.js +46 -3
  273. package/dist/memory/recall/platform-memory.d.ts +34 -0
  274. package/dist/memory/recall/platform-memory.js +139 -0
  275. package/dist/memory/recall/project-memory.js +36 -8
  276. package/dist/portal/bridge/bridge.d.ts +9 -5
  277. package/dist/portal/bridge/bridge.js +66 -23
  278. package/dist/portal/bridge/harness-request.d.ts +23 -0
  279. package/dist/portal/bridge/harness-request.js +27 -0
  280. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  281. package/dist/portal/bridge/wrong-path.js +35 -0
  282. package/dist/portal/input/network-mock-tools.js +11 -2
  283. package/dist/portal/input/real-input.d.ts +2 -0
  284. package/dist/portal/input/real-input.js +13 -10
  285. package/dist/portal/pool/browser-pool.d.ts +48 -0
  286. package/dist/portal/pool/browser-pool.js +120 -2
  287. package/dist/portal/pool/context-permissions.d.ts +33 -0
  288. package/dist/portal/pool/context-permissions.js +33 -0
  289. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  290. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  291. package/dist/portal/pool/playwright-launcher.d.ts +27 -5
  292. package/dist/portal/pool/playwright-launcher.js +59 -14
  293. package/dist/portal/pool/pool-contract.d.ts +21 -1
  294. package/dist/portal/session/agent-link.d.ts +8 -0
  295. package/dist/portal/session/agent-link.js +17 -0
  296. package/dist/portal/session/command-payload.js +6 -1
  297. package/dist/portal/session/daemon-answers.d.ts +3 -3
  298. package/dist/portal/session/daemon-answers.js +4 -2
  299. package/dist/portal/session/dev-server/dev-command.d.ts +9 -0
  300. package/dist/portal/session/dev-server/dev-command.js +27 -1
  301. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  302. package/dist/portal/session/facts/observed-state.js +46 -3
  303. package/dist/portal/session/human/live-control.d.ts +9 -2
  304. package/dist/portal/session/human/live-control.js +12 -3
  305. package/dist/portal/session/live-control-tools.js +82 -13
  306. package/dist/portal/session/narration-args.d.ts +5 -0
  307. package/dist/portal/session/narration-args.js +17 -0
  308. package/dist/portal/session/no-session-diagnosis.d.ts +1 -1
  309. package/dist/portal/session/no-session-diagnosis.js +31 -9
  310. package/dist/portal/session/no-session-next-action.d.ts +20 -0
  311. package/dist/portal/session/no-session-next-action.js +134 -61
  312. package/dist/portal/session/no-session-watch.js +179 -22
  313. package/dist/portal/session/presence/session-lease.js +1 -1
  314. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  315. package/dist/portal/session/recorded-gaps.js +251 -0
  316. package/dist/portal/session/session-health.d.ts +11 -0
  317. package/dist/portal/session/session-health.js +3 -1
  318. package/dist/portal/session/session-info.js +2 -1
  319. package/dist/portal/session/session-manager.d.ts +18 -0
  320. package/dist/portal/session/session-manager.js +54 -3
  321. package/dist/portal/session/session-successor.d.ts +8 -0
  322. package/dist/portal/session/session-successor.js +1 -1
  323. package/dist/portal/session/session.d.ts +15 -28
  324. package/dist/portal/session/session.js +60 -61
  325. package/dist/portal/session/timing/command-timeout.js +25 -1
  326. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  327. package/dist/portal/session/timing/wall-clock.js +1 -1
  328. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  329. package/dist/portal/session/zero-install-first-call.js +88 -0
  330. package/dist/start-options.d.ts +7 -1
  331. package/dist/start-wiring.d.ts +63 -0
  332. package/dist/start-wiring.js +169 -0
  333. package/dist/status-payload.d.ts +13 -1
  334. package/dist/status-payload.js +13 -1
  335. package/dist/surface/http-server.js +7 -1
  336. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  337. package/dist/surface/mcp/attach-memory.js +12 -1
  338. package/dist/surface/mcp/mcp-proxy.d.ts +4 -0
  339. package/dist/surface/mcp/mcp-proxy.js +29 -8
  340. package/dist/surface/mcp/mcp.d.ts +23 -0
  341. package/dist/surface/mcp/mcp.js +34 -4
  342. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  343. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  344. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  345. package/dist/surface/mcp/server-instructions.js +22 -14
  346. package/dist/surface/mcp/shared-params.js +1 -1
  347. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  348. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  349. package/dist/surface/tools/account-tool.d.ts +22 -0
  350. package/dist/surface/tools/account-tool.js +157 -0
  351. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  352. package/dist/surface/tools/act/act-danger.js +38 -1
  353. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  354. package/dist/surface/tools/act/act-observation.js +57 -0
  355. package/dist/surface/tools/act/act-preflight.js +25 -2
  356. package/dist/surface/tools/act/act-target.js +8 -3
  357. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  358. package/dist/surface/tools/act/resolve-target.js +18 -3
  359. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  360. package/dist/surface/tools/act/screen-request.js +113 -0
  361. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  362. package/dist/surface/tools/act/sequence-grade.js +13 -2
  363. package/dist/surface/tools/act-sequence-tool.js +136 -27
  364. package/dist/surface/tools/act-tools.d.ts +0 -9
  365. package/dist/surface/tools/act-tools.js +48 -34
  366. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  367. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  368. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  369. package/dist/surface/tools/agent/app-notes.js +48 -0
  370. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  371. package/dist/surface/tools/agent/build-staleness.js +62 -0
  372. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  373. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  374. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  375. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  376. package/dist/surface/tools/agent/notices.d.ts +50 -0
  377. package/dist/surface/tools/agent/notices.js +152 -0
  378. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  379. package/dist/surface/tools/agent/reteach.js +50 -0
  380. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  381. package/dist/surface/tools/args/alias-args.js +10 -0
  382. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  383. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  384. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  385. package/dist/surface/tools/assert/assert-source.js +40 -0
  386. package/dist/surface/tools/assert/assert-verdict.js +25 -15
  387. package/dist/surface/tools/browser-tools.js +43 -1
  388. package/dist/surface/tools/chat-drives.d.ts +75 -0
  389. package/dist/surface/tools/chat-drives.js +265 -21
  390. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  391. package/dist/surface/tools/coverage-tools.js +2 -53
  392. package/dist/surface/tools/dynamic-tools.js +29 -1
  393. package/dist/surface/tools/empty-session-list.d.ts +10 -0
  394. package/dist/surface/tools/empty-session-list.js +45 -5
  395. package/dist/surface/tools/error-recovery.d.ts +8 -0
  396. package/dist/surface/tools/error-recovery.js +69 -5
  397. package/dist/surface/tools/explore-tools.d.ts +23 -2
  398. package/dist/surface/tools/explore-tools.js +377 -74
  399. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  400. package/dist/surface/tools/feedback-tools.js +4 -3
  401. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  402. package/dist/surface/tools/gap-novelty.js +8 -1
  403. package/dist/surface/tools/harness-explore.d.ts +52 -73
  404. package/dist/surface/tools/harness-explore.js +177 -146
  405. package/dist/surface/tools/harness-gate.d.ts +88 -0
  406. package/dist/surface/tools/harness-gate.js +235 -0
  407. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  408. package/dist/surface/tools/harness-hunt.js +215 -0
  409. package/dist/surface/tools/harness-plan.d.ts +5 -0
  410. package/dist/surface/tools/harness-plan.js +7 -0
  411. package/dist/surface/tools/harness-script.d.ts +22 -0
  412. package/dist/surface/tools/harness-script.js +256 -38
  413. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  414. package/dist/surface/tools/harness-tab-guard.js +27 -0
  415. package/dist/surface/tools/harness-toolset.d.ts +8 -0
  416. package/dist/surface/tools/harness-toolset.js +27 -4
  417. package/dist/surface/tools/human-notes.d.ts +16 -0
  418. package/dist/surface/tools/human-notes.js +27 -0
  419. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  420. package/dist/surface/tools/invoke-tool.js +220 -93
  421. package/dist/surface/tools/lease-hint.js +26 -5
  422. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  423. package/dist/surface/tools/lease-permissions.js +73 -0
  424. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  425. package/dist/surface/tools/lease-readiness.js +57 -0
  426. package/dist/surface/tools/lease-seed.d.ts +20 -0
  427. package/dist/surface/tools/lease-seed.js +45 -1
  428. package/dist/surface/tools/lease-tools.d.ts +10 -1
  429. package/dist/surface/tools/lease-tools.js +119 -69
  430. package/dist/surface/tools/live-call-text.js +2 -2
  431. package/dist/surface/tools/merge-tools.js +42 -2
  432. package/dist/surface/tools/merged-name-redirect.js +4 -0
  433. package/dist/surface/tools/next-step.d.ts +11 -1
  434. package/dist/surface/tools/next-step.js +73 -18
  435. package/dist/surface/tools/observe-tools.js +43 -5
  436. package/dist/surface/tools/platform-moment.d.ts +60 -0
  437. package/dist/surface/tools/platform-moment.js +132 -4
  438. package/dist/surface/tools/read-tools.js +65 -14
  439. package/dist/surface/tools/reticle-result.d.ts +120 -0
  440. package/dist/surface/tools/reticle-result.js +364 -0
  441. package/dist/surface/tools/tool-kit.d.ts +68 -2
  442. package/dist/surface/tools/tool-kit.js +73 -1
  443. package/dist/surface/tools/tools.js +25 -13
  444. package/dist/telemetry/account-envelope.d.ts +7 -0
  445. package/dist/telemetry/account-envelope.js +61 -0
  446. package/dist/telemetry/agent-client.d.ts +15 -0
  447. package/dist/telemetry/agent-client.js +57 -0
  448. package/dist/telemetry/app-instrumented.js +9 -2
  449. package/dist/telemetry/argument-shape.d.ts +7 -0
  450. package/dist/telemetry/argument-shape.js +86 -1
  451. package/dist/telemetry/automation-hint.d.ts +2 -3
  452. package/dist/telemetry/automation-hint.js +33 -8
  453. package/dist/telemetry/cli-telemetry.js +7 -2
  454. package/dist/telemetry/daemon-telemetry.js +3 -0
  455. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  456. package/dist/telemetry/error-fingerprint.js +61 -5
  457. package/dist/telemetry/feedback-cli.d.ts +0 -13
  458. package/dist/telemetry/feedback-cli.js +0 -77
  459. package/dist/telemetry/feedback.d.ts +13 -0
  460. package/dist/telemetry/feedback.js +183 -17
  461. package/dist/telemetry/harness-run.d.ts +18 -0
  462. package/dist/telemetry/harness-run.js +80 -0
  463. package/dist/telemetry/hud-events.d.ts +16 -0
  464. package/dist/telemetry/hud-events.js +27 -0
  465. package/dist/telemetry/hud-metrics.d.ts +27 -6
  466. package/dist/telemetry/hud-metrics.js +99 -25
  467. package/dist/telemetry/init-telemetry.js +2 -2
  468. package/dist/telemetry/install-source.d.ts +13 -25
  469. package/dist/telemetry/install-source.js +44 -3
  470. package/dist/telemetry/mcp-connection.d.ts +0 -14
  471. package/dist/telemetry/mcp-connection.js +5 -1
  472. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  473. package/dist/telemetry/onboarding-firsts.js +81 -6
  474. package/dist/telemetry/platform-linked.d.ts +5 -0
  475. package/dist/telemetry/platform-linked.js +32 -0
  476. package/dist/telemetry/project-profile.js +5 -3
  477. package/dist/telemetry/proxy-telemetry.js +4 -1
  478. package/dist/telemetry/session-metrics.d.ts +15 -4
  479. package/dist/telemetry/session-metrics.js +88 -52
  480. package/dist/telemetry/telemetry.d.ts +26 -2
  481. package/dist/telemetry/telemetry.js +102 -21
  482. package/dist/telemetry/verification-of.d.ts +3 -1
  483. package/dist/telemetry/verification-of.js +12 -4
  484. package/dist/wire-journal.d.ts +2 -2
  485. package/dist/wire-journal.js +16 -5
  486. package/docs/README.md +2 -2
  487. package/docs/actions.mdx +6 -3
  488. package/docs/adapters.md +1 -1
  489. package/docs/agent-cheatsheet.md +24 -27
  490. package/docs/architecture.md +5 -5
  491. package/docs/autodrive.md +13 -12
  492. package/docs/benchmarks.md +5 -5
  493. package/docs/best-practices.mdx +27 -9
  494. package/docs/capabilities.mdx +14 -16
  495. package/docs/cli/affected.mdx +1 -1
  496. package/docs/cli/cloud.mdx +54 -75
  497. package/docs/cli/doctor.mdx +8 -3
  498. package/docs/cli/drive.mdx +12 -12
  499. package/docs/cli/feedback.mdx +3 -3
  500. package/docs/cli/gate.mdx +7 -2
  501. package/docs/cli/help.mdx +50 -55
  502. package/docs/cli/init.mdx +32 -15
  503. package/docs/cli/license.mdx +12 -8
  504. package/docs/cli/mcp.mdx +4 -4
  505. package/docs/cli/open.mdx +3 -3
  506. package/docs/cli/report.mdx +4 -2
  507. package/docs/cli/restart.mdx +2 -2
  508. package/docs/cli/rollback.mdx +14 -8
  509. package/docs/cli/serve.mdx +4 -4
  510. package/docs/cli/setup.mdx +23 -0
  511. package/docs/cli/status.mdx +13 -4
  512. package/docs/cli/stop.mdx +67 -8
  513. package/docs/cli/try.mdx +62 -0
  514. package/docs/cli/update.mdx +4 -3
  515. package/docs/cli/verify.mdx +17 -6
  516. package/docs/cli/version.mdx +3 -2
  517. package/docs/cli.mdx +110 -41
  518. package/docs/debugging.md +3 -3
  519. package/docs/deploy-checks.md +1 -1
  520. package/docs/desktop.mdx +5 -3
  521. package/docs/enterprise.md +11 -10
  522. package/docs/environment.mdx +5 -2
  523. package/docs/faq.mdx +3 -3
  524. package/docs/first-drive.md +5 -4
  525. package/docs/flows.md +35 -27
  526. package/docs/for-agents.md +4 -5
  527. package/docs/frameworks.mdx +32 -21
  528. package/docs/getting-started.md +66 -64
  529. package/docs/human-control.md +15 -14
  530. package/docs/index.mdx +15 -43
  531. package/docs/install-agentic.mdx +22 -37
  532. package/docs/install-manual.mdx +22 -12
  533. package/docs/instrumentation.mdx +5 -3
  534. package/docs/integration-patterns.md +7 -7
  535. package/docs/license-activation.mdx +1 -1
  536. package/docs/multi-agent-testing.md +24 -6
  537. package/docs/packages/babel-plugin.mdx +4 -2
  538. package/docs/packages/browser.mdx +16 -10
  539. package/docs/packages/core.mdx +12 -5
  540. package/docs/packages/electron.mdx +3 -2
  541. package/docs/packages/engine.mdx +1 -1
  542. package/docs/packages/eslint-plugin.mdx +18 -12
  543. package/docs/packages/next.mdx +8 -7
  544. package/docs/packages/open-verification.mdx +1 -1
  545. package/docs/packages/server.mdx +5 -5
  546. package/docs/packages/tauri.mdx +8 -8
  547. package/docs/packages/test.mdx +4 -10
  548. package/docs/packages/vite-plugin.mdx +11 -4
  549. package/docs/packages.mdx +11 -15
  550. package/docs/platform-integration.md +6 -5
  551. package/docs/predicates.mdx +40 -24
  552. package/docs/quickstart.mdx +58 -29
  553. package/docs/required-checks.md +8 -7
  554. package/docs/reticle-manual.md +15 -5
  555. package/docs/skill-file.mdx +17 -79
  556. package/docs/skill-setup.md +9 -9
  557. package/docs/skill.md +200 -0
  558. package/docs/system-map.md +7 -7
  559. package/docs/telemetry.md +22 -24
  560. package/docs/testing.md +4 -4
  561. package/docs/token-efficiency.md +12 -12
  562. package/docs/tools/act-and-wait.mdx +9 -2
  563. package/docs/tools/act-sequence.mdx +6 -7
  564. package/docs/tools/act.mdx +2 -2
  565. package/docs/tools/assert.mdx +18 -17
  566. package/docs/tools/console.mdx +9 -9
  567. package/docs/tools/inspect.mdx +16 -7
  568. package/docs/tools/look.mdx +24 -0
  569. package/docs/tools/navigate.mdx +5 -3
  570. package/docs/tools/network.mdx +2 -2
  571. package/docs/tools/observe.mdx +6 -6
  572. package/docs/tools/overview.mdx +34 -33
  573. package/docs/tools/query.mdx +5 -5
  574. package/docs/tools/session-and-feedback.mdx +13 -4
  575. package/docs/tools/sessions.mdx +8 -8
  576. package/docs/tools/snapshot.mdx +6 -5
  577. package/docs/tools/state.mdx +9 -9
  578. package/docs/tools/tools-and-run.mdx +26 -24
  579. package/docs/tools/verify.mdx +28 -0
  580. package/docs/tools/wait-for.mdx +8 -4
  581. package/docs/troubleshooting.mdx +21 -6
  582. package/docs/usage.md +51 -45
  583. package/docs/use-cases.mdx +3 -3
  584. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  585. package/docs/vs-playwright-mcp.mdx +3 -1
  586. package/docs/what-is-recorded.md +7 -5
  587. package/docs/what-is-reticle.mdx +2 -2
  588. package/docs/why-reticle.mdx +1 -1
  589. package/package.json +6 -5
  590. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  591. package/dist/command/cli/demo/demo-page.js +0 -249
  592. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  593. package/dist/command/cli/demo/demo-run.js +0 -138
  594. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  595. package/dist/judgement/hunt/hunt-report.js +0 -84
  596. package/dist/language/flows/buddy-status.d.ts +0 -25
  597. package/dist/language/flows/buddy-status.js +0 -32
  598. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  599. package/dist/language/flows/change/watch-batcher.js +0 -19
  600. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  601. package/dist/memory/cloud/harness-offer.js +0 -145
  602. package/dist/surface/tools/feature-capture.d.ts +0 -151
  603. package/dist/surface/tools/feature-capture.js +0 -235
  604. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  605. package/dist/surface/tools/tool-hit-rate.js +0 -90
  606. package/dist/telemetry/harness-drive.d.ts +0 -4
  607. package/dist/telemetry/harness-drive.js +0 -35
  608. package/dist/telemetry/identify.d.ts +0 -22
  609. package/dist/telemetry/identify.js +0 -73
  610. package/docs/cli/capsules.mdx +0 -70
  611. package/docs/cli/hunt.mdx +0 -73
  612. package/docs/cli/identify.mdx +0 -76
  613. package/docs/cli/kill.mdx +0 -91
  614. package/docs/cli/watch.mdx +0 -62
@@ -8,12 +8,14 @@
8
8
  * lighter per-flow RunRecord that feeds regression memory is synced separately in flow-replay-run.ts.
9
9
  * Both are best-effort + opt-in: no creds → the artifact still lands on disk, nothing leaves the machine.
10
10
  */
11
- import { mcpClientIdentity } from '../../surface/mcp/peer/client-identity.js';
12
- import { RunAgentKind, RunFramework, RunProfile, RunTrigger, } from '@reticlehq/core';
11
+ import { callerClientName } from '../../hooks/coding-agents.js';
12
+ import { currentDrivenBy } from '../../hooks/driven-by.js';
13
+ import { RunAgentKind, RunFramework, RunProfile, RunTrigger, asRunId, } from '@reticlehq/core';
13
14
  import { homedir } from 'node:os';
14
15
  import { buildVerificationRun, } from './artifact/build-verification-run.js';
15
16
  import { mapReplayToFlowResult } from './artifact/replay-mapping.js';
16
17
  import { defaultRunId } from './default-run-id.js';
18
+ import { currentShotRun } from './default-run-id.js';
17
19
  import { RunStore } from './artifact/run-store.js';
18
20
  import { cloudFetch, syncRunToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
19
21
  import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
@@ -21,29 +23,43 @@ import { log } from '../../log.js';
21
23
  import { rootForTarget } from '../../memory/project/session-root.js';
22
24
  /** The author of record when no MCP peer introduced itself — a CLI run, or a client that skipped the handshake. */
23
25
  const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
26
+ /** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
27
+ export const CLI_CLIENT_NAME = 'reticle-cli';
28
+ /**
29
+ * Who ran a suite, and why. The command line is the pipeline, whichever daemon replays for it:
30
+ * through a running daemon its runs read as a coding agent, trigger manual, credited to whoever
31
+ * minted the key, while the path that boots its own daemon said pipeline.
32
+ */
33
+ function agentAndTrigger(client) {
34
+ return CLI_CLIENT_NAME === client
35
+ ? { agent: { id: client, kind: RunAgentKind.OEM_PIPELINE }, trigger: { kind: RunTrigger.OEM } }
36
+ : {
37
+ agent: { id: client ?? RETICLE_MCP_AGENT_ID, kind: RunAgentKind.CODING_AGENT },
38
+ trigger: { kind: RunTrigger.MANUAL },
39
+ };
40
+ }
24
41
  /** Assemble the ReticleVerificationRun artifact for a verify suite (pure — no IO). */
25
- function assembleRun(deps, timed, projectId) {
42
+ function assembleRun(deps, timed,
43
+ /** The dashboard project this checkout is linked to, else the session's own id. */
44
+ projectName) {
26
45
  const flows = timed.map((t) => mapReplayToFlowResult(t.replay, t.durationMs, t.flow));
27
46
  const input = {
28
- runId: defaultRunId(),
47
+ // The run its replays' screenshots were filed under, when the verify minted one first.
48
+ runId: asRunId(currentShotRun() ?? defaultRunId()),
29
49
  durationMs: flows.reduce((sum, f) => sum + f.durationMs, 0),
30
50
  profile: RunProfile.DEV,
31
- project: { name: projectId ?? 'reticle', framework: RunFramework.OTHER },
51
+ project: { name: projectName ?? 'reticle', framework: RunFramework.OTHER },
32
52
  /*
33
53
  * WHICH agent drove this, not merely THAT one did.
34
54
  *
35
55
  * This was hardcoded to 'reticle-mcp', so every run in every workspace claimed the same author.
36
56
  * A dashboard built on it could say "an agent verified this" and never "Claude Code verified
37
57
  * this, Cursor broke it" — which is the question a team actually has once more than one agent
38
- * touches the repo. The name is the client's own claim from the MCP handshake; a plain CLI run
39
- * with no MCP peer keeps the old id, because inventing a vendor there would be worse than
40
- * admitting we do not know.
58
+ * touches the repo. The name is the client's own claim from the MCP handshake, for the call that
59
+ * ran this suite only; a plain CLI run, or a dashboard Re-verify no agent made, keeps the old id,
60
+ * because inventing a vendor there would be worse than admitting we do not know.
41
61
  */
42
- agent: {
43
- id: mcpClientIdentity().name ?? RETICLE_MCP_AGENT_ID,
44
- kind: RunAgentKind.CODING_AGENT,
45
- },
46
- trigger: { kind: RunTrigger.MANUAL },
62
+ ...agentAndTrigger(callerClientName()),
47
63
  changedFiles: [],
48
64
  flows,
49
65
  checks: [],
@@ -61,6 +77,10 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
61
77
  const { projectId } = target;
62
78
  if (0 === timed.length)
63
79
  return undefined;
80
+ // A replay the Harness made inside its own drive is part of that drive's run: written on its own
81
+ // it was a second row ("Passed · Flow replay · Your agent") beside the plan run it belonged to.
82
+ if (currentDrivenBy() !== undefined)
83
+ return undefined;
64
84
  let run;
65
85
  // The project the suite ran for, not the directory the daemon was started in. Both halves below
66
86
  // take it: the artifact `reticle_run` reads back through `sessionRoot`, and the cloud link that
@@ -68,8 +88,10 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
68
88
  // a misrouted read silently meant "not attached" — and where it DID have one, the run was pushed
69
89
  // to a dashboard belonging to whoever that checkout was linked to.
70
90
  const root = rootForTarget(deps, target);
91
+ const cloud = await resolveProjectCloud(deps.fs, root, homedir(), process.env);
71
92
  try {
72
- run = assembleRun(deps, timed, projectId);
93
+ // Named after the dashboard project the checkout is linked to: a Re-verify run read "reticle".
94
+ run = assembleRun(deps, timed, cloud.projectId ?? projectId);
73
95
  await new RunStore(deps.fs, root).write(run);
74
96
  }
75
97
  catch (error) {
@@ -79,7 +101,6 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
79
101
  return undefined;
80
102
  }
81
103
  // Per-project cloud: only push when THIS project has cloud attached AND its policy allows runs.
82
- const cloud = await resolveProjectCloud(deps.fs, root, homedir(), process.env);
83
104
  if (null === cloud.config || !cloud.policy.runs)
84
105
  return run.runId; // not attached / runs disabled → local only
85
106
  const result = await syncRunToCloud(run, cloud.config, cloudFetch);
@@ -165,7 +165,8 @@ invoked = new Map()) {
165
165
  ...(fix !== undefined ? { suggestedFix: fix } : {}),
166
166
  nextAction: fix !== undefined
167
167
  ? `${fix}, or update the flow if the change was intended.`
168
- : `inspect ${where ?? 'the step'} — the anchored element is gone; rebind or update the flow.`,
168
+ : `inspect ${where ?? 'the step'} — the anchored element is not on the page and nothing there looks like a rename. ` +
169
+ 'If the replay began somewhere the recording did not (signed out, another route), record the steps that reach this one; otherwise rebind or update the flow.',
169
170
  };
170
171
  }
171
172
  // status error: an action failed, or the success oracle was not satisfied (green-but-wrong).
@@ -1,4 +1,6 @@
1
+ import { z } from 'zod';
1
2
  import { type FlowAnchor, type FlowFile } from '@reticlehq/core';
3
+ import { CALL_SECRETS_ARG } from '../../../surface/tools/tool-kit.js';
2
4
  /**
3
5
  * What the anchor CALLS the field it points at.
4
6
  *
@@ -20,6 +22,8 @@ export declare function anchorFieldName(anchor: FlowAnchor): string | undefined;
20
22
  * reader what to do: the value belongs in the environment, not in a file they are about to commit.
21
23
  */
22
24
  export declare const REDACTED_FILL = "<redacted: supply at replay>";
25
+ /** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
26
+ export declare const SECRET_NAME_ARG = "secret";
23
27
  /**
24
28
  * The environment variable that supplies one redacted field.
25
29
  *
@@ -33,6 +37,14 @@ export declare const REDACTED_FILL = "<redacted: supply at replay>";
33
37
  * saying it had to stay together.
34
38
  */
35
39
  export declare const secretEnvKey: (field: string) => string;
40
+ /** The schema of that argument, shared by every tool that replays a flow. */
41
+ export { CALL_SECRETS_ARG };
42
+ export declare const callSecretsArg: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
43
+ /**
44
+ * One secret's value: supplied with this call (by field or by variable name), else from the
45
+ * daemon's environment.
46
+ */
47
+ export declare function secretValue(envKey: string, env: Record<string, string | undefined>): string | undefined;
36
48
  /** One field a flow needs supplied, and the variable that supplies it. */
37
49
  export interface UnsuppliedSecret {
38
50
  field: string;
@@ -1,4 +1,6 @@
1
+ import { z } from 'zod';
1
2
  import { AnchorKind } from '@reticlehq/core';
3
+ import { CALL_SECRETS_ARG, callSecrets } from '../../../surface/tools/tool-kit.js';
2
4
  /**
3
5
  * What the anchor CALLS the field it points at.
4
6
  *
@@ -28,6 +30,10 @@ export function anchorFieldName(anchor) {
28
30
  * reader what to do: the value belongs in the environment, not in a file they are about to commit.
29
31
  */
30
32
  export const REDACTED_FILL = '<redacted: supply at replay>';
33
+ /** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
34
+ export const SECRET_NAME_ARG = 'secret';
35
+ /** The prefix every secret's variable carries. */
36
+ const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
31
37
  /**
32
38
  * The environment variable that supplies one redacted field.
33
39
  *
@@ -40,7 +46,24 @@ export const REDACTED_FILL = '<redacted: supply at replay>';
40
46
  * rules must not be able to drift. It used to sit in `replay.ts`, one import away from the sentence
41
47
  * saying it had to stay together.
42
48
  */
43
- export const secretEnvKey = (field) => `RETICLE_SECRET_${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
49
+ export const secretEnvKey = (field) => `${SECRET_ENV_PREFIX}${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
50
+ /** The schema of that argument, shared by every tool that replays a flow. */
51
+ export { CALL_SECRETS_ARG };
52
+ export const callSecretsArg = z
53
+ .record(z.string())
54
+ .optional()
55
+ .describe('Redacted fields\' values, this call only, never kept: { "auth-password": "…" }');
56
+ /**
57
+ * One secret's value: supplied with this call (by field or by variable name), else from the
58
+ * daemon's environment.
59
+ */
60
+ export function secretValue(envKey, env) {
61
+ for (const [key, value] of Object.entries(callSecrets() ?? {})) {
62
+ if (envKey === (key.startsWith(SECRET_ENV_PREFIX) ? key : secretEnvKey(key)))
63
+ return value;
64
+ }
65
+ return env[envKey];
66
+ }
44
67
  /**
45
68
  * Every credential this flow will replay as the literal placeholder.
46
69
  *
@@ -63,7 +86,7 @@ export function unsuppliedSecrets(flow, env) {
63
86
  if (field === undefined)
64
87
  continue;
65
88
  const envKey = secretEnvKey(field);
66
- const supplied = env[envKey];
89
+ const supplied = secretValue(envKey, env);
67
90
  if (supplied !== undefined && supplied.length > 0)
68
91
  continue;
69
92
  if (seen.has(envKey))
@@ -16,8 +16,13 @@ import type { FlowReplaySession, Sleep } from './flow-replay-types.js';
16
16
  export declare function editDistance(a: string, b: string): number;
17
17
  /**
18
18
  * The closest present testid to a missing one, by case-insensitive edit distance, ties broken
19
- * by shortest length then lexically. Returns null only when nothing is present — so a drift
20
- * record always names a fix when one exists ("whose fault is it": here is the closest survivor).
19
+ * by shortest length then lexically — when it is close enough to be a rename. Null when nothing
20
+ * present is, so a drift record names a fix only when one plausibly exists.
21
+ *
22
+ * It used to name the closest survivor however far away it was. A replay that started signed out
23
+ * missed `compose-prompt` on the login screen and advised rebinding it to `login-submit`: eleven
24
+ * edits away, a different control on a different page, offered as the fix. Half the longer name is
25
+ * the ceiling — `chat-send` → `chat-submit` and `checkout-btn` → `checkout-button` stay in.
21
26
  */
22
27
  export declare function nearestTestid(missing: string, present: string[]): string | null;
23
28
  /**
@@ -35,8 +35,13 @@ export function editDistance(a, b) {
35
35
  }
36
36
  /**
37
37
  * The closest present testid to a missing one, by case-insensitive edit distance, ties broken
38
- * by shortest length then lexically. Returns null only when nothing is present — so a drift
39
- * record always names a fix when one exists ("whose fault is it": here is the closest survivor).
38
+ * by shortest length then lexically — when it is close enough to be a rename. Null when nothing
39
+ * present is, so a drift record names a fix only when one plausibly exists.
40
+ *
41
+ * It used to name the closest survivor however far away it was. A replay that started signed out
42
+ * missed `compose-prompt` on the login screen and advised rebinding it to `login-submit`: eleven
43
+ * edits away, a different control on a different page, offered as the fix. Half the longer name is
44
+ * the ceiling — `chat-send` → `chat-submit` and `checkout-btn` → `checkout-button` stay in.
40
45
  */
41
46
  export function nearestTestid(missing, present) {
42
47
  let best = null;
@@ -53,7 +58,9 @@ export function nearestTestid(missing, present) {
53
58
  bestDistance = distance;
54
59
  }
55
60
  }
56
- return best;
61
+ if (null === best)
62
+ return null;
63
+ return bestDistance <= Math.max(missing.length, best.length) / 2 ? best : null;
57
64
  }
58
65
  /**
59
66
  * Bounded settle for anchor re-resolution. A testid step queries the live DOM for the anchor; if a
@@ -49,4 +49,5 @@ export declare function dischargeFlowIntent(store: IntentStore, flow: FlowFile,
49
49
  verdictId: string;
50
50
  grade: string;
51
51
  at: number;
52
+ runId?: string;
52
53
  }): Promise<boolean>;
@@ -1,6 +1,12 @@
1
1
  import { type FlowFile, type FlowStep, type Predicate } from '@reticlehq/core';
2
2
  /** A short, stable identity for a journey's shape: its start page and its steps. */
3
3
  export declare function journeyFingerprint(flow: Pick<FlowFile, 'startPath' | 'steps'>): string;
4
+ /**
5
+ * Whether `shorter` is `longer` driven with steps left out: same start, and its steps appear in
6
+ * `longer` in the same order. A re-drive that retried a step, or stopped one short, is the same
7
+ * journey; two flows that share only a name and a page are not.
8
+ */
9
+ export declare function withinJourney(longer: Pick<FlowFile, 'startPath' | 'steps'>, shorter: Pick<FlowFile, 'startPath' | 'steps'>): boolean;
4
10
  /**
5
11
  * Fold two copies of one journey into one file.
6
12
  *
@@ -31,6 +31,26 @@ export function journeyFingerprint(flow) {
31
31
  .digest('hex')
32
32
  .slice(0, FINGERPRINT_LENGTH);
33
33
  }
34
+ /**
35
+ * Whether `shorter` is `longer` driven with steps left out: same start, and its steps appear in
36
+ * `longer` in the same order. A re-drive that retried a step, or stopped one short, is the same
37
+ * journey; two flows that share only a name and a page are not.
38
+ */
39
+ export function withinJourney(longer, shorter) {
40
+ if ((longer.startPath ?? null) !== (shorter.startPath ?? null))
41
+ return false;
42
+ const shapes = longer.steps.map((step) => JSON.stringify(stepShape(step)));
43
+ let at = 0;
44
+ for (const step of shorter.steps) {
45
+ const wanted = JSON.stringify(stepShape(step));
46
+ while (at < shapes.length && shapes[at] !== wanted)
47
+ at += 1;
48
+ if (at === shapes.length)
49
+ return false;
50
+ at += 1;
51
+ }
52
+ return true;
53
+ }
34
54
  /** `kept` wins wherever it says something; `other` fills only what `kept` left unsaid. */
35
55
  function fillStep(kept, other) {
36
56
  if (other === undefined)
@@ -53,3 +53,7 @@ export declare function replayAndLearn(deps: ToolDeps,
53
53
  args: Record<string, unknown>): Promise<FlowReplayResult>;
54
54
  /** Write back the files a clean replay's anchors resolved to. Best-effort, as `persistLearning` is. */
55
55
  export declare function persistSources(deps: ToolDeps, args: Record<string, unknown>, sources: Parameters<typeof withLearnedSources>[1]): Promise<void>;
56
+ /** A replay, under seeded perturbation when `seed` asks for one; the page is always put back. */
57
+ export declare function replaySeededOrNot(deps: ToolDeps, args: Record<string, unknown>,
58
+ /** Where the perturbation port finds the page: the app's origin. */
59
+ appUrl: string | undefined): Promise<FlowReplayResult>;
@@ -1,4 +1,6 @@
1
- import { asString } from '@reticlehq/core';
1
+ import { runSavedFlow } from '../../hooks/driven-by.js';
2
+ import { asNumber, asString, mutationTargetsFor, perturbationFor } from '@reticlehq/core';
3
+ import { sessionPerturbationPort } from '../../surface/tools/lease-tools.js';
2
4
  import { flowsForSession } from './flow-store-for-session.js';
3
5
  import { safeSessionTarget } from '../../memory/project/session-root.js';
4
6
  import { replayNamedFlow } from './flow-replay-run.js';
@@ -73,10 +75,11 @@ export async function replayAndLearn(deps,
73
75
  */
74
76
  args) {
75
77
  let recorded;
76
- const result = await replayNamedFlow(deps, args, (session) => {
78
+ // A saved flow's steps were asked for by whoever recorded it: no outward gate on them.
79
+ const result = await runSavedFlow(() => replayNamedFlow(deps, args, (session) => {
77
80
  recorded = recordingSources(session);
78
81
  return recorded.session;
79
- });
82
+ }));
80
83
  // Only a clean run teaches a file: a drifted step may have resolved to the wrong element.
81
84
  if (result.status === ReplayStatus.OK && recorded !== undefined && recorded.sources.size > 0) {
82
85
  await persistSources(deps, args, recorded.sources);
@@ -102,3 +105,34 @@ export async function persistSources(deps, args, sources) {
102
105
  // Bookkeeping only.
103
106
  }
104
107
  }
108
+ /** A replay, under seeded perturbation when `seed` asks for one; the page is always put back. */
109
+ export async function replaySeededOrNot(deps, args,
110
+ /** Where the perturbation port finds the page: the app's origin. */
111
+ appUrl) {
112
+ const seed = asNumber(args['seed']);
113
+ if (seed === undefined)
114
+ return await replayAndLearn(deps, args);
115
+ /*
116
+ * The targets are the endpoints the FLOW declared it depends on, so the perturbation lands on
117
+ * traffic the flow claims to care about. No declared endpoints means nothing to slow, and the
118
+ * replay runs clean rather than pretending a seed did something. `finally` is not tidiness: a
119
+ * page left slowed is damage the NEXT run inherits, as a mystery.
120
+ */
121
+ const target = targetOf(deps, args);
122
+ const loaded = await flowsForSession(deps, target)
123
+ .flows.load(asString(args['flowName']) ?? asString(args['flow']) ?? '', target.projectId)
124
+ .catch(() => null);
125
+ const targets = loaded !== null && loaded.ok ? mutationTargetsFor(loaded.value) : [];
126
+ const rules = perturbationFor(seed, targets);
127
+ const port = 0 === rules.length ? undefined : await sessionPerturbationPort(deps.realInput, appUrl);
128
+ if (port === undefined)
129
+ return replayAndLearn(deps, args);
130
+ try {
131
+ await port.slow(rules);
132
+ const replay = await runSavedFlow(() => replayNamedFlow(deps, args));
133
+ return { ...replay, perturbed: rules };
134
+ }
135
+ finally {
136
+ await port.clear().catch(() => undefined);
137
+ }
138
+ }
@@ -4,7 +4,7 @@ import { EventType, FLOW_SIGNAL_TIMEOUT_MS, FlowErrorCode, RecordedFlowSchema, R
4
4
  import { haltedFrom } from './recording/replay-halt.js';
5
5
  import { establishedState, samePath } from './flow-journey.js';
6
6
  import { asRecord, asString } from '@reticlehq/core';
7
- import { routeOfEvent, routeOfUrl } from '@reticlehq/engine/question/predicate/predicate-route.js';
7
+ import { navigablePath, routeOfEvent, routeOfUrl, } from '@reticlehq/engine/question/predicate/predicate-route.js';
8
8
  import { carryReticleIdentity } from '../../surface/tools/lease-tools.js';
9
9
  import { partialStatus, replayFlow, replayWindow } from './flow-replay.js';
10
10
  import { anchorPrecondition, anchorQueryArgs, staleTargetResult } from './flow-step-runners.js';
@@ -28,9 +28,10 @@ import { EnvelopeStore } from '../../memory/journal/envelope-store.js';
28
28
  import { homedir } from 'node:os';
29
29
  import { cloudFetch, syncRunRecordToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
30
30
  import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
31
- import { memoryReadUrl, scopedMemoryEntries } from '../../memory/cloud/memory-scope.js';
31
+ import { memoryReadHeaders, memoryReadUrl, scopedMemoryEntries, } from '../../memory/cloud/memory-scope.js';
32
32
  import { consultSubjectFor, selectConsulted } from './flow-memory-consult.js';
33
33
  import { log } from '../../log.js';
34
+ import { replayStepShooter } from '../../features/visual/step-shots.js';
34
35
  import { flowsForSession } from './flow-store-for-session.js';
35
36
  import { projectForRoot } from '../../memory/project/project-for-root.js';
36
37
  import { CROSS_STEP_INDEX, crossStepOnly } from './flow-cross-step.js';
@@ -46,7 +47,7 @@ export function latestRecordedFlow(events) {
46
47
  return undefined;
47
48
  }
48
49
  export { flowErrorMessage } from './flow-result.js';
49
- import { flowErrorMessage } from './flow-result.js';
50
+ import { flowErrorMessage, noteReplayCheck } from './flow-result.js';
50
51
  /** Map the wire ReplayStatus onto the persisted RunStatus (ok→pass). */
51
52
  function replayToRunStatus(status) {
52
53
  switch (status) {
@@ -107,13 +108,14 @@ function currentPathOf(session) {
107
108
  // query usually decides what the page renders, so a tab on `?tab=summary` would read as "already
108
109
  // at `?tab=wrap`" and the replay would start on the wrong page with nothing saying so. Both sides
109
110
  // carry it, which keeps a real difference visible and stops the false one.
111
+ // Reticle's own params dropped, as the recording drops them from `startPath` (#1411).
110
112
  const observed = last === undefined ? undefined : routeOfEvent(last);
111
113
  if (observed !== undefined)
112
- return `${observed.docPath}${observed.search}${observed.hash}`;
114
+ return navigablePath(observed);
113
115
  if (session.url === undefined)
114
116
  return undefined;
115
117
  const fromUrl = routeOfUrl(session.url);
116
- return fromUrl === undefined ? undefined : `${fromUrl.docPath}${fromUrl.search}${fromUrl.hash}`;
118
+ return fromUrl === undefined ? undefined : navigablePath(fromUrl);
117
119
  }
118
120
  /**
119
121
  * Ask the project what it already knows about this flow.
@@ -132,11 +134,7 @@ async function consultProjectMemory(deps, flow, root) {
132
134
  if (subject === undefined)
133
135
  return undefined;
134
136
  try {
135
- // The APP's root, not the daemon's. `deps.reticleRoot` is wherever the daemon was launched,
136
- // which for a user-scoped MCP registration is almost never the project being verified — so the
137
- // link file it reads is the wrong one, or absent, and every project silently reads as
138
- // "not attached". Same class of bug as the flow store resolving per daemon instead of per
139
- // session, and it is invisible: the feature simply never appears.
137
+ // The APP's root, not the daemon's (wherever it was launched): its link file is this project's.
140
138
  const cloud = await resolveProjectCloud(deps.fs, root, homedir(), process.env);
141
139
  if (null === cloud.config || !cloud.policy.memory)
142
140
  return undefined;
@@ -146,7 +144,7 @@ async function consultProjectMemory(deps, flow, root) {
146
144
  const url = memoryReadUrl(cloud.config.url, { projectId: cloud.projectId, subject });
147
145
  const res = await cloudFetch(url, {
148
146
  method: 'GET',
149
- headers: { authorization: `Bearer ${cloud.config.apiKey}` },
147
+ headers: memoryReadHeaders(cloud.config.apiKey),
150
148
  });
151
149
  if (200 !== res.status)
152
150
  return undefined;
@@ -574,8 +572,8 @@ observe = (s) => s) {
574
572
  status: ReplayStatus.UNVERIFIABLE,
575
573
  steps: [],
576
574
  unverifiable: {
577
- reason: `this flow fills a redacted field and nothing supplied it, so nothing ran and nothing ` +
578
- `was proved. Set ${names} in the environment the daemon runs in, then replay. Until then ` +
575
+ reason: `this flow fills a redacted field and nothing supplied it, so nothing ran and nothing was ` +
576
+ `proved. Pass it with this call — secrets: { ${missing.map((each) => `"${each.field}": "…"`).join(', ')} } — or set ${names} where the daemon runs and restart it. Until then ` +
579
577
  `the value typed would be the placeholder itself, and any failure after it would be ` +
580
578
  `about this and not about the application.`,
581
579
  },
@@ -613,6 +611,7 @@ observe = (s) => s) {
613
611
  ...(continueAt === undefined ? {} : { at: continueAt }),
614
612
  // The HUD's replay chip, when the human pressed ▶. In-process only: an agent's arguments
615
613
  // arrive as JSON and can never carry a function.
614
+ onStepResult: replayStepShooter(deps, session.id),
616
615
  ...('function' === typeof args['onStep']
617
616
  ? { onStep: args['onStep'] }
618
617
  : {}),
@@ -624,7 +623,7 @@ observe = (s) => s) {
624
623
  return lostDocumentResult(name, error);
625
624
  }
626
625
  // Only part of the journey was driven here: its steps were checked, nothing about the whole flow.
627
- if (continueAt !== undefined || (to !== undefined && to < loaded.value.steps.length))
626
+ if (0 < (continueAt ?? 0) || (to !== undefined && to < loaded.value.steps.length))
628
627
  return { name, status: partialStatus(steps), steps };
629
628
  // Computed HERE, before the synthetic success row is appended below: once that row is pushed,
630
629
  // `steps.length` no longer counts only the flow's own steps and the arithmetic is wrong.
@@ -728,13 +727,12 @@ observe = (s) => s) {
728
727
  result.halted = halted;
729
728
  if (knows !== undefined)
730
729
  result.knows = knows;
731
- // A green that cannot go red is not a pass. `reticle_flow_verify` already refuses to count these,
732
- // via this same function -- a single-flow caller saw a bare `ok` and had no way to learn the flow
733
- // asserts nothing. Derived from the same helper on purpose: two copies of this judgement would
734
- // drift, and the sibling tools would then disagree about the same flow.
730
+ // A green that cannot go red is not a pass: the same judgement `reticle_flow_verify` makes.
735
731
  const cannotFail = status === ReplayStatus.OK ? unverifiableReason(loaded.value, invokedFlows) : undefined;
736
732
  if (cannotFail !== undefined)
737
733
  result.unverifiable = { reason: cannotFail };
734
+ // One check of the session that ran it, so its end does not say "nothing was checked".
735
+ noteReplayCheck(session, name, status, cannotFail !== undefined);
738
736
  if (status !== ReplayStatus.OK)
739
737
  result.decision = buildDecision(result, loaded.value, intentSaid, invokedFlows);
740
738
  applyStartPathHint(result, startPathHint);
@@ -12,7 +12,7 @@ import type { EvalResult } from '@reticlehq/engine/question/predicate/predicate.
12
12
  * (via the injected waitForPredicate). Mirrors PredicateSession so the same fake drives both.
13
13
  */
14
14
  export interface FlowReplaySession {
15
- command(name: string, args?: Record<string, unknown>): Promise<CommandResult>;
15
+ command(name: string, args?: Record<string, unknown>, timeoutMs?: number): Promise<CommandResult>;
16
16
  /**
17
17
  * Attribution window around each replayed step. Optional so a minimal test double still satisfies the
18
18
  * interface, but a real session MUST supply it: without a window the step's own effects carry no
@@ -43,6 +43,15 @@ export declare function runTestidStep(session: FlowReplaySession, step: FlowStep
43
43
  * state it was never meant to run in.
44
44
  */
45
45
  export declare function assertStepExpect(session: FlowReplaySession, expect: NonNullable<FlowStep['expect']>, waitForSignal: WaitForSignal, timeoutMs: number, since: number): Promise<Drift | undefined>;
46
+ /**
47
+ * A text check that missed only on case says so, with what would hold. Text checks match case
48
+ * exactly now, so a flow saved when they did not goes red on capitalisation alone; the person
49
+ * reading its replay needs the fix (`ignoreCase: true`, or re-record), not a bare "did not hold".
50
+ */
51
+ export declare function withCaseOnly(reason: string, verdict: {
52
+ caseOnlyMiss?: boolean;
53
+ wouldHold?: string;
54
+ }): string;
46
55
  /**
47
56
  * Replay a loaded flow by RE-RESOLVING every step's semantic anchor against the live DOM — never
48
57
  * a stale ref. A testid anchor is re-found by reticle_query; a signal anchor waits on a predicate.
@@ -58,6 +67,11 @@ export interface ReplayFromOptions {
58
67
  * The HUD's replay chip draws its progress from this; it must never throw into the replay.
59
68
  */
60
69
  onStep?: (done: number, total: number, held: boolean) => void;
70
+ /**
71
+ * Told each reported step the moment its outcome is decided, before it is kept, so a caller can
72
+ * add to it (the step's screenshot). Never allowed to fail the replay.
73
+ */
74
+ onStepResult?: (result: FlowStepResult, flow: string) => Promise<void>;
61
75
  /**
62
76
  * Resume at this step: an index, or a step's `id` (which survives edits that shift indices).
63
77
  *
@@ -114,7 +128,10 @@ export interface ReplayFromOptions {
114
128
  * is not setup, it is a second charge, a second email, a second record.
115
129
  */
116
130
  export declare function resumeIndex(from: number | string | undefined, steps: readonly FlowStep[]): number | undefined;
117
- /** How far a replay drives: `to` stops before a step, `at` picks up at one. Positive indices only. */
131
+ /**
132
+ * How far a replay drives: `to` stops before a step (positive), `at` picks up at one on the page as
133
+ * it is. `at: 0` is the whole flow continuing the page the flow before it left, with no reload.
134
+ */
118
135
  export declare function replayWindow(args: Record<string, unknown>): {
119
136
  to?: number;
120
137
  at?: number;
@@ -7,7 +7,7 @@ import { routeOfEvent, routeOfUrl } from '@reticlehq/engine/question/predicate/p
7
7
  import { evalConsole } from '@reticlehq/engine/question/predicate/predicate-console.js';
8
8
  import { stepEffect } from '@reticlehq/engine/evidence/step-effect.js';
9
9
  import { AnchorKind, DriftReason, EventType, FlowStepTool, StepEffect, PredicateKind, ReplayStatus, } from '@reticlehq/core';
10
- import { asString, isConsequenceDrift } from '@reticlehq/core';
10
+ import { asString, invokedFlowMissing, isConsequenceDrift } from '@reticlehq/core';
11
11
  import { anchorFieldName } from './fields/flow-secret-field.js';
12
12
  import { degradedStepResult, isDegradedAnchor, runComponentStep, runRoleStep, runSequenceStep, } from './flow-step-runners.js';
13
13
  import { inFlightRequestLabels } from '../../surface/tools/act/settle-in-flight.js';
@@ -282,11 +282,22 @@ export async function assertStepExpect(session, expect, waitForSignal, timeoutMs
282
282
  : DriftReason.SIGNAL_NOT_OBSERVED,
283
283
  reason: namedInFlight
284
284
  ? `${IN_FLIGHT_AT_BUDGET_END} (${openRequests.join(', ')})`
285
- : (verdict.failureReason ?? "the step's declared consequence did not hold"),
285
+ : withCaseOnly(verdict.failureReason ?? "the step's declared consequence did not hold", verdict),
286
286
  anchor: expectLabel(expect),
287
287
  nearest: null,
288
288
  };
289
289
  }
290
+ /**
291
+ * A text check that missed only on case says so, with what would hold. Text checks match case
292
+ * exactly now, so a flow saved when they did not goes red on capitalisation alone; the person
293
+ * reading its replay needs the fix (`ignoreCase: true`, or re-record), not a bare "did not hold".
294
+ */
295
+ export function withCaseOnly(reason, verdict) {
296
+ if (true !== verdict.caseOnlyMiss)
297
+ return reason;
298
+ const shown = verdict.wouldHold === undefined ? '' : ` ("${verdict.wouldHold}")`;
299
+ return `${reason} — the page shows it in another case${shown}. Text checks match case exactly: if any case is meant, add ignoreCase: true to this check, or re-record the flow.`;
300
+ }
290
301
  /** Run one signal-anchored step: wait for the signal predicate, else drift (no nearest for signals). */
291
302
  async function runSignalStep(session, step, index, name, waitForSignal, signalTimeoutMs, since) {
292
303
  // Scope to THIS replay's floor, not the whole buffer.
@@ -328,11 +339,14 @@ export function resumeIndex(from, steps) {
328
339
  return undefined;
329
340
  return steps.slice(0, at).some((step) => StepEffect.COMMITS === step.effect) ? 0 : at;
330
341
  }
331
- /** How far a replay drives: `to` stops before a step, `at` picks up at one. Positive indices only. */
342
+ /**
343
+ * How far a replay drives: `to` stops before a step (positive), `at` picks up at one on the page as
344
+ * it is. `at: 0` is the whole flow continuing the page the flow before it left, with no reload.
345
+ */
332
346
  export function replayWindow(args) {
333
- const index = (raw) => 'number' === typeof raw && Number.isInteger(raw) && 0 < raw ? raw : undefined;
334
- const to = index(args['to']);
335
- const at = index(args['at']);
347
+ const index = (raw, least) => 'number' === typeof raw && Number.isInteger(raw) && least <= raw ? raw : undefined;
348
+ const to = index(args['to'], 1);
349
+ const at = index(args['at'], 0);
336
350
  return { ...(to === undefined ? {} : { to }), ...(at === undefined ? {} : { at }) };
337
351
  }
338
352
  /** A part-way replay's status, from the steps it drove. */
@@ -381,7 +395,7 @@ async function runInvokeStep(session, flow, step, index, waitForSignal, signalTi
381
395
  return {
382
396
  ...base,
383
397
  ok: false,
384
- error: `cannot replay "${name}": it was not found, so this journey would report green having never run it`,
398
+ error: invokedFlowMissing(name),
385
399
  };
386
400
  }
387
401
  // `from` is an offset into the CALLER's steps. A sub-journey invoked from the setup prefix runs
@@ -555,6 +569,7 @@ export async function replayFlow(session, flow, waitForSignal, signalTimeoutMs,
555
569
  }
556
570
  if (index < from)
557
571
  result.note = `setup step for resuming at step ${String(from)} failed`;
572
+ await options.onStepResult?.(result, flow.name).catch(() => undefined);
558
573
  results.push(result);
559
574
  tell(result);
560
575
  // Under `sweep`, a failure whose action still RAN does not stop the run — the page is where the
@@ -1,4 +1,4 @@
1
- import { FlowErrorCode } from '@reticlehq/core';
1
+ import { FlowErrorCode, ReplayStatus, Verified } from '@reticlehq/core';
2
2
  import { type ProjectId } from '@reticlehq/core';
3
3
  /** Discriminated result so callers never branch on free strings. */
4
4
  export type FlowResult<T> = {
@@ -35,3 +35,24 @@ export type FlowResult<T> = {
35
35
  export declare const safeProjectId: (projectId?: ProjectId) => ProjectId | undefined;
36
36
  /** Map a structured FlowErrorCode to a legible one-line message for the agent. */
37
37
  export declare function flowErrorMessage(code: FlowErrorCode, detail?: string): string;
38
+ /**
39
+ * A replay as one check of the session that ran it: held when it replayed clean, failed when a step
40
+ * failed, undecided when it drifted or its flow asserts nothing. A session whose only work was a
41
+ * failing replay ended "nothing was checked" beside the replay's own failure.
42
+ */
43
+ export declare function replayVerdictEffect(name: string, status: ReplayStatus, assertsNothing: boolean): {
44
+ claim: string;
45
+ verified: Verified;
46
+ declaredBeforeActing: true;
47
+ grade: string;
48
+ };
49
+ /** Record a replay as one check of the session that ran it. A session double without a journal is skipped. */
50
+ export declare function noteReplayCheck(session: {
51
+ recordAction?: (tool: string, args: Record<string, unknown>, effect?: unknown) => string;
52
+ }, name: string, status: ReplayStatus, assertsNothing: boolean): void;
53
+ /**
54
+ * The active recording a refused `reticle_flow_save` was most likely about: the one it named, or
55
+ * the only one running when it named none and nothing is stopped yet.
56
+ */
57
+ export declare function stillRecording(active: readonly string[], name: string, explicitName: string | undefined, held: readonly string[]): string | undefined;
58
+ export declare function stillRecordingMessage(recording: string): string;