@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
@@ -5,10 +5,13 @@
5
5
  * individual run to a deploy. The run is already clock-stamped by buildVerificationRun, so the store
6
6
  * needs no clock.
7
7
  */
8
- import { asRunId, ReticleVerificationRunSchema, RUN_RETENTION, RUN_RETENTION_SLACK, RunReadError, RunScreenshotSchema, STEP_SCREENSHOT, } from '@reticlehq/core';
8
+ import { callingAttachId } from '../../../hooks/coding-agents.js';
9
+ import { episodeStampFor } from '../../../hooks/episode-stamp.js';
10
+ import { asRunId, checkoutOf, ReticleDir, ReticleVerificationRunSchema, RUN_RETENTION, RUN_RETENTION_SLACK, RunReadError, RunScreenshotSchema, STEP_SCREENSHOT, } from '@reticlehq/core';
9
11
  import { PromptContextSchema } from '@reticlehq/core/artifacts';
12
+ import { readTextOrUndefined } from '../../../memory/project/fs/fs-port.js';
10
13
  import { reticleDirPaths, isValidRunId, runPath, stepShotDir, } from '../../../memory/project/dir/reticle-dir.js';
11
- import { join } from 'node:path';
14
+ import { dirname, join } from 'node:path';
12
15
  const JSON_INDENT = 2;
13
16
  const JSON_EXT = '.json';
14
17
  const TMP_EXT = '.tmp';
@@ -34,18 +37,53 @@ export class RunStore {
34
37
  * Guards runId as a safe path segment BEFORE building the path — a runId can originate from a caller
35
38
  * (an OEM may set it), so an unsafe value must never escape .reticle/runs/ (mirrors the read guard).
36
39
  */
37
- async write(given) {
40
+ /**
41
+ * The branch of the checkout that holds these runs. None for a folder inside Reticle's own
42
+ * storage (`~/.reticle/unmatched/<id>`): the walk up from there finds the home folder, which can be
43
+ * a dotfiles repository, and its branch says nothing about the app.
44
+ */
45
+ #branch() {
46
+ const project = dirname(this.#root);
47
+ if (project.split(/[\\/]/).includes(ReticleDir.ROOT)) {
48
+ return undefined;
49
+ }
50
+ return checkoutOf(project, readTextOrUndefined)?.branch;
51
+ }
52
+ async write(given,
53
+ /** The tab the run came from, so a run written outside any call still finds its episode. */
54
+ hint = {}) {
38
55
  let run = given;
39
56
  if (!isValidRunId(run.runId)) {
40
57
  throw new Error(`refusing to write run with unsafe runId: ${JSON.stringify(run.runId)}`);
41
58
  }
42
59
  await this.#fs.mkdir(reticleDirPaths(this.#root).runs);
43
- const context = run.context ?? (await this.#recentRequest(run.createdAt, run.runId));
44
- if (context !== undefined)
60
+ const context = run.context ??
61
+ (await this.#recentRequest(run.createdAt, run.runId)) ??
62
+ (await this.#heldContext(run.runId));
63
+ if (context !== undefined) {
45
64
  run = { ...run, context };
65
+ }
66
+ // The episode this run came from, the agent session behind it, and the commit it ran against,
67
+ // so it joins exactly.
68
+ const episode = episodeStampFor(this.#root, callingAttachId(), hint.sessionId);
69
+ if (episode !== undefined) {
70
+ const commit = run.project.commit ?? episode.head;
71
+ run = {
72
+ ...run,
73
+ episodeId: episode.episodeId,
74
+ ...(episode.agentSession === undefined ? {} : { agentSession: episode.agentSession }),
75
+ project: { ...run.project, ...(commit === undefined ? {} : { commit }) },
76
+ };
77
+ }
46
78
  // The step screenshots taken for this run, the last of which may still be landing.
47
79
  await shotsLanded(this.#root, run.runId);
48
80
  run = withScreenshots(run, await readStepShots(this.#fs, this.#root, run.runId));
81
+ // Several agents drive one project at once, each in its own git worktree. Every run kind is
82
+ // written here, so here the run learns which branch it belongs to.
83
+ const branch = run.project.branch ?? this.#branch();
84
+ if (branch !== undefined) {
85
+ run = { ...run, project: { ...run.project, branch } };
86
+ }
49
87
  // Atomic publish: write a temp file then rename, so a crash mid-write never leaves a half-written
50
88
  // artifact (a partial.json would otherwise read back as MALFORMED).
51
89
  const path = runPath(this.#root, run.runId);
@@ -71,16 +109,19 @@ export class RunStore {
71
109
  const path = reticleDirPaths(this.#root).request;
72
110
  const raw = JSON.parse(await this.#fs.readFile(path));
73
111
  const parsed = PromptContextSchema.safeParse(raw);
74
- if (!parsed.success)
112
+ if (!parsed.success) {
75
113
  return undefined;
114
+ }
76
115
  const given = parsed.data.at;
77
- if (given === undefined || at - given < 0 || REQUEST_RELEVANT_MS < at - given)
116
+ if (given === undefined || at - given < 0 || REQUEST_RELEVANT_MS < at - given) {
78
117
  return undefined;
118
+ }
79
119
  // The first run written for a request answers it; a later run (the next agent session in the
80
120
  // same tab) inherited it and showed a goal it never had. Its own rewrite keeps it.
81
121
  const answeredBy = raw[REQUEST_RUN_KEY];
82
- if ('string' === typeof answeredBy)
122
+ if ('string' === typeof answeredBy) {
83
123
  return answeredBy === runId ? parsed.data : undefined;
124
+ }
84
125
  await this.#fs.writeFile(path, `${JSON.stringify({ ...raw, [REQUEST_RUN_KEY]: runId }, null, JSON_INDENT)}\n`);
85
126
  return parsed.data;
86
127
  }
@@ -88,14 +129,30 @@ export class RunStore {
88
129
  return undefined; // no request recorded: the common case
89
130
  }
90
131
  }
132
+ /**
133
+ * The request this run already carries on disk. A tab's run is written again after every verdict,
134
+ * and the prompt hook replaces request.json on every prompt: a newer prompt made the rewrite find
135
+ * no request of its own and drop the one it had, on this machine and on the platform.
136
+ */
137
+ async #heldContext(runId) {
138
+ try {
139
+ const held = JSON.parse(await this.#fs.readFile(runPath(this.#root, runId)));
140
+ const parsed = PromptContextSchema.safeParse(held.context);
141
+ return parsed.success ? parsed.data : undefined;
142
+ }
143
+ catch {
144
+ return undefined; // a first write: nothing held yet
145
+ }
146
+ }
91
147
  /**
92
148
  * Keep .reticle/runs/ bounded. Only acts once the count exceeds RUN_RETENTION + SLACK, then deletes the
93
149
  * oldest (by createdAt) back down to RUN_RETENTION — so the read-all is amortized, not per-write.
94
150
  */
95
151
  async #pruneOld() {
96
152
  const ids = await this.list();
97
- if (ids.length <= this.#retention + this.#slack)
153
+ if (ids.length <= this.#retention + this.#slack) {
98
154
  return;
155
+ }
99
156
  // `id: RunId`, not `string`. `list()` already returns RunId[]; annotating the local as string
100
157
  // silently discarded the brand and handed a bare string to runPath — which is the transposition
101
158
  // the brand exists to prevent, reintroduced by a type annotation rather than by a bad call.
@@ -111,11 +168,13 @@ export class RunStore {
111
168
  }
112
169
  /** Never throws. Invalid id / missing → MISSING; bad JSON or failed schema → MALFORMED. */
113
170
  async read(runId) {
114
- if (!isValidRunId(runId))
171
+ if (!isValidRunId(runId)) {
115
172
  return { ok: false, reason: RunReadError.MISSING };
173
+ }
116
174
  const path = runPath(this.#root, runId);
117
- if (!(await this.#fs.exists(path)))
175
+ if (!(await this.#fs.exists(path))) {
118
176
  return { ok: false, reason: RunReadError.MISSING };
177
+ }
119
178
  let text;
120
179
  try {
121
180
  text = await this.#fs.readFile(path);
@@ -134,15 +193,17 @@ export class RunStore {
134
193
  return { ok: false, reason: RunReadError.MALFORMED };
135
194
  }
136
195
  const result = ReticleVerificationRunSchema.safeParse(parsed);
137
- if (!result.success)
196
+ if (!result.success) {
138
197
  return { ok: false, reason: RunReadError.MALFORMED };
198
+ }
139
199
  return { ok: true, run: result.data };
140
200
  }
141
201
  /** List run ids on disk (filenames minus.json). Empty when the runs dir is absent. */
142
202
  async list() {
143
203
  const dir = reticleDirPaths(this.#root).runs;
144
- if (!(await this.#fs.exists(dir)))
204
+ if (!(await this.#fs.exists(dir))) {
145
205
  return [];
206
+ }
146
207
  let entries;
147
208
  try {
148
209
  entries = await this.#fs.readdir(dir);
@@ -154,6 +215,17 @@ export class RunStore {
154
215
  .filter((e) => e.endsWith(JSON_EXT))
155
216
  .map((e) => asRunId(e.slice(0, -JSON_EXT.length)));
156
217
  }
218
+ /** Every readable run. Retention bounds how many there are. */
219
+ async all() {
220
+ const runs = [];
221
+ for (const id of await this.list()) {
222
+ const result = await this.read(id);
223
+ if (result.ok) {
224
+ runs.push(result.run);
225
+ }
226
+ }
227
+ return runs;
228
+ }
157
229
  /** The most-recent run by createdAt (undefined when none). Powers reticle_run_export's default. */
158
230
  async latest() {
159
231
  const ids = await this.list();
@@ -166,6 +238,44 @@ export class RunStore {
166
238
  }
167
239
  return best;
168
240
  }
241
+ /**
242
+ * The newest recorded result for each flow name, taken across every readable run, with the time
243
+ * and id of the run it came from. A run that carries no flows (a drive or an export) says nothing
244
+ * about any flow, so it can neither supply nor erase a result: judging coverage from `latest()`
245
+ * alone let one such run hide every earlier replay. Equal times break on the run id, so the answer
246
+ * never depends on the order `list()` returns.
247
+ */
248
+ async latestPerFlow() {
249
+ const newest = new Map();
250
+ for (const id of await this.list()) {
251
+ const read = await this.read(id);
252
+ if (!read.ok) {
253
+ continue;
254
+ }
255
+ const createdAt = read.run.createdAt;
256
+ for (const result of read.run.flows) {
257
+ const s = newest.get(result.name);
258
+ if (!s || createdAt > s.createdAt || (createdAt === s.createdAt && id > s.id)) {
259
+ newest.set(result.name, { result, createdAt, id });
260
+ }
261
+ }
262
+ }
263
+ return newest;
264
+ }
265
+ /**
266
+ * The names `credit` (the gate's passing rule) gives each flow's newest result, each with the time
267
+ * of that result, so a caller can refuse a pass that predates an edit. The rule is passed in, so
268
+ * the run store does not reach into the flow language.
269
+ */
270
+ async passingFlowTimes(credit) {
271
+ const passing = new Map();
272
+ for (const { result, createdAt } of (await this.latestPerFlow()).values()) {
273
+ for (const name of credit([result])) {
274
+ passing.set(name, Math.max(passing.get(name) ?? createdAt, createdAt));
275
+ }
276
+ }
277
+ return passing;
278
+ }
169
279
  /**
170
280
  * The two most-recent runs by createdAt as `[previous, current]` (oldest-first), or undefined when
171
281
  * fewer than two readable runs exist. Powers reticle_run_export's `format:"diff"` (run-to-run deltas).
@@ -174,16 +284,19 @@ export class RunStore {
174
284
  const runs = [];
175
285
  for (const id of await this.list()) {
176
286
  const result = await this.read(id);
177
- if (result.ok)
287
+ if (result.ok) {
178
288
  runs.push(result.run);
289
+ }
179
290
  }
180
- if (runs.length < 2)
291
+ if (runs.length < 2) {
181
292
  return undefined;
293
+ }
182
294
  runs.sort((a, b) => a.createdAt - b.createdAt);
183
295
  const previous = runs[runs.length - 2];
184
296
  const current = runs[runs.length - 1];
185
- if (previous === undefined || current === undefined)
297
+ if (previous === undefined || current === undefined) {
186
298
  return undefined;
299
+ }
187
300
  return [previous, current];
188
301
  }
189
302
  }
@@ -205,11 +318,13 @@ export function noteLanding(dir, land) {
205
318
  }
206
319
  /** Wait for this run's screenshots still landing, so a run written now can list them. Bounded. */
207
320
  export async function shotsLanded(root, runId) {
208
- if (!isValidRunId(runId))
321
+ if (!isValidRunId(runId)) {
209
322
  return;
323
+ }
210
324
  const pending = landing.get(stepShotDir(root, runId));
211
- if (pending === undefined || 0 === pending.size)
325
+ if (pending === undefined || 0 === pending.size) {
212
326
  return;
327
+ }
213
328
  let timer;
214
329
  await Promise.race([
215
330
  Promise.allSettled([...pending]),
@@ -217,8 +332,9 @@ export async function shotsLanded(root, runId) {
217
332
  timer = setTimeout(resolve, LANDING_WAIT_MS);
218
333
  }),
219
334
  ]);
220
- if (timer !== undefined)
335
+ if (timer !== undefined) {
221
336
  clearTimeout(timer);
337
+ }
222
338
  }
223
339
  /** One line of a run's record, read back; anything malformed is skipped. */
224
340
  function parseLine(line) {
@@ -232,8 +348,9 @@ function parseLine(line) {
232
348
  }
233
349
  /** Every screenshot a run has landed, in the order they were taken (by seq). Never throws. */
234
350
  export async function readStepShots(fs, root, runId) {
235
- if (!isValidRunId(runId))
351
+ if (!isValidRunId(runId)) {
236
352
  return [];
353
+ }
237
354
  try {
238
355
  const text = await fs.readFile(join(stepShotDir(root, runId), STEP_SCREENSHOT.MANIFEST_FILE));
239
356
  return (text
@@ -256,9 +373,11 @@ function stepShotOf(shot) {
256
373
  /** An id that occurs once in the list; a repeated one (a reload restarts the count) pairs nothing. */
257
374
  function uniqueIds(ids) {
258
375
  const seen = new Map();
259
- for (const id of ids)
260
- if (id !== undefined)
376
+ for (const id of ids) {
377
+ if (id !== undefined) {
261
378
  seen.set(id, (seen.get(id) ?? 0) + 1);
379
+ }
380
+ }
262
381
  return new Set([...seen].filter(([, n]) => 1 === n).map(([id]) => id));
263
382
  }
264
383
  /**
@@ -268,8 +387,9 @@ function uniqueIds(ids) {
268
387
  */
269
388
  function pairByAction(run, shots) {
270
389
  const verdictShots = shots.filter((shot) => true === shot.verdict && shot.actionId !== undefined);
271
- if (0 === verdictShots.length || run.checks.every((check) => check.actionId === undefined))
390
+ if (0 === verdictShots.length || run.checks.every((check) => check.actionId === undefined)) {
272
391
  return undefined;
392
+ }
273
393
  const okChecks = uniqueIds(run.checks.map((check) => check.actionId));
274
394
  const okShots = uniqueIds(verdictShots.map((shot) => shot.actionId));
275
395
  const shotOf = new Map(verdictShots.flatMap((shot) => shot.actionId !== undefined && okShots.has(shot.actionId) && okChecks.has(shot.actionId)
@@ -278,10 +398,12 @@ function pairByAction(run, shots) {
278
398
  const checkIdOf = new Map();
279
399
  const checks = run.checks.map((check) => {
280
400
  const shot = check.actionId === undefined ? undefined : shotOf.get(check.actionId);
281
- if (shot === undefined)
401
+ if (shot === undefined) {
282
402
  return check;
283
- if (check.checkId !== undefined)
403
+ }
404
+ if (check.checkId !== undefined) {
284
405
  checkIdOf.set(shot, check.checkId);
406
+ }
285
407
  return { ...check, screenshot: stepShotOf(shot) };
286
408
  });
287
409
  return {
@@ -300,13 +422,15 @@ function pairByAction(run, shots) {
300
422
  */
301
423
  function pairWithChecks(run, shots) {
302
424
  const byAction = pairByAction(run, shots);
303
- if (byAction !== undefined)
425
+ if (byAction !== undefined) {
304
426
  return byAction;
427
+ }
305
428
  const verdictShots = shots.filter((shot) => true === shot.verdict);
306
429
  if (0 === verdictShots.length ||
307
430
  verdictShots.length !== run.checks.length ||
308
- run.checks.some((check) => check.checkId === undefined))
431
+ run.checks.some((check) => check.checkId === undefined)) {
309
432
  return { checks: run.checks, shots: [...shots] };
433
+ }
310
434
  const checkIdOf = new Map(verdictShots.map((shot, i) => [shot, run.checks[i]?.checkId]));
311
435
  return {
312
436
  checks: run.checks.map((check, i) => {
@@ -325,8 +449,9 @@ function pairWithChecks(run, shots) {
325
449
  * back unchanged.
326
450
  */
327
451
  export function withScreenshots(run, taken) {
328
- if (0 === taken.length)
452
+ if (0 === taken.length) {
329
453
  return run;
454
+ }
330
455
  const { checks, shots } = pairWithChecks(run, taken);
331
456
  const byStep = new Map(shots.flatMap((shot) => (shot.step === undefined ? [] : [[shot.step, shot]])));
332
457
  const flows = run.flows.map((flow) => flow.stepResults === undefined
@@ -1,11 +1,13 @@
1
1
  import { type RunId } from '@reticlehq/core';
2
2
  /**
3
- * The default run-id generator — a branded uuid.
3
+ * The default run-id generator — 16 random hex characters.
4
4
  *
5
5
  * A leaf on purpose: `verification-sync.ts` wants this one function, and reaching it through the
6
6
  * flow-replay stack would be a cycle.
7
7
  */
8
8
  export declare function defaultRunId(): RunId;
9
+ /** A short id that is always the same for `key`, and always a safe path segment. */
10
+ export declare function stableRunId(key: string): string;
9
11
  export declare function withShotRun<T>(runId: string, fn: () => Promise<T>): Promise<T>;
10
12
  /** The run being replayed now, or undefined outside a verify. */
11
13
  export declare function currentShotRun(): string | undefined;
@@ -1,14 +1,26 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { randomUUID } from 'node:crypto';
2
+ import { createHash, randomBytes } from 'node:crypto';
3
3
  import { asRunId } from '@reticlehq/core';
4
4
  /**
5
- * The default run-id generator — a branded uuid.
5
+ * How many hex characters a new run id has: 64 bits.
6
+ *
7
+ * Each step screenshot path that an agent reads contains the run id, so a 36-character uuid cost
8
+ * tokens on every action. 64 bits keeps a collision in one organisation's runs improbable. Old
9
+ * uuid ids stay valid: a run id is any safe path segment, and nothing reads its shape.
10
+ */
11
+ const RUN_ID_HEX = 16;
12
+ /**
13
+ * The default run-id generator — 16 random hex characters.
6
14
  *
7
15
  * A leaf on purpose: `verification-sync.ts` wants this one function, and reaching it through the
8
16
  * flow-replay stack would be a cycle.
9
17
  */
10
18
  export function defaultRunId() {
11
- return asRunId(randomUUID());
19
+ return asRunId(randomBytes(RUN_ID_HEX / 2).toString('hex'));
20
+ }
21
+ /** A short id that is always the same for `key`, and always a safe path segment. */
22
+ export function stableRunId(key) {
23
+ return createHash('sha256').update(key).digest('hex').slice(0, RUN_ID_HEX);
12
24
  }
13
25
  /**
14
26
  * The run a replay's step screenshots belong to, carried across every await under it.
@@ -66,9 +66,9 @@ export declare function checkWords(verdict: {
66
66
  * reload, each a superset of the last, and the dashboard would fill with overlapping copies of one
67
67
  * drive. Derived from the session instead, so the fold is idempotent.
68
68
  *
69
- * A session id is a free string on the wire, so the derived id is CHECKED before it becomes a path
70
- * segment; anything that would not be a safe one falls back to a random id, which loses idempotence
71
- * for that session rather than refusing to record it.
69
+ * A hash of the session id, not the id itself. A session id is a free string on the wire, and a
70
+ * uuid one put 36 characters into every step screenshot path. The hash is short, stable and always
71
+ * a safe path segment. A run that an older daemon wrote keeps its long id and stays readable.
72
72
  */
73
73
  export declare function driveRunId(sessionId: string): string;
74
74
  /** The run the agent's session now open in this tab is kept under. */
@@ -25,7 +25,7 @@
25
25
  import { supersededChecks } from '@reticlehq/engine/evidence/superseded-checks.js';
26
26
  import { isValidRunId } from '../../memory/project/dir/reticle-dir.js';
27
27
  import { defaultRunId } from './runner-port.js';
28
- import { currentShotRun } from './default-run-id.js';
28
+ import { currentShotRun, stableRunId } from './default-run-id.js';
29
29
  import { currentDrivenBy } from '../../hooks/driven-by.js';
30
30
  import { JournalVerdictEffectSchema, RunAgentKind, asRecord, asString, RunFramework, RunProfile, RunTrigger, PredicateKind, Verified, VerifiedReason, driveFlowStatus, } from '@reticlehq/core';
31
31
  import { withCorrections } from './late-answer.js';
@@ -79,13 +79,12 @@ const DRIVE_RUN_PREFIX = 'drive-';
79
79
  * reload, each a superset of the last, and the dashboard would fill with overlapping copies of one
80
80
  * drive. Derived from the session instead, so the fold is idempotent.
81
81
  *
82
- * A session id is a free string on the wire, so the derived id is CHECKED before it becomes a path
83
- * segment; anything that would not be a safe one falls back to a random id, which loses idempotence
84
- * for that session rather than refusing to record it.
82
+ * A hash of the session id, not the id itself. A session id is a free string on the wire, and a
83
+ * uuid one put 36 characters into every step screenshot path. The hash is short, stable and always
84
+ * a safe path segment. A run that an older daemon wrote keeps its long id and stays readable.
85
85
  */
86
86
  export function driveRunId(sessionId) {
87
- const candidate = `${DRIVE_RUN_PREFIX}${sessionId}`;
88
- return isValidRunId(candidate) ? candidate : defaultRunId();
87
+ return `${DRIVE_RUN_PREFIX}${stableRunId(sessionId)}`;
89
88
  }
90
89
  /** The run of the `segment`th agent session in a tab: the tab's id first, then `-2`, `-3`… */
91
90
  function segmentRunId(base, segment) {
@@ -179,12 +178,17 @@ export function driveRunFrom(actions, deps) {
179
178
  const intentOf = new Map(actions.map((a) => [a.actionId, asString(asRecord(a.args)['intent'])]));
180
179
  const checks = [];
181
180
  for (const verdict of found) {
182
- const intent = intentOf.get(verdict.actionId);
181
+ // The agent's own words on the call win; else the sentence the verdict recorded.
182
+ const given = intentOf.get(verdict.actionId);
183
+ const own = given !== undefined && 0 < given.length;
184
+ const intent = own ? given : verdict.intent;
183
185
  checks.push({
184
186
  predicate: verdict.claim,
185
187
  status: verdict.verified,
186
188
  actionId: verdict.actionId,
187
189
  ...(intent === undefined || 0 === intent.length ? {} : { intent }),
190
+ ...(!own && true === verdict.intentDerived ? { intentDerived: true } : {}),
191
+ ...(verdict.failedPart === undefined ? {} : { failedPart: verdict.failedPart }),
188
192
  // Where it was written, and on a miss the calls of its window: what an issue page shows.
189
193
  ...(verdict.source === undefined && verdict.net === undefined
190
194
  ? {}
@@ -0,0 +1,21 @@
1
+ import { Verified, type JournalAction, type RunReport } from '@reticlehq/core';
2
+ export declare class RunLedger {
3
+ #private;
4
+ /** An agent call starts. The first one starts the run, and a call from another agent starts a new one. */
5
+ begin(now: number, owner: string): void;
6
+ /** An agent call ended. The first one that left a verdict sets the time to the first verdict. */
7
+ after(now: number): void;
8
+ /** A journal record from the agent's own call. A record with no verdict is not a claim. */
9
+ verdict(action: JournalAction): void;
10
+ flowSaved(name: string): void;
11
+ /** The last replay of a flow in this run is its verdict. */
12
+ replayed(name: string, verified: Verified): void;
13
+ memoryWritten(count?: number): void;
14
+ /** Notes given to the agent. Each one counts once, however often it is shown. */
15
+ memoryRead(notes: readonly string[]): void;
16
+ isEmpty(): boolean;
17
+ /** The report, without the cloud line (the caller knows the project). Empties the ledger. */
18
+ take(now: number): RunReport;
19
+ }
20
+ /** The daemon's ledger. */
21
+ export declare const runLedger: RunLedger;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * The run ledger: what one agent run checked, saved and read, kept until its report is taken.
3
+ *
4
+ * A run is the agent's calls from its first Reticle call to the call that ends it (a session end, a
5
+ * yield, a released tab). The verdicts come from the journal records the agent's own calls wrote;
6
+ * the Harness's are never counted. Taking the report empties the ledger, so the next run starts at
7
+ * zero.
8
+ *
9
+ * A call from another agent (another MCP attach id) starts a new run. An agent that stops without a
10
+ * call that ends its run then does not leak its claims into the next agent's report.
11
+ *
12
+ * ponytail: one ledger for each daemon, not for each agent. Two agents that call at the same time
13
+ * restart each other's run. Key the ledger by attach id when that happens.
14
+ */
15
+ import { supersededChecks } from '@reticlehq/engine/evidence/superseded-checks.js';
16
+ import { JournalVerdictEffectSchema, ReticleTool, Verified, } from '@reticlehq/core';
17
+ const SAW = 'saw ';
18
+ const FLOW = 'flow ';
19
+ /** One piece of evidence for a claim: what the check saw, else the source line it drove. */
20
+ function evidenceOf(effect) {
21
+ if (effect.observed !== undefined)
22
+ return `${SAW}${effect.observed}`;
23
+ return effect.source;
24
+ }
25
+ /** `no` when anything failed, `yes` only when something held and nothing was undecided. */
26
+ function runVerified(all) {
27
+ if (all.includes(Verified.NO))
28
+ return Verified.NO;
29
+ if (0 === all.length || all.some((v) => Verified.YES !== v))
30
+ return Verified.UNKNOWN;
31
+ return Verified.YES;
32
+ }
33
+ export class RunLedger {
34
+ #owner;
35
+ #startedAt;
36
+ #firstVerdictAt;
37
+ #verdicts = [];
38
+ #saved = new Set();
39
+ #replayed = new Map();
40
+ #written = 0;
41
+ #read = new Set();
42
+ /** An agent call starts. The first one starts the run, and a call from another agent starts a new one. */
43
+ begin(now, owner) {
44
+ if (this.#owner !== owner)
45
+ this.#reset();
46
+ this.#owner = owner;
47
+ this.#startedAt ??= now;
48
+ }
49
+ /** An agent call ended. The first one that left a verdict sets the time to the first verdict. */
50
+ after(now) {
51
+ if (0 < this.#verdicts.length || 0 < this.#replayed.size)
52
+ this.#firstVerdictAt ??= now;
53
+ }
54
+ /** A journal record from the agent's own call. A record with no verdict is not a claim. */
55
+ verdict(action) {
56
+ if (this.#idle() || action.drivenBy !== undefined)
57
+ return;
58
+ // A replay is counted once, as a flow, decided as its run decides it (`replayed`). Its journal
59
+ // record said `unknown` where the run said `no`, and one report gave both answers.
60
+ if (ReticleTool.FLOW_REPLAY === action.tool)
61
+ return;
62
+ const parsed = JournalVerdictEffectSchema.safeParse(action.effect);
63
+ if (parsed.success)
64
+ this.#verdicts.push(parsed.data);
65
+ }
66
+ flowSaved(name) {
67
+ if (!this.#idle())
68
+ this.#saved.add(name);
69
+ }
70
+ /** The last replay of a flow in this run is its verdict. */
71
+ replayed(name, verified) {
72
+ if (!this.#idle())
73
+ this.#replayed.set(name, verified);
74
+ }
75
+ memoryWritten(count = 1) {
76
+ if (!this.#idle())
77
+ this.#written += count;
78
+ }
79
+ /** Notes given to the agent. Each one counts once, however often it is shown. */
80
+ memoryRead(notes) {
81
+ if (this.#idle())
82
+ return;
83
+ for (const note of notes)
84
+ this.#read.add(note);
85
+ }
86
+ isEmpty() {
87
+ return this.#idle();
88
+ }
89
+ /**
90
+ * No agent run is open. A CLI `reticle verify` replays through the same code, and what it did is
91
+ * not the next agent's run, so nothing is kept until an agent call begins one.
92
+ */
93
+ #idle() {
94
+ return this.#startedAt === undefined;
95
+ }
96
+ /** The report, without the cloud line (the caller knows the project). Empties the ledger. */
97
+ take(now) {
98
+ const started = this.#startedAt ?? now;
99
+ // A passive check that read too early is not counted: the rule every fold applies.
100
+ const superseded = supersededChecks(this.#verdicts.map((v) => ({
101
+ key: v.claim,
102
+ passive: false === v.declaredBeforeActing,
103
+ held: Verified.YES === v.verified,
104
+ failed: Verified.NO === v.verified,
105
+ })));
106
+ const counted = this.#verdicts.filter((_, at) => !superseded.has(at));
107
+ const claims = counted.map((v) => {
108
+ const evidence = evidenceOf(v);
109
+ return evidence === undefined
110
+ ? { claim: v.claim, verified: v.verified }
111
+ : { claim: v.claim, verified: v.verified, evidence };
112
+ });
113
+ const replayed = [...this.#replayed].map(([name, verified]) => ({ name, verified }));
114
+ const report = {
115
+ verified: runVerified([...claims.map((c) => c.verified), ...replayed.map((r) => r.verified)]),
116
+ claims,
117
+ caught: [
118
+ ...claims.filter((c) => Verified.NO === c.verified).map((c) => c.claim),
119
+ ...replayed.filter((r) => Verified.NO === r.verified).map((r) => `${FLOW}${r.name}`),
120
+ ],
121
+ flows: { saved: [...this.#saved], replayed },
122
+ memory: { written: this.#written, read: this.#read.size },
123
+ wallMs: Math.max(0, now - started),
124
+ ...(this.#firstVerdictAt === undefined
125
+ ? {}
126
+ : { firstVerdictMs: Math.max(0, this.#firstVerdictAt - started) }),
127
+ };
128
+ this.#reset();
129
+ return report;
130
+ }
131
+ #reset() {
132
+ this.#owner = undefined;
133
+ this.#startedAt = undefined;
134
+ this.#firstVerdictAt = undefined;
135
+ this.#verdicts = [];
136
+ this.#saved = new Set();
137
+ this.#replayed = new Map();
138
+ this.#written = 0;
139
+ this.#read = new Set();
140
+ }
141
+ }
142
+ /** The daemon's ledger. */
143
+ export const runLedger = new RunLedger();
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The live adapter: build a RunnerPort from the real ToolDeps so ReticleRunner drives actual flow
3
- * replays against the connected app. Thin glue — it wires deps.flows.list, replayNamedFlow, deps.now,
3
+ * replays against the connected app. Thin glue — it wires the session's flow list, replayNamedFlow, deps.now,
4
4
  * and a uuid generator. The ReticleRunner core (tested with a fake port) holds all the orchestration and
5
5
  * verdict logic, so this layer carries no decisions.
6
6
  */
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * The live adapter: build a RunnerPort from the real ToolDeps so ReticleRunner drives actual flow
3
- * replays against the connected app. Thin glue — it wires deps.flows.list, replayNamedFlow, deps.now,
3
+ * replays against the connected app. Thin glue — it wires the session's flow list, replayNamedFlow, deps.now,
4
4
  * and a uuid generator. The ReticleRunner core (tested with a fake port) holds all the orchestration and
5
5
  * verdict logic, so this layer carries no decisions.
6
6
  */
7
7
  import { replayAndLearn } from '../../language/flows/flow-learning.js';
8
+ import { flowsForSession } from '../../language/flows/flow-store-for-session.js';
9
+ import { safeSessionTarget } from '../../memory/project/session-root.js';
8
10
  import { defaultRunId } from './default-run-id.js';
9
11
  export { defaultRunId } from './default-run-id.js';
10
12
  /** Wire a RunnerPort to the live session. Pass sessionId to disambiguate when several tabs are open. */
@@ -12,7 +14,11 @@ export function createRunnerPort(deps, sessionId,
12
14
  /** `reticle verify --confirm-dangerous`: this run acknowledges the steps held as destructive. */
13
15
  opts = {}) {
14
16
  return {
15
- listFlows: () => deps.flows.list(),
17
+ // Resolved as replay resolves it, so every listed name is one replay can load.
18
+ listFlows: () => {
19
+ const target = safeSessionTarget(deps, sessionId);
20
+ return flowsForSession(deps, target).flows.list(target.projectId);
21
+ },
16
22
  replayFlow: (name) => replayAndLearn(deps, {
17
23
  flowName: name,
18
24
  ...(sessionId === undefined ? {} : { sessionId }),