@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,18 +1,22 @@
1
1
  import { asFlowName, asProjectId, } from '@reticlehq/core';
2
- import { REDACTED_FILL, SECRET_NAME_ARG, secretEnvKey } from './fields/flow-secret-field.js';
2
+ import { REDACTED_FILL, SECRET_FIELD_ARG, SECRET_NAME_ARG, secretEnvKey, withDistinctSecretKeys, } from './fields/flow-secret-field.js';
3
3
  export { REDACTED_FILL, secretEnvKey } from './fields/flow-secret-field.js';
4
4
  import { safeProjectId } from './flow-result.js';
5
5
  import { changeInPlace } from './narrow-write.js';
6
- import { AnchorKind, DEGRADED_ANCHOR_ROLE, FLOW_FILE_VERSION, flowFileVersionFor, FlowErrorCode, FlowFileSchema, FlowStepTool, QueryBy, defaultIsSensitiveKey, } from '@reticlehq/core';
7
- import { ReticleTool, flowJsonReplacer } from '@reticlehq/core';
6
+ import { dirname } from 'node:path';
7
+ import { gitTracks } from '../../machine/git-tracks.js';
8
+ import { AnchorKind, DEGRADED_ANCHOR_ROLE, DOCUMENT_ANCHOR_ROLE, FLOW_FILE_VERSION, flowFileVersionFor, FlowErrorCode, FlowFileSchema, FlowStepTool, QueryBy, defaultIsSensitiveKey, isGlobalPressCall, } from '@reticlehq/core';
9
+ import { ReticleTool, flowJsonReplacer, mainCheckoutTwin } from '@reticlehq/core';
8
10
  import { asRecord, asString } from '@reticlehq/core';
9
11
  import { applyHealChanges } from './heal.js';
10
12
  import { withLearnedSources } from './learned-sources.js';
11
13
  import { flowIntentGap, linkFlowIntent } from './flow-intent.js';
12
14
  import { journeyFingerprint, journeyName, mergeJourney, routeClaims, withinJourney, } from './flow-journey.js';
13
15
  import { IntentStore } from '../../memory/intent/intent-store.js';
16
+ import { readTextOrUndefined } from '../../memory/project/fs/fs-port.js';
14
17
  import { flowDir, flowParentDir, flowPath, reticleDirPaths, isValidFlowName, } from '../../memory/project/dir/reticle-dir.js';
15
18
  import { describeFlowZodFailure, parseFlowFileText } from './flow-expect-grammar.js';
19
+ import { readyForReplay, replayability, Replayable, } from './flow-replayable.js';
16
20
  /**
17
21
  * The anchor for a DEGRADED step (no resolvable testid). A volatile eXX ref is NEVER persisted —
18
22
  * the on-disk flow carries a placeholder ROLE anchor + degraded:true instead, so a ref can never
@@ -64,6 +68,9 @@ export function anchorForStep(args) {
64
68
  const source = sourceArg(args);
65
69
  if (source !== undefined)
66
70
  anchor.source = source;
71
+ const of = args['of'];
72
+ if ('number' === typeof of && 1 < of)
73
+ anchor.of = of;
67
74
  return { anchor, degraded: false };
68
75
  }
69
76
  // Role + NAME is a real anchor, not a degraded placeholder.
@@ -73,6 +80,14 @@ export function anchorForStep(args) {
73
80
  // that means "add a data-testid". So a step the recorder anchored by accessible name arrived here
74
81
  // and had that name thrown away, which is precisely the anchor that distinguishes one row's
75
82
  // control from another's when a shared JSX source location cannot.
83
+ // A document-key press compiled with no element (#1559): a real anchor, not a degraded one. It is
84
+ // nameless on purpose, because it names no element; the press is what replay dispatches.
85
+ if (by === QueryBy.ROLE &&
86
+ value === DOCUMENT_ANCHOR_ROLE &&
87
+ args['name'] === undefined &&
88
+ isGlobalPressCall({ action: args['action'], args: args['args'] })) {
89
+ return { anchor: { kind: AnchorKind.ROLE, role: DOCUMENT_ANCHOR_ROLE }, degraded: false };
90
+ }
76
91
  if (by === QueryBy.ROLE && value !== undefined) {
77
92
  const name = asString(args['name']);
78
93
  if (name !== undefined && name.length > 0) {
@@ -96,7 +111,8 @@ function subStepToFlowStep(raw) {
96
111
  const action = asString(sub['action']);
97
112
  const args = asRecord(sub['args']);
98
113
  const { anchor, degraded } = anchorForStep(sub);
99
- const step = buildStep(ReticleTool.ACT, anchor, action, args, degraded);
114
+ const step = buildStep(ReticleTool.ACT, anchor, action, args, degraded, markedSecret(sub));
115
+ keepRoleSource(step, sub);
100
116
  /*
101
117
  * The sub-step's own declared consequence, carried rather than folded into the parent.
102
118
  *
@@ -124,15 +140,23 @@ function subStepToFlowStep(raw) {
124
140
  * `defaultIsSensitiveKey` is the same rule the network channel redacts by, so a field considered
125
141
  * sensitive on the wire cannot be considered safe on disk.
126
142
  */
127
- function redactSecretFill(anchor, args) {
143
+ function redactSecretFill(anchor, args,
144
+ /** The SDK said the target holds a secret: redact whatever the field is called. */
145
+ secret = false) {
128
146
  if (typeof args['value'] !== 'string')
129
147
  return args;
130
148
  const field = anchorFieldName(anchor);
131
- if (field === undefined || !defaultIsSensitiveKey(field))
149
+ const sensitive = secret || (field !== undefined && defaultIsSensitiveKey(field));
150
+ if (!sensitive)
132
151
  return args;
152
+ // ponytail: a secret field with no name (a component anchor) gets no variable; replay then refuses it.
153
+ if (field === undefined)
154
+ return { ...args, value: REDACTED_FILL };
133
155
  // The variable that supplies it, beside the placeholder: the file alone says what to set.
134
156
  return { ...args, value: REDACTED_FILL, [SECRET_NAME_ARG]: secretEnvKey(field) };
135
157
  }
158
+ /** Whether a recorded step's args carry the SDK's secret mark. */
159
+ const markedSecret = (args) => true === args[SECRET_FIELD_ARG];
136
160
  /**
137
161
  * The recorded steps as they may be SHOWN: every credential fill carries the placeholder.
138
162
  *
@@ -154,7 +178,7 @@ function redactNormalizedArgs(normalized) {
154
178
  const inner = normalized['args'];
155
179
  if ('object' !== typeof inner || null === inner)
156
180
  return normalized;
157
- const redacted = redactSecretFill(anchorForStep(normalized).anchor, asRecord(inner));
181
+ const redacted = redactSecretFill(anchorForStep(normalized).anchor, asRecord(inner), markedSecret(normalized));
158
182
  return redacted === inner ? normalized : { ...normalized, args: redacted };
159
183
  }
160
184
  /**
@@ -179,8 +203,19 @@ export function anchorFieldName(anchor) {
179
203
  return anchor.name;
180
204
  return undefined;
181
205
  }
182
- function buildStep(tool, anchor, action, args, degraded) {
183
- const step = { tool, anchor, args: redactSecretFill(anchor, args) };
206
+ /**
207
+ * A role anchor has no room for a source, so the stamped source goes on the step. Without it the
208
+ * flow named no file: the gate called the driven component unflowed, and `affected` replayed the
209
+ * flow for every change.
210
+ */
211
+ function keepRoleSource(step, src) {
212
+ const source = sourceArg(src);
213
+ if (AnchorKind.ROLE === step.anchor.kind && source !== undefined) {
214
+ step.source = { file: source.file, line: source.line };
215
+ }
216
+ }
217
+ function buildStep(tool, anchor, action, args, degraded, secret = false) {
218
+ const step = { tool, anchor, args: redactSecretFill(anchor, args, secret) };
184
219
  if (action !== undefined)
185
220
  step.action = action;
186
221
  if (degraded)
@@ -200,6 +235,8 @@ export function recordedStepToFlowStep(step) {
200
235
  out.page = step.page;
201
236
  if (step.endPage !== undefined && step.endPage !== step.page)
202
237
  out.endPage = step.endPage;
238
+ if (true === step.writes)
239
+ out.writes = true;
203
240
  return out;
204
241
  }
205
242
  function anchoredStep(step) {
@@ -235,7 +272,8 @@ function anchoredStep(step) {
235
272
  const action = asString(step.args['action']);
236
273
  const args = asRecord(step.args['args']);
237
274
  const { anchor, degraded } = anchorForStep(step.args);
238
- const out = buildStep(step.tool, anchor, action, args, degraded);
275
+ const out = buildStep(step.tool, anchor, action, args, degraded, markedSecret(step.args));
276
+ keepRoleSource(out, step.args);
239
277
  if (step.expect !== undefined)
240
278
  out.expect = step.expect;
241
279
  return out;
@@ -271,11 +309,24 @@ export class FlowStore {
271
309
  * new run (`RunStore` takes the same callback). Without it a flow saved with no run behind it
272
310
  * waited for the timer, and a daemon that exited first never sent it.
273
311
  */
312
+ /**
313
+ * The main checkout's flows, read-only, when this store sits in a linked git worktree and git
314
+ * ignores `.reticle/`. A flow saved there is then still replayed here. Writes never go to it.
315
+ * When git tracks `.reticle/`, the worktree already has every committed flow, and reading the
316
+ * main checkout brought back a flow that the branch deleted.
317
+ */
318
+ #main;
274
319
  constructor(fs, root, clock, opts = {}) {
275
320
  this.#fs = fs;
276
321
  this.#root = root;
277
322
  this.#clock = clock;
278
323
  this.#onWrote = opts.onWrote;
324
+ const twin = mainCheckoutTwin(root, readTextOrUndefined);
325
+ // The main checkout has no twin of its own, so this never nests deeper than one level.
326
+ this.#main =
327
+ twin === undefined || gitTracks(reticleDirPaths(root).flows)
328
+ ? undefined
329
+ : new FlowStore(fs, twin, clock);
279
330
  }
280
331
  /**
281
332
  * The single byte-stable flow serializer: 2-space indent + one trailing newline. save,
@@ -306,12 +357,16 @@ export class FlowStore {
306
357
  */
307
358
  #summary(flow) {
308
359
  const gap = flowIntentGap(flow);
360
+ const replay = replayability(flow);
309
361
  return {
310
362
  name: flow.name,
311
363
  stepCount: flow.steps.length,
312
364
  degraded: flow.steps.filter((s) => true === s.degraded).length,
313
365
  empty: 0 === flow.steps.length,
314
366
  ...(gap === undefined ? {} : { intentGap: gap }),
367
+ ...(Replayable.YES === replay.status && replay.writes === undefined
368
+ ? {}
369
+ : { replayability: replay }),
315
370
  };
316
371
  }
317
372
  /** The on-disk flow a compiled recording becomes, before anything is written. */
@@ -336,13 +391,17 @@ export class FlowStore {
336
391
  };
337
392
  const intent = program.steps.find((step) => step.intent !== undefined)?.intent;
338
393
  const annotated = withAnnotations(base, annotations);
339
- return {
394
+ return readyForReplay(withDistinctSecretKeys({
340
395
  ...annotated,
341
396
  // The action's own intent, when nobody annotated the flow — see RecordedStep.intent.
342
397
  ...(annotated.intent === undefined && intent !== undefined ? { intent } : {}),
398
+ // Else the sentence an auto-saved drive built from its expects, marked as built.
399
+ ...(annotated.intent === undefined && intent === undefined && program.intent !== undefined
400
+ ? { intent: program.intent, ...(program.intentDerived ? { intentDerived: true } : {}) }
401
+ : {}),
343
402
  ...routeClaims(annotated.startPath, annotated.steps),
344
403
  ...(program.author === undefined ? {} : { author: program.author }),
345
- };
404
+ }));
346
405
  }
347
406
  /**
348
407
  * Convert a CompiledProgram (testid-normalized) into an anchored, on-disk flow + write it.
@@ -458,7 +517,7 @@ export class FlowStore {
458
517
  detail: describeFlowZodFailure(parsed.error),
459
518
  };
460
519
  }
461
- const valid = await this.#linkIntent(parsed.data);
520
+ const valid = await this.#linkIntent(readyForReplay(parsed.data));
462
521
  await this.#fs.mkdir(flowParentDir(this.#root, asFlowName(valid.name), pid));
463
522
  await this.#fs.writeFile(flowPath(this.#root, asFlowName(valid.name), pid), this.#serialize(valid));
464
523
  this.#onWrote?.();
@@ -477,8 +536,12 @@ export class FlowStore {
477
536
  load: (n, p) => this.load(n, p),
478
537
  // Branded at the boundary: the port speaks strings, the store speaks FlowName, and the
479
538
  // name has already passed isValidFlowName inside changeInPlace.
480
- resolvePath: (n, p) => this.#resolveReadPath(asFlowName(n), p),
481
- write: (path, contents) => this.#fs.writeFile(path, contents),
539
+ // A flow read from the main checkout is changed in a copy in this worktree.
540
+ resolvePath: async (n, p) => (await this.#resolveReadPath(asFlowName(n), p)) ?? flowPath(this.#root, asFlowName(n), p),
541
+ write: async (path, contents) => {
542
+ await this.#fs.mkdir(dirname(path));
543
+ await this.#fs.writeFile(path, contents);
544
+ },
482
545
  serialize: (flow) => this.#serialize(flow),
483
546
  readRaw: (path) => this.#fs.readFile(path),
484
547
  }, name, projectId, change);
@@ -539,6 +602,12 @@ export class FlowStore {
539
602
  * name must validate first; `flowPath` takes a branded FlowName precisely so the compiler insists.
540
603
  */
541
604
  async list(projectId) {
605
+ const own = await this.#listOwn(projectId);
606
+ if (this.#main === undefined)
607
+ return own;
608
+ return [...new Set([...own, ...(await this.#main.list(projectId))])].sort();
609
+ }
610
+ async #listOwn(projectId) {
542
611
  const flowsDir = reticleDirPaths(this.#root).flows;
543
612
  const pid = safeProjectId(projectId);
544
613
  const legacy = await this.#namesIn(flowsDir);
@@ -604,6 +673,12 @@ export class FlowStore {
604
673
  * back to a legacy flat (untagged) flow of the same name — so pre-existing flows keep loading.
605
674
  */
606
675
  async load(name, projectId) {
676
+ const own = await this.#loadOwn(name, projectId);
677
+ if (own.ok || own.code !== FlowErrorCode.NOT_FOUND || this.#main === undefined)
678
+ return own;
679
+ return this.#main.load(name, projectId);
680
+ }
681
+ async #loadOwn(name, projectId) {
607
682
  if (!isValidFlowName(name))
608
683
  return { ok: false, code: FlowErrorCode.INVALID_NAME };
609
684
  const path = await this.#resolveReadPath(name, safeProjectId(projectId));
@@ -6,12 +6,18 @@
6
6
  * fires (heal the locator, never the intent).
7
7
  */
8
8
  import { type FlowHealResult } from '@reticlehq/core';
9
+ import { DriftReason } from '@reticlehq/core';
9
10
  import type { ToolDeps } from '../../surface/tools/tool-kit.js';
10
11
  /**
11
- * Why heal produced no proposal: a floor it consulted, or a kind of drift it cannot rebind.
12
+ * Why heal produced no proposal. Three cases.
12
13
  *
13
- * Exported for its own test — the distinction is a sentence a reader ACTS on, and the wrong one
14
- * sends them to lower a threshold that had no part in the refusal.
14
+ * A testid anchor drifted, but no candidate cleared the confidence floor: UNHEALABLE.
15
+ * Every drift is a consequence (the anchors resolved, the assertion failed): NOT_A_REBIND.
16
+ * Any other drift means an anchor did not resolve, so the step did not run: ANCHOR_UNRESOLVED.
17
+ * That message names the nearest candidate when there is one.
18
+ *
19
+ * Exported for its own test. A reader acts on this sentence, and the wrong one sends them to
20
+ * lower a threshold that had no part in the refusal.
15
21
  */
16
- export declare function unhealableMessage(reasons: readonly string[]): string;
22
+ export declare function unhealableMessage(reasons: readonly DriftReason[], nearest?: string | null): string;
17
23
  export declare function healFlow(deps: ToolDeps, args: Record<string, unknown>): Promise<FlowHealResult>;
@@ -6,7 +6,7 @@
6
6
  * fires (heal the locator, never the intent).
7
7
  */
8
8
  import { FLOW_SIGNAL_TIMEOUT_MS, HEAL_CONFIDENCE_MIN, HealStatus, ReplayStatus, } from '@reticlehq/core';
9
- import { asString, DriftReason } from '@reticlehq/core';
9
+ import { asString, DriftReason, isConsequenceDrift } from '@reticlehq/core';
10
10
  import { waitForPredicate } from '@reticlehq/engine/question/predicate/predicate.js';
11
11
  import { replayFlow } from './flow-replay.js';
12
12
  import { applyHealChanges, collectProposals } from './heal.js';
@@ -30,24 +30,39 @@ const HEAL_MESSAGES = {
30
30
  * questions.
31
31
  */
32
32
  NOT_A_REBIND: 'drift found, but none of it is a renamed locator, so there is nothing to rebind — the anchors resolved and what failed was what the steps assert afterwards. The confidence floor was never consulted. Fix the app so the consequence fires again, or update the step expectations by hand',
33
+ ANCHOR_UNRESOLVED: 'drift found, but a step anchor did not resolve on the page, so the step did not run. Heal does not rebind this kind of anchor, and the confidence floor was not used. Update the step anchor by hand',
34
+ ANCHOR_NEAREST_PREFIX: 'The nearest candidate on the page is',
33
35
  HEALED_UNVERIFIED: "rewrote drifted testid anchors. This flow declares its consequences per STEP rather than as a flow `success`, so the rebind was not re-verified end to end — the steps will assert on the next replay, but nothing proved the healed flow still reaches its outcome. Set the flow's `success` (reticle_annotate) to have future heals re-verified before they are written.",
34
36
  CONSEQUENCE_BROKEN: 'rebind resolves the drifted locator to a surviving element, but the healed flow no longer satisfies its success consequence — refusing to write (a heal that loses the intent would ship a green-but-dead test). Fix by hand and verify',
35
37
  };
36
38
  /**
37
- * Why heal produced no proposal: a floor it consulted, or a kind of drift it cannot rebind.
39
+ * Why heal produced no proposal. Three cases.
38
40
  *
39
- * Exported for its own test — the distinction is a sentence a reader ACTS on, and the wrong one
40
- * sends them to lower a threshold that had no part in the refusal.
41
+ * A testid anchor drifted, but no candidate cleared the confidence floor: UNHEALABLE.
42
+ * Every drift is a consequence (the anchors resolved, the assertion failed): NOT_A_REBIND.
43
+ * Any other drift means an anchor did not resolve, so the step did not run: ANCHOR_UNRESOLVED.
44
+ * That message names the nearest candidate when there is one.
45
+ *
46
+ * Exported for its own test. A reader acts on this sentence, and the wrong one sends them to
47
+ * lower a threshold that had no part in the refusal.
41
48
  */
42
- export function unhealableMessage(reasons) {
43
- const rebindable = reasons.some((reason) => DriftReason.TESTID_NOT_FOUND === reason);
44
- return rebindable ? HEAL_MESSAGES.UNHEALABLE : HEAL_MESSAGES.NOT_A_REBIND;
49
+ export function unhealableMessage(reasons, nearest = null) {
50
+ if (reasons.some((reason) => DriftReason.TESTID_NOT_FOUND === reason)) {
51
+ return HEAL_MESSAGES.UNHEALABLE;
52
+ }
53
+ if (reasons.every((reason) => isConsequenceDrift(reason))) {
54
+ return HEAL_MESSAGES.NOT_A_REBIND;
55
+ }
56
+ return null === nearest
57
+ ? HEAL_MESSAGES.ANCHOR_UNRESOLVED
58
+ : `${HEAL_MESSAGES.ANCHOR_UNRESOLVED}. ${HEAL_MESSAGES.ANCHOR_NEAREST_PREFIX} "${nearest}".`;
45
59
  }
46
60
  function toChange(proposal) {
47
61
  return { step: proposal.step, from: proposal.from, to: proposal.to };
48
62
  }
49
63
  export async function healFlow(deps, args) {
50
- const name = asString(args['flowName']) ?? '';
64
+ // `flow` is the alias the tool's schema offers; ignoring it healed a flow named "".
65
+ const name = asString(args['flowName']) ?? asString(args['flow']) ?? '';
51
66
  const apply = true === args['apply'];
52
67
  const target = sessionTarget(deps, asString(args['sessionId']));
53
68
  const { projectId } = target;
@@ -91,13 +106,15 @@ export async function healFlow(deps, args) {
91
106
  }
92
107
  const proposals = collectProposals(steps);
93
108
  if (0 === proposals.length) {
109
+ const drifts = steps.flatMap((step) => (step.drift === undefined ? [] : [step.drift]));
94
110
  return {
95
111
  name,
96
112
  status: HealStatus.UNHEALABLE,
97
113
  applied: false,
98
114
  proposals: [],
99
115
  changed: [],
100
- message: unhealableMessage(steps.flatMap((step) => (step.drift === undefined ? [] : [step.drift.reasonKind]))),
116
+ message: unhealableMessage(drifts.map((drift) => drift.reasonKind), drifts.find((drift) => !isConsequenceDrift(drift.reasonKind) && null !== drift.nearest)
117
+ ?.nearest ?? null),
101
118
  };
102
119
  }
103
120
  if (!apply) {
@@ -8,13 +8,7 @@ import { z } from 'zod';
8
8
  declare const FlakeRecordSchema: z.ZodObject<{
9
9
  runs: z.ZodNumber;
10
10
  fails: z.ZodNumber;
11
- }, "strip", z.ZodTypeAny, {
12
- runs: number;
13
- fails: number;
14
- }, {
15
- runs: number;
16
- fails: number;
17
- }>;
11
+ }, z.core.$strip>;
18
12
  type FlakeRecord = z.infer<typeof FlakeRecordSchema>;
19
13
  /** Per-flow map (flow name → record). */
20
14
  export type FlakeLedger = Record<string, FlakeRecord>;
@@ -23,26 +17,8 @@ export declare const FlakeFileSchema: z.ZodObject<{
23
17
  flows: z.ZodRecord<z.ZodString, z.ZodObject<{
24
18
  runs: z.ZodNumber;
25
19
  fails: z.ZodNumber;
26
- }, "strip", z.ZodTypeAny, {
27
- runs: number;
28
- fails: number;
29
- }, {
30
- runs: number;
31
- fails: number;
32
- }>>;
33
- }, "strip", z.ZodTypeAny, {
34
- flows: Record<string, {
35
- runs: number;
36
- fails: number;
37
- }>;
38
- version: 1;
39
- }, {
40
- flows: Record<string, {
41
- runs: number;
42
- fails: number;
43
- }>;
44
- version: 1;
45
- }>;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>;
46
22
  export declare function emptyRecord(): FlakeRecord;
47
23
  /** Accrue one unchanged-code replay outcome. */
48
24
  export declare function recordOutcome(record: FlakeRecord, passed: boolean): FlakeRecord;
@@ -11,7 +11,7 @@ const FlakeRecordSchema = z.object({
11
11
  });
12
12
  export const FlakeFileSchema = z.object({
13
13
  version: z.literal(1),
14
- flows: z.record(FlakeRecordSchema),
14
+ flows: z.record(z.string(), FlakeRecordSchema),
15
15
  });
16
16
  /** Minimum unchanged-code replays before flakiness can be judged (too few = noise). */
17
17
  const DEFAULT_MIN_FLAKE_RUNS = 5;
@@ -6,11 +6,8 @@
6
6
  * exists on search. That shape is visible from the route list with no change to the flow file, so
7
7
  * stop/save can warn instead of writing a flow that fails on the next click.
8
8
  */
9
- import { EventType } from '@reticlehq/core';
9
+ import { EventType, asString } from '@reticlehq/core';
10
10
  import { routePathOf } from '@reticlehq/engine/question/predicate/predicate-route.js';
11
- function asString(value) {
12
- return 'string' === typeof value ? value : undefined;
13
- }
14
11
  /**
15
12
  * The page a recording step sat on, comparable across path routers and hash routers.
16
13
  *
@@ -47,6 +47,8 @@ export interface RecordedStep {
47
47
  * never saved silently.
48
48
  */
49
49
  unkeptExpect?: string;
50
+ /** The step sent a write request (POST, PUT, PATCH, DELETE) while it was recorded. */
51
+ writes?: true;
50
52
  }
51
53
  interface ActiveRecording {
52
54
  cursor: number;
@@ -92,6 +94,9 @@ export interface CompiledProgram {
92
94
  routes?: string[];
93
95
  /** Who made it — see FlowFile.author. Stamped by the caller that knows. */
94
96
  author?: FlowFile['author'];
97
+ /** A sentence built from the steps' expects (an auto-saved drive): see FlowFile.intentDerived. */
98
+ intent?: string;
99
+ intentDerived?: true;
95
100
  }
96
101
  /**
97
102
  * The `tool` written on an invocation step — core's constant, re-exported for this module's callers.
@@ -153,7 +158,12 @@ export declare class RecordingStore {
153
158
  * they are, so the journey it belongs to is not auto-saved as a flow (#1459).
154
159
  */
155
160
  markMocked(session: string | undefined, active: boolean): void;
156
- capture(step: RecordedStep, route?: string, session?: string): void;
161
+ /**
162
+ * `forAmbient` is the step as the ambient tape keeps it, when that differs: a journey's refuted
163
+ * claims come off the ambient tape (see `unassertLast`), and a recording somebody opened keeps
164
+ * every claim they declared, held or not.
165
+ */
166
+ capture(step: RecordedStep, route?: string, session?: string, forAmbient?: RecordedStep): void;
157
167
  /**
158
168
  * Add a consequence to the last captured step of every active recording.
159
169
  *
@@ -101,7 +101,12 @@ export class RecordingStore {
101
101
  else
102
102
  this.#mocked.delete(session ?? '');
103
103
  }
104
- capture(step, route, session) {
104
+ /**
105
+ * `forAmbient` is the step as the ambient tape keeps it, when that differs: a journey's refuted
106
+ * claims come off the ambient tape (see `unassertLast`), and a recording somebody opened keeps
107
+ * every claim they declared, held or not.
108
+ */
109
+ capture(step, route, session, forAmbient) {
105
110
  this.#navigatedSinceStep = false;
106
111
  const mocked = this.#mocked.has(session ?? '');
107
112
  const ambient = ambientRecordingOf(session);
@@ -138,13 +143,14 @@ export class RecordingStore {
138
143
  // The route rides on the AMBIENT tape only: a recording somebody opened deliberately is
139
144
  // already one journey by construction, and stamping a route on its steps would change what a
140
145
  // deliberate recording contains.
146
+ const taped = isAmbient(name) ? (forAmbient ?? step) : step;
141
147
  rec.steps.push(isAmbient(name) && (route !== undefined || mocked)
142
148
  ? {
143
- ...step,
149
+ ...taped,
144
150
  ...(route === undefined ? {} : { route }),
145
151
  ...(mocked ? { mocked: true } : {}),
146
152
  }
147
- : step);
153
+ : taped);
148
154
  }
149
155
  }
150
156
  /**
@@ -1,4 +1,4 @@
1
- import { type Predicate } from '@reticlehq/core';
1
+ import { pathOf, type Predicate, type ReticleEvent } from '@reticlehq/core';
2
2
  import { type CommandResult } from '@reticlehq/core';
3
3
  import type { RecordedStep, CompiledProgram } from './recording/tape/recordings.js';
4
4
  import type { Session } from '../../portal/session/session.js';
@@ -34,7 +34,16 @@ export declare function replayActionArgs(value: unknown, confirmDangerous?: bool
34
34
  * Pathname rather than the whole url, because that is what `startPath` is compared against and what
35
35
  * a hash-routed app makes meaningless in the document location — see routeOfEvent.
36
36
  */
37
- export declare function pathOf(url: string | undefined): string | undefined;
37
+ export { pathOf };
38
+ /**
39
+ * Did the app send a write request in this window? A step that did is saved `writes: true`, so a
40
+ * replay does not repeat it unasked. The dev server's own traffic is not the app's.
41
+ */
42
+ export declare function wroteIn(events: readonly ReticleEvent[]): boolean;
43
+ /** `wroteIn` over a session's window, best-effort: the record must never fail the drive it records. */
44
+ export declare function wroteSince(session: {
45
+ eventsSince(since: number): readonly ReticleEvent[];
46
+ }, since: number): boolean;
38
47
  /** What a saved flow could not keep, and the fix. See RecordedStep.unkeptExpect. */
39
48
  export declare const UNKEPT_EXPECT: string;
40
49
  /**
@@ -51,14 +60,18 @@ export declare function captureAct(recordings: {
51
60
  /** Where this step ran, so the ambient tape can be cut into journeys. See RecordedStep.route. */
52
61
  route?: string,
53
62
  /** The session that acted: only recordings it started take the step. */
54
- session?: string): void;
63
+ session?: string,
64
+ /** The act's window sent a write request; see `wroteIn`. */
65
+ wrote?: boolean): void;
55
66
  /**
56
67
  * Capture an act_and_wait once its verdict is known, keeping `until` as the step's expectation only
57
68
  * on a yes. Recorded before the verdict, a step kept an `until` that came back `no` or `no-fault` —
58
69
  * a regression test asserting something never once observed to hold because of the action. The
59
70
  * action itself is always recorded: it happened, and replay needs it to reach the next step.
60
71
  */
61
- export declare function captureVerdictedAct(recordings: Parameters<typeof captureAct>[0], args: Record<string, unknown>, res: unknown, route: string | undefined, verified: string | undefined, session?: string): void;
72
+ export declare function captureVerdictedAct(recordings: Parameters<typeof captureAct>[0], args: Record<string, unknown>, res: unknown, route: string | undefined, verified: string | undefined, session?: string,
73
+ /** The act's window sent a write request; see `wroteIn`. */
74
+ wrote?: boolean): void;
62
75
  /** Fold a PASSING standalone assertion into the step it proved. See RecordingStore.attachExpect. */
63
76
  export declare function captureAssertion(recordings: {
64
77
  attachExpect: (expect: Predicate, session?: string) => void;
@@ -76,6 +89,14 @@ export declare function compileActStep(args: Record<string, unknown>, res: unkno
76
89
  * every sequence unreplayable on an app without testids.
77
90
  */
78
91
  export declare function compileSequenceStep(args: Record<string, unknown>, res: unknown): RecordedStep;
92
+ /**
93
+ * A compiled step that presses a document key at no element (#1559).
94
+ *
95
+ * Both halves are required. The anchor alone is not enough, because a hand-edited `role: document`
96
+ * on a click would then dispatch that click at nothing; and the press alone is not enough, because a
97
+ * recorded Escape aimed at a named element keeps that element.
98
+ */
99
+ export declare function isDocumentPress(step: Record<string, unknown>): boolean;
79
100
  interface ReplayStepResult {
80
101
  tool: string;
81
102
  ok: boolean;
@@ -103,4 +124,3 @@ via?: readonly {
103
124
  flow: string;
104
125
  step: number;
105
126
  }[]): Promise<ReplayStepResult[]>;
106
- export {};