@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
@@ -1,4 +1,5 @@
1
1
  import { type FlowFile, type FlowReplayResult } from '@reticlehq/core';
2
+ import { type VerificationRunInput } from './artifact/build-verification-run.js';
2
3
  import { type ProjectTarget } from '../../memory/project/session-root.js';
3
4
  import type { ToolDeps } from '../../surface/tools/tool-kit.js';
4
5
  /** A replay plus the wall-clock time it took — the shape the verify handler already collects. */
@@ -11,8 +12,8 @@ export interface TimedReplay {
11
12
  /** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
12
13
  export declare const CLI_CLIENT_NAME = "reticle-cli";
13
14
  /**
14
- * Persist the suite's run artifact and best-effort mirror it to the cloud. Never throws into the verify
15
- * tool — a disk or network failure is logged and swallowed so the verdict the agent asked for is
16
- * unaffected. Returns the runId (for logging/tests); undefined if nothing was produced (empty suite).
15
+ * Who ran the command line, and why. On a CI runner it is the pipeline; anywhere else it is the
16
+ * person who holds the key, so the cloud credits them and the run does not read as CI.
17
17
  */
18
+ export declare function cliRunAuthor(env: NodeJS.ProcessEnv): Pick<VerificationRunInput, 'agent' | 'trigger'>;
18
19
  export declare function persistAndSyncVerificationRun(deps: ToolDeps, timed: TimedReplay[], target: ProjectTarget): Promise<string | undefined>;
@@ -10,29 +10,42 @@
10
10
  */
11
11
  import { callerClientName } from '../../hooks/coding-agents.js';
12
12
  import { currentDrivenBy } from '../../hooks/driven-by.js';
13
- import { RunAgentKind, RunFramework, RunProfile, RunTrigger, asRunId, } from '@reticlehq/core';
13
+ import { RunAgentKind, RunFramework, RunProfile, RunTrigger, RunFlowStatus, Verified, asRunId, } from '@reticlehq/core';
14
14
  import { homedir } from 'node:os';
15
15
  import { buildVerificationRun, } from './artifact/build-verification-run.js';
16
16
  import { mapReplayToFlowResult } from './artifact/replay-mapping.js';
17
+ import { runLedger } from './run-ledger.js';
17
18
  import { defaultRunId } from './default-run-id.js';
18
19
  import { currentShotRun } from './default-run-id.js';
19
20
  import { RunStore } from './artifact/run-store.js';
20
21
  import { cloudFetch, syncRunToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
21
22
  import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
22
23
  import { log } from '../../log.js';
24
+ import { isCiEnv } from '../../telemetry/automation-hint.js';
23
25
  import { rootForTarget } from '../../memory/project/session-root.js';
24
26
  /** The author of record when no MCP peer introduced itself — a CLI run, or a client that skipped the handshake. */
25
27
  const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
26
28
  /** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
27
29
  export const CLI_CLIENT_NAME = 'reticle-cli';
28
30
  /**
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.
31
+ * Who ran the command line, and why. On a CI runner it is the pipeline; anywhere else it is the
32
+ * person who holds the key, so the cloud credits them and the run does not read as CI.
32
33
  */
34
+ export function cliRunAuthor(env) {
35
+ return isCiEnv(env)
36
+ ? {
37
+ agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.OEM_PIPELINE },
38
+ trigger: { kind: RunTrigger.OEM },
39
+ }
40
+ : {
41
+ agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.HUMAN },
42
+ trigger: { kind: RunTrigger.MANUAL },
43
+ };
44
+ }
45
+ /** Who ran a suite, and why: the command line by `cliRunAuthor`, any other client as a coding agent. */
33
46
  function agentAndTrigger(client) {
34
47
  return CLI_CLIENT_NAME === client
35
- ? { agent: { id: client, kind: RunAgentKind.OEM_PIPELINE }, trigger: { kind: RunTrigger.OEM } }
48
+ ? cliRunAuthor(process.env)
36
49
  : {
37
50
  agent: { id: client ?? RETICLE_MCP_AGENT_ID, kind: RunAgentKind.CODING_AGENT },
38
51
  trigger: { kind: RunTrigger.MANUAL },
@@ -73,6 +86,13 @@ projectName) {
73
86
  * tool — a disk or network failure is logged and swallowed so the verdict the agent asked for is
74
87
  * unaffected. Returns the runId (for logging/tests); undefined if nothing was produced (empty suite).
75
88
  */
89
+ /** A replay's verdict, decided as its run decides it: a green that proved nothing is undecided. */
90
+ function replayVerified(replay, durationMs) {
91
+ const status = mapReplayToFlowResult(replay, durationMs).status;
92
+ if (RunFlowStatus.PASS === status)
93
+ return Verified.YES;
94
+ return RunFlowStatus.FAIL === status ? Verified.NO : Verified.UNKNOWN;
95
+ }
76
96
  export async function persistAndSyncVerificationRun(deps, timed, target) {
77
97
  const { projectId } = target;
78
98
  if (0 === timed.length)
@@ -81,6 +101,8 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
81
101
  // it was a second row ("Passed · Flow replay · Your agent") beside the plan run it belonged to.
82
102
  if (currentDrivenBy() !== undefined)
83
103
  return undefined;
104
+ for (const t of timed)
105
+ runLedger.replayed(t.replay.name, replayVerified(t.replay, t.durationMs));
84
106
  let run;
85
107
  // The project the suite ran for, not the directory the daemon was started in. Both halves below
86
108
  // take it: the artifact `reticle_run` reads back through `sessionRoot`, and the cloud link that
@@ -4,6 +4,7 @@ import { loadNamedFlows, resolveChangedFiles } from '../../command/cli/cli-flow-
4
4
  import { projectDirFor } from '../../memory/project/session-root.js';
5
5
  import { sessionRoot, sessionProjectId } from '../../memory/project/session-root.js';
6
6
  import { affectedSavedFlows } from './change/flow-sources.js';
7
+ import { RECORD_A_FLOW } from './suite/coverage.js';
7
8
  /**
8
9
  * `reticle_affected` — which saved flows must re-verify for a set of changed files.
9
10
  *
@@ -67,7 +68,7 @@ export const AFFECTED_TOOLS = [
67
68
  changed.failed
68
69
  ? `could not read the diff for \`${String(since)}\`, so NOTHING was compared and this result proves nothing: ${changed.reason ?? 'git failed'}`
69
70
  : 0 === flows.length
70
- ? 'no saved flows exist yet, so nothing COULD be affected — record one with reticle_record then reticle_flow_save'
71
+ ? `no saved flows exist yet, so nothing COULD be affected. ${RECORD_A_FLOW}`
71
72
  : 0 === changedFiles.length
72
73
  ? since === undefined && 0 === files.length
73
74
  ? 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref'
@@ -1,4 +1,4 @@
1
- import { AnnotationErrorCode, AnnotationKind, AnnotationTarget, COMPILED_PREDICATE_PREFIX, flowExpectHasConsequence, flowExpectIsPresenceOnly, PredicateKind, } from '@reticlehq/core';
1
+ import { AnnotationErrorCode, AnnotationKind, AnnotationTarget, COMPILED_PREDICATE_PREFIX, flowExpectHasConsequence, flowExpectIsPresenceOnly, PredicateKind, SettledChannel, } from '@reticlehq/core';
2
2
  /**
3
3
  * The PURE compiler at the heart of the annotation facet. A structured annotation +
4
4
  * the current captured-step count → an AnnotateOutcome (a result envelope + the patch to apply to
@@ -39,7 +39,12 @@ function netPredicate(net) {
39
39
  if (net.count === undefined)
40
40
  return clause;
41
41
  clause.count = net.count;
42
- return { kind: PredicateKind.ALL_OF, predicates: [{ kind: PredicateKind.SETTLED }, clause] };
42
+ // The gate waits on the NETWORK: DOM churn from an animation held a request check open until it
43
+ // timed out, a flaky red on a loaded machine.
44
+ return {
45
+ kind: PredicateKind.ALL_OF,
46
+ predicates: [{ kind: PredicateKind.SETTLED, channel: SettledChannel.NETWORK }, clause],
47
+ };
43
48
  }
44
49
  export function compileAnnotation(a, stepCount) {
45
50
  switch (a.kind) {
@@ -112,7 +117,7 @@ export function compileAnnotation(a, stepCount) {
112
117
  if (a.console !== undefined) {
113
118
  return flowSuccess(a, {
114
119
  kind: PredicateKind.CONSOLE,
115
- ...(a.console.level === undefined ? {} : { level: a.console.level }),
120
+ level: a.console.level ?? 'error',
116
121
  ...(a.console.absent === undefined ? {} : { absent: a.console.absent }),
117
122
  });
118
123
  }
@@ -85,7 +85,7 @@ export const ANNOTATE_TOOLS = [
85
85
  .optional()
86
86
  .describe('Treat statePath as an INVARIANT that must still hold AFTER the action settles (a blast-radius "this unrelated path must not have moved" check), not a condition to wait for. Without it a wait-until-true read passes before an over-reaching side-effect lands.'),
87
87
  dataMatches: z
88
- .record(z.unknown())
88
+ .record(z.string(), z.unknown())
89
89
  .optional()
90
90
  .describe('Key/value pairs the signal payload must match (assert-signal only).'),
91
91
  net: z
@@ -16,6 +16,14 @@ export interface AffectedResult {
16
16
  /** Of the affected, which were included only because their provenance is unknown (fail-safe). */
17
17
  unknownProvenance: string[];
18
18
  }
19
+ /**
20
+ * The one rule for "this changed file is that flow source": paths are compared by normalized suffix,
21
+ * so a repo-root-relative change (`web/src/app.ts`) matches a package-relative stamp (`src/app.ts`)
22
+ * and an absolute stamp, and vice-versa. Everything that asks whether a flow touches a file uses it,
23
+ * so "affected" and "stale" can never disagree about which files belong to a flow.
24
+ */
25
+ export declare function pathsMatch(a: string, b: string): boolean;
26
+ export declare function sourceMatchesChange(source: string, changedFiles: readonly string[]): boolean;
19
27
  /**
20
28
  * Which flows are affected by a set of changed files. Deterministic; a flow with no sources manifest is
21
29
  * always affected (fail-safe). `changedFiles` and flow sources are matched by normalized path suffix so
@@ -5,9 +5,26 @@
5
5
  * (recorded before source stamping, or un-stampable) is `unknown` — and unknown always means affected, never
6
6
  * silently skipped: the loop fails safe toward re-verifying.
7
7
  */
8
- /** Normalize a path for comparison — strip a leading./ and any file:line suffix. */
8
+ /** Normalize a path for comparison — use `/` separators, strip a leading ./ and any file:line suffix. */
9
9
  function normalize(path) {
10
- return path.replace(/^\.\//, '').replace(/:\d+(:\d+)?$/, '');
10
+ return path
11
+ .replace(/\\/g, '/')
12
+ .replace(/^\.\//, '')
13
+ .replace(/:\d+(:\d+)?$/, '');
14
+ }
15
+ /**
16
+ * The one rule for "this changed file is that flow source": paths are compared by normalized suffix,
17
+ * so a repo-root-relative change (`web/src/app.ts`) matches a package-relative stamp (`src/app.ts`)
18
+ * and an absolute stamp, and vice-versa. Everything that asks whether a flow touches a file uses it,
19
+ * so "affected" and "stale" can never disagree about which files belong to a flow.
20
+ */
21
+ export function pathsMatch(a, b) {
22
+ const x = normalize(a);
23
+ const y = normalize(b);
24
+ return x === y || x.endsWith(`/${y}`) || y.endsWith(`/${x}`);
25
+ }
26
+ export function sourceMatchesChange(source, changedFiles) {
27
+ return changedFiles.some((c) => pathsMatch(c, source));
11
28
  }
12
29
  /**
13
30
  * Which flows are affected by a set of changed files. Deterministic; a flow with no sources manifest is
@@ -15,11 +32,7 @@ function normalize(path) {
15
32
  * a repo-relative change matches an absolute stamp and vice-versa.
16
33
  */
17
34
  export function affectedFlows(flows, changedFiles) {
18
- const changed = changedFiles.map(normalize);
19
- const matchesChange = (source) => {
20
- const s = normalize(source);
21
- return changed.some((c) => c === s || c.endsWith(`/${s}`) || s.endsWith(`/${c}`));
22
- };
35
+ const matchesChange = (source) => sourceMatchesChange(source, changedFiles);
23
36
  const affected = [];
24
37
  const unknownProvenance = [];
25
38
  for (const flow of flows) {
@@ -1,6 +1,8 @@
1
1
  import { AnchorKind, DriftReason, isConsequenceDrift, ReplayStatus, unreachedRoutes, SuiteIsolation, } from '@reticlehq/core';
2
+ import { replayability, Replayable } from './flow-replayable.js';
2
3
  import { classifyFlowAssertions, FlowAssertionGrade } from './flow-classify.js';
3
4
  import { SUCCESS_STEP_TOOL } from './flow-success.js';
5
+ import { RECORD_A_FLOW } from './suite/coverage.js';
4
6
  /**
5
7
  * Turn a replay result into the autonomy DECISION envelope — the judgement a human reviewer used to
6
8
  * make, expressed so a coding agent can act on it without one. Pure: no IO, no clock.
@@ -43,7 +45,7 @@ const INTENT_BROKEN_PREFIX = 'NO LONGER TRUE: ';
43
45
  * Never an intent derived from step names: a guessed goal reads as the product owner's words and an
44
46
  * agent will act on it. The same rule as the source pointer — absence stays honest.
45
47
  */
46
- const NO_INTENT_ON_PASS = 'no intent declared, so this proves the steps ran, not what they were for — declare one with reticle_intent.';
48
+ const NO_INTENT_ON_PASS = 'no intent declared, so this proves the steps ran, not what they were for — declare one with reticle_run { tool: "reticle_intent" }.';
47
49
  const NO_INTENT_ON_FAIL = 'no intent declared, so this names the mechanism, not the stakes.';
48
50
  /** `<intent> — <mechanical>`, or the mechanical sentence plus the honest absence. */
49
51
  function withIntent(mechanical, statement) {
@@ -215,7 +217,7 @@ invoked = new Map()) {
215
217
  if (flow === undefined)
216
218
  return undefined;
217
219
  if (0 === flow.steps.length) {
218
- return 'the flow has no steps — it replays green whatever the app does. Record it again, or add steps with reticle_annotate.';
220
+ return 'the flow has no steps — it replays green whatever the app does. Record it again, or add steps with reticle_run { tool: "reticle_annotate" }.';
219
221
  }
220
222
  const c = classifyFlowAssertions(flow, invoked);
221
223
  if (c.grade !== FlowAssertionGrade.ASSERTION_FREE)
@@ -339,7 +341,7 @@ isolation) {
339
341
  ? ''
340
342
  : ` — ${String(unreached.length)} known route(s) never opened: ${unreached.join(', ')}`;
341
343
  const summary = 0 === total
342
- ? 'no flows to verify — nothing was checked. Record one with reticle_record { action: "start" }, then reticle_flow_save.'
344
+ ? `no flows to verify — nothing was checked. ${RECORD_A_FLOW}`
343
345
  : 0 === failed
344
346
  ? 0 === unverifiable.length
345
347
  ? `all ${total} flow${1 === total ? '' : 's'} pass`
@@ -356,18 +358,31 @@ isolation) {
356
358
  const sharedState = SuiteIsolation.SHARED_SESSION === isolation && total > 1
357
359
  ? ' — these flows shared one session and ran in order, so a pass here may rest on state an earlier flow left behind; replay with `parallel` to give each its own context'
358
360
  : '';
361
+ const notAsSaved = runs.flatMap(({ replay, flow }) => {
362
+ if (flow === undefined)
363
+ return [];
364
+ const report = replayability(flow);
365
+ return Replayable.YES === report.status && report.writes === undefined
366
+ ? []
367
+ : [{ flow: replay.name, ...report }];
368
+ });
369
+ const notReplayable = notAsSaved.filter((row) => Replayable.YES !== row.status);
370
+ const asSaved = 0 === notReplayable.length
371
+ ? ''
372
+ : ` — ${String(notReplayable.length)} of ${String(total)} flows are not replayable as saved (${notReplayable.map((row) => row.flow).join(', ')}): a drift there is the flow, not the app`;
359
373
  return {
360
374
  status,
361
375
  total,
362
376
  passed,
363
377
  failed,
364
- summary: summary + silentSteps + neverOpened + disagreed + sharedState,
378
+ summary: summary + silentSteps + neverOpened + disagreed + sharedState + asSaved,
365
379
  failures,
366
380
  ...(isolation === undefined ? {} : { isolation }),
367
381
  ...(unverifiable.length > 0 ? { unverifiable } : {}),
368
382
  ...(coverage === undefined ? {} : { coverage }),
369
383
  ...(0 === unreached.length ? {} : { unreached }),
370
384
  ...(0 === contradictions.length ? {} : { contradictions }),
385
+ ...(0 === notAsSaved.length ? {} : { replayability: notAsSaved }),
371
386
  };
372
387
  }
373
388
  /**
@@ -24,6 +24,11 @@ export declare function anchorFieldName(anchor: FlowAnchor): string | undefined;
24
24
  export declare const REDACTED_FILL = "<redacted: supply at replay>";
25
25
  /** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
26
26
  export declare const SECRET_NAME_ARG = "secret";
27
+ /**
28
+ * The arg a RECORDED step carries when the SDK said its target holds a secret. Recorder-internal:
29
+ * it decides redaction at save and never reaches the saved flow.
30
+ */
31
+ export declare const SECRET_FIELD_ARG = "secretField";
27
32
  /**
28
33
  * The environment variable that supplies one redacted field.
29
34
  *
@@ -45,6 +50,10 @@ export declare const callSecretsArg: z.ZodOptional<z.ZodRecord<z.ZodString, z.Zo
45
50
  * daemon's environment.
46
51
  */
47
52
  export declare function secretValue(envKey: string, env: Record<string, string | undefined>): string | undefined;
53
+ /** The field's own saved variable name, or its original key for legacy and invalid metadata. */
54
+ export declare function secretKeyForFill(args: Record<string, unknown> | undefined, field: string): string | undefined;
55
+ /** Allocate recorded fills' names while preserving legacy placeholders and existing suffixes. */
56
+ export declare function withDistinctSecretKeys(flow: FlowFile): FlowFile;
48
57
  /** One field a flow needs supplied, and the variable that supplies it. */
49
58
  export interface UnsuppliedSecret {
50
59
  field: string;
@@ -32,6 +32,11 @@ export function anchorFieldName(anchor) {
32
32
  export const REDACTED_FILL = '<redacted: supply at replay>';
33
33
  /** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
34
34
  export const SECRET_NAME_ARG = 'secret';
35
+ /**
36
+ * The arg a RECORDED step carries when the SDK said its target holds a secret. Recorder-internal:
37
+ * it decides redaction at save and never reaches the saved flow.
38
+ */
39
+ export const SECRET_FIELD_ARG = 'secretField';
35
40
  /** The prefix every secret's variable carries. */
36
41
  const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
37
42
  /**
@@ -50,7 +55,7 @@ export const secretEnvKey = (field) => `${SECRET_ENV_PREFIX}${field.replace(/[^a
50
55
  /** The schema of that argument, shared by every tool that replays a flow. */
51
56
  export { CALL_SECRETS_ARG };
52
57
  export const callSecretsArg = z
53
- .record(z.string())
58
+ .record(z.string(), z.string())
54
59
  .optional()
55
60
  .describe('Redacted fields\' values, this call only, never kept: { "auth-password": "…" }');
56
61
  /**
@@ -64,6 +69,63 @@ export function secretValue(envKey, env) {
64
69
  }
65
70
  return env[envKey];
66
71
  }
72
+ const SECRET_OCCURRENCE = /^(?:[2-9]|[1-9][0-9]+)$/;
73
+ /** The field's own saved variable name, or its original key for legacy and invalid metadata. */
74
+ export function secretKeyForFill(args, field) {
75
+ if (args?.['value'] !== REDACTED_FILL)
76
+ return undefined;
77
+ const named = args[SECRET_NAME_ARG];
78
+ const base = secretEnvKey(field);
79
+ // A flow can supply this field's occurrence, never an unrelated environment variable.
80
+ return 'string' === typeof named &&
81
+ named.startsWith(`${base}_`) &&
82
+ SECRET_OCCURRENCE.test(named.slice(base.length + 1))
83
+ ? named
84
+ : base;
85
+ }
86
+ function* secretSteps(steps) {
87
+ for (const step of steps) {
88
+ yield step;
89
+ if (step.steps !== undefined)
90
+ yield* secretSteps(step.steps);
91
+ }
92
+ }
93
+ /** Allocate recorded fills' names while preserving legacy placeholders and existing suffixes. */
94
+ export function withDistinctSecretKeys(flow) {
95
+ const reserved = new Set();
96
+ const used = new Set();
97
+ for (const step of secretSteps(flow.steps)) {
98
+ const field = anchorFieldName(step.anchor);
99
+ if (field === undefined)
100
+ continue;
101
+ const key = secretKeyForFill(step.args, field);
102
+ if (key === undefined)
103
+ continue;
104
+ reserved.add(key);
105
+ if (key !== secretEnvKey(field) || step.args?.[SECRET_NAME_ARG] === undefined)
106
+ used.add(key);
107
+ }
108
+ const assign = (step) => {
109
+ let out = step;
110
+ const field = anchorFieldName(step.anchor);
111
+ if (field !== undefined &&
112
+ step.args?.['value'] === REDACTED_FILL &&
113
+ step.args[SECRET_NAME_ARG] === secretEnvKey(field)) {
114
+ const base = secretEnvKey(field);
115
+ let key = base;
116
+ let occurrence = 2;
117
+ while (used.has(key) || (key !== base && reserved.has(key))) {
118
+ key = `${base}_${occurrence}`;
119
+ occurrence += 1;
120
+ }
121
+ used.add(key);
122
+ if (key !== base)
123
+ out = { ...step, args: { ...step.args, [SECRET_NAME_ARG]: key } };
124
+ }
125
+ return step.steps === undefined ? out : { ...out, steps: step.steps.map(assign) };
126
+ };
127
+ return { ...flow, steps: flow.steps.map(assign) };
128
+ }
67
129
  /**
68
130
  * Every credential this flow will replay as the literal placeholder.
69
131
  *
@@ -79,13 +141,13 @@ export function secretValue(envKey, env) {
79
141
  export function unsuppliedSecrets(flow, env) {
80
142
  const out = [];
81
143
  const seen = new Set();
82
- for (const step of flow.steps ?? []) {
83
- if (REDACTED_FILL !== step.args?.['value'])
84
- continue;
144
+ for (const step of secretSteps(flow.steps ?? [])) {
85
145
  const field = anchorFieldName(step.anchor);
86
146
  if (field === undefined)
87
147
  continue;
88
- const envKey = secretEnvKey(field);
148
+ const envKey = secretKeyForFill(step.args, field);
149
+ if (envKey === undefined)
150
+ continue;
89
151
  const supplied = secretValue(envKey, env);
90
152
  if (supplied !== undefined && supplied.length > 0)
91
153
  continue;
@@ -101,6 +101,11 @@ export declare function reresolved(anchor: FlowAnchor, refs: readonly string[]):
101
101
  * consequence did not hold.
102
102
  */
103
103
  export declare function expectElementDrift(value: string, hint: QueryEmptyHint | undefined): Drift;
104
+ /** One look, no settling: for an anchor that may legitimately not be on the page yet. */
105
+ export declare function queryOnce(session: FlowReplaySession, queryArgs: Record<string, unknown>): Promise<{
106
+ refs: string[];
107
+ hint?: QueryEmptyHint;
108
+ }>;
104
109
  export declare function resolveQuery(session: FlowReplaySession, queryArgs: Record<string, unknown>, sleep: Sleep, now?: () => number): Promise<{
105
110
  refs: string[];
106
111
  hint?: QueryEmptyHint;
@@ -309,6 +309,10 @@ async function settleTick(session, sleep) {
309
309
  unsubscribe?.();
310
310
  }
311
311
  }
312
+ /** One look, no settling: for an anchor that may legitimately not be on the page yet. */
313
+ export async function queryOnce(session, queryArgs) {
314
+ return readQuery(await session.command(ReticleCommand.QUERY, queryArgs));
315
+ }
312
316
  export async function resolveQuery(session, queryArgs, sleep, now = Date.now) {
313
317
  let last = readQuery(await session.command(ReticleCommand.QUERY, queryArgs));
314
318
  const deadline = now() + ANCHOR_SETTLE_BUDGET_MS;
@@ -1,4 +1,4 @@
1
- import type { Contradiction, FlowStepResult } from '@reticlehq/core';
1
+ import type { Contradiction, FlowStep, FlowStepResult, Predicate } from '@reticlehq/core';
2
2
  /** Cross-step findings belong to no single step; -1 is the address the suite verdict already uses. */
3
3
  export declare const CROSS_STEP_INDEX = -1;
4
4
  /**
@@ -13,3 +13,9 @@ export declare const CROSS_STEP_INDEX = -1;
13
13
  * Exported for its own test: the subtraction is the whole rule, and it is pure.
14
14
  */
15
15
  export declare function crossStepOnly(whole: readonly Contradiction[], steps: readonly FlowStepResult[]): Contradiction[];
16
+ /**
17
+ * Every consequence the flow declared, sub-steps included. The whole-span pass judges the same
18
+ * window the steps did, so a failure a step expected is expected here too. Without it, the per-step
19
+ * pass dropped the declared failure and this pass reported it again as a cross-step finding.
20
+ */
21
+ export declare function declaredIn(steps: readonly FlowStep[]): Predicate[];
@@ -1,3 +1,4 @@
1
+ import { flattenSteps } from './flow-classify.js';
1
2
  /** A contradiction's identity for de-duplication: the rule that fired, and the evidence it fired on. */
2
3
  function contradictionId(found) {
3
4
  return `${found.kind}|${found.detail}`;
@@ -19,3 +20,11 @@ export function crossStepOnly(whole, steps) {
19
20
  const seen = new Set(steps.flatMap((step) => (step.contradictions ?? []).map(contradictionId)));
20
21
  return whole.filter((found) => !seen.has(contradictionId(found)));
21
22
  }
23
+ /**
24
+ * Every consequence the flow declared, sub-steps included. The whole-span pass judges the same
25
+ * window the steps did, so a failure a step expected is expected here too. Without it, the per-step
26
+ * pass dropped the declared failure and this pass reported it again as a cross-step finding.
27
+ */
28
+ export function declaredIn(steps) {
29
+ return flattenSteps(steps).flatMap((step) => (step.expect === undefined ? [] : [step.expect]));
30
+ }
@@ -11,15 +11,12 @@
11
11
  * re-save writes the canonical shape. A kind a saved flow cannot enforce is refused, not stripped
12
12
  * to an empty expect that would grade asserted-while-unchecked.
13
13
  */
14
- import { FlowExpectSchema, FlowPredicateSchema, READABLE_FLOW_VERSIONS, FlowErrorCode, FlowFileSchema, } from '@reticlehq/core';
14
+ import { FlowExpectSchema, FlowPredicateSchema, READABLE_FLOW_VERSIONS, FlowErrorCode, FlowFileSchema, isPlainRecord as isRecord, } from '@reticlehq/core';
15
15
  export const FlowParseNote = {
16
16
  NOT_JSON: 'flow file is not valid JSON — fix the syntax or regenerate it with reticle_flow_save',
17
17
  MALFORMED: 'flow file is malformed — fix or regenerate it with reticle_flow_save',
18
18
  UNSUPPORTED_SHAPE: 'valid JSON, unsupported expect shape',
19
19
  };
20
- function isRecord(value) {
21
- return 'object' === typeof value && null !== value && !Array.isArray(value);
22
- }
23
20
  /**
24
21
  * Flatten `signal: { name, count }` into the on-disk fields. Other channels already match FlowExpect.
25
22
  * Leave a signal object with no name alone so the schema failure can name the key.
@@ -127,15 +124,22 @@ export function coerceFlowFileExpects(raw) {
127
124
  * The issues a union rejection buries.
128
125
  *
129
126
  * `expect` accepts a predicate OR a v1 expect, and zod reports a union failure as one
130
- * `invalid_union` issue whose branch errors live inside `unionErrors`. The one that matters is the
127
+ * `invalid_union` issue whose branch errors live inside `errors`, with paths relative to the union. The one that matters is the
131
128
  * v1 branch's `unrecognized_keys` — the misspelled field. Without this the file was still correctly
132
129
  * REFUSED and the message said only "malformed", which sends the author back to hunt a
133
130
  * one-character typo we had already identified.
134
131
  */
135
132
  function flatten(issues) {
136
- return issues.flatMap((issue) => 'invalid_union' === issue.code
137
- ? [issue, ...flatten(issue.unionErrors.flatMap((e) => e.issues))]
138
- : [issue]);
133
+ return issues.flatMap((issue) => {
134
+ if ('invalid_union' !== issue.code) {
135
+ return [issue];
136
+ }
137
+ const branches = issue.errors.flat().map((inner) => ({
138
+ ...inner,
139
+ path: [...issue.path, ...inner.path],
140
+ }));
141
+ return [issue, ...flatten(branches)];
142
+ });
139
143
  }
140
144
  export function describeFlowZodFailure(error) {
141
145
  const all = flatten(error.issues);
@@ -148,12 +152,13 @@ export function describeFlowZodFailure(error) {
148
152
  * top-level `invalid_union` says only "malformed", which is true and useless.
149
153
  */
150
154
  const named = (one) => {
151
- // NOT the discriminator complaint. `invalid_union_discriminator` on `expect.kind` is the
155
+ // NOT the discriminator complaint. An `invalid_union` with a `discriminator` on `expect.kind` is the
152
156
  // PREDICATE branch objecting that a v1 expect has no `kind` — which is true of every v1 expect
153
157
  // ever written and tells the author nothing. The useful issue is the one from the branch they
154
158
  // were actually writing.
155
- if ('invalid_union_discriminator' === one.code)
159
+ if ('invalid_union' === one.code && undefined !== one.discriminator) {
156
160
  return false;
161
+ }
157
162
  return (('steps' === one.path[0] && 'expect' === one.path[2] && one.path.length > 3) ||
158
163
  ('success' === one.path[0] && one.path.length > 1));
159
164
  };
@@ -12,7 +12,9 @@ import { classifyFlowAssertions } from './flow-classify.js';
12
12
  *
13
13
  * Nothing here derives an intent from step names. A flow that declares none reports that it declares
14
14
  * none — a guessed intent puts words in the product owner's mouth and an agent will act on them,
15
- * which is strictly worse than the honest absence.
15
+ * which is strictly worse than the honest absence. An auto-saved drive does carry a sentence built
16
+ * from its expects (`intentDerived`), so a reader can tell what it checks; it never enters the
17
+ * ledger, and the flow still reports that it declares no intent.
16
18
  */
17
19
  /** Namespaced so a flow-declared intent never collides with one an agent declared by hand. */
18
20
  const FLOW_INTENT_ID_PREFIX = 'flow:';
@@ -35,6 +37,9 @@ export function flowReplayVerdictId(flowName, at) {
35
37
  function intentIdOf(flow) {
36
38
  if (flow.intentId !== undefined)
37
39
  return flow.intentId;
40
+ // A sentence built from the steps names the flow; it is not a goal, so it declares nothing.
41
+ if (true === flow.intentDerived)
42
+ return undefined;
38
43
  // TRIMMED, not merely defined. `intent: " "` satisfied `!== undefined` and silenced the gap, so
39
44
  // a flow whose stated goal is whitespace looked identical on disk to one somebody thought about.
40
45
  //
@@ -58,3 +58,11 @@ export declare function establishedState(flow: FlowFile): readonly Predicate[];
58
58
  * tab on `?tab=summary` as already at `?tab=wrap`.
59
59
  */
60
60
  export declare function samePath(observed: string, expected: string): boolean;
61
+ /**
62
+ * How long replay waits for the start page: the first step's budget when that is longer.
63
+ *
64
+ * A dev server that compiles a route on its first visit can take longer than the floor, and the
65
+ * flow then ended as unverifiable with nothing run. A step the caller let wait 15 s for its
66
+ * consequence can also wait 15 s for its page.
67
+ */
68
+ export declare function startPathBudgetMs(flow: FlowFile): number;
@@ -137,3 +137,16 @@ export function samePath(observed, expected) {
137
137
  const comparable = expected.includes('?') ? observed : withoutQuery(observed);
138
138
  return trimmed(comparable) === trimmed(expected);
139
139
  }
140
+ /** The least time replay waits for the SDK to reconnect on the start page. */
141
+ const START_PATH_ARRIVAL_TIMEOUT_MS = 5_000;
142
+ /**
143
+ * How long replay waits for the start page: the first step's budget when that is longer.
144
+ *
145
+ * A dev server that compiles a route on its first visit can take longer than the floor, and the
146
+ * flow then ended as unverifiable with nothing run. A step the caller let wait 15 s for its
147
+ * consequence can also wait 15 s for its page.
148
+ */
149
+ export function startPathBudgetMs(flow) {
150
+ const first = flow.steps[0]?.timeoutMs ?? flow.signalTimeoutMs ?? 0;
151
+ return Math.max(START_PATH_ARRIVAL_TIMEOUT_MS, first);
152
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What a flow needs from the live session to run in a leased context, and what it reports when the
3
+ * lease never came up.
4
+ */
5
+ import { type FlowReplayResult } from '@reticlehq/core';
6
+ import type { ToolDeps } from '../../surface/tools/tool-kit.js';
7
+ /**
8
+ * The URL a leased context should open: the app's ORIGIN, not the live tab's current location.
9
+ *
10
+ * The live tab drifts — every replay navigates it — so using its full URL made each lease start wherever
11
+ * the previous run happened to finish (observed: leases opening /deployments and failing to find the
12
+ * login control that only exists at the root). A lease must be a FRESH visit to a deterministic entry
13
+ * point; flows that need another page carry their own startPath.
14
+ */
15
+ export declare function leasableAppUrl(deps: ToolDeps, sessionId: string | undefined): string | undefined;
16
+ /**
17
+ * The live session's own URL — what the fixture port must be looked up by.
18
+ *
19
+ * NOT `leasableAppUrl`. That returns an ORIGIN, and the input provider finds a page by comparing
20
+ * full URLs, so an origin matched no page: `suiteFixtureSeed` answered `undefined` on every run and
21
+ * every leased flow booted cold while the code read as if it were seeded. Silent, because every
22
+ * refusal on that path is deliberately silent — a fixture is an optimisation, and a suite must not
23
+ * die when one is unavailable.
24
+ */
25
+ export declare function sessionUrlOf(deps: ToolDeps, sessionId: string | undefined): string | undefined;
26
+ /** A flow whose leased context never came up is a suite ERROR, never a silent pass. */
27
+ export declare function leaseFailureReplay(name: string, error: string | undefined): FlowReplayResult;