@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
@@ -45,7 +45,7 @@ export interface PlatformModelConfig {
45
45
  */
46
46
  providerReady: boolean;
47
47
  /**
48
- * Harness credits used and held this 30 days, and when the grant ends (`endsAt`, epoch ms) when
48
+ * Credits used and held this 30 days, and when the grant ends (`endsAt`, epoch ms) when
49
49
  * the platform says. Absent when the plan is unbounded or the API is older.
50
50
  */
51
51
  credits?: Credits & {
@@ -59,8 +59,6 @@ export interface PlatformModelConfig {
59
59
  * the API's origin 404s. Absent from an older platform.
60
60
  */
61
61
  planUrl?: string;
62
- /** The platform's coverage gate (`harnessUnlocked`, `coverageScore`, `harnessLock`), when it sent one. */
63
- gate?: PlatformGate;
64
62
  /** The plan in force (`plan`), for the HUD's account menu. */
65
63
  plan?: PlatformPlan;
66
64
  /** Harness runs the platform holds for this project (`harnessRuns.total`). */
@@ -74,13 +72,6 @@ export interface PlatformPlan {
74
72
  daysLeft?: number;
75
73
  seats?: number;
76
74
  }
77
- /** The platform's Harness coverage gate, as the HUD is pushed it. */
78
- export interface PlatformGate {
79
- unlocked: boolean;
80
- percent?: number;
81
- reason?: string;
82
- prompt?: string;
83
- }
84
75
  /** A GET, narrowed to what this file uses, so a test can answer it without a network. */
85
76
  export type ConfigFetch = (url: string, init: {
86
77
  method: string;
@@ -66,24 +66,6 @@ function webUrl(value, key) {
66
66
  return {};
67
67
  }
68
68
  }
69
- /** The gate out of `/v1/model/config`, or undefined from a platform that does not send one. */
70
- function gateOf(record) {
71
- const unlocked = record['harnessUnlocked'];
72
- if ('boolean' !== typeof unlocked)
73
- return undefined;
74
- const score = record['coverageScore'];
75
- const lock = record['harnessLock'];
76
- const lockRecord = 'object' === typeof lock && null !== lock ? lock : {};
77
- const reason = lockRecord['reason'];
78
- const prompt = lockRecord['prompt'];
79
- return {
80
- unlocked,
81
- // Rounded down, as core's rule is: a locked app never shows 80%.
82
- ...('number' === typeof score ? { percent: Math.floor(score * 100 + 1e-9) } : {}),
83
- ...('string' === typeof reason ? { reason } : {}),
84
- ...('string' === typeof prompt ? { prompt } : {}),
85
- };
86
- }
87
69
  /** When the grant ends, epoch ms, from an ISO date or a number. Anything else: not said. */
88
70
  function endsAtOf(value) {
89
71
  const at = 'number' === typeof value ? value : 'string' === typeof value ? Date.parse(value) : NaN;
@@ -121,7 +103,6 @@ function parse(body) {
121
103
  const kind = 'object' === typeof credits && null !== credits
122
104
  ? Object.values(CreditKind).find((k) => k === credits['kind'])
123
105
  : undefined;
124
- const gate = gateOf(record);
125
106
  const endsAt = endsAtOf('object' === typeof credits && null !== credits
126
107
  ? credits['endsAt']
127
108
  : undefined);
@@ -130,7 +111,6 @@ function parse(body) {
130
111
  harnessEnabled: true === enabled,
131
112
  harnessEntitled: 'boolean' === typeof entitled ? entitled : true,
132
113
  providerReady: 'boolean' === typeof ready ? ready : true,
133
- ...(gate === undefined ? {} : { gate }),
134
114
  ...hudFieldsOf(record),
135
115
  ...webUrl(record['planUrl'], 'planUrl'),
136
116
  ...('number' === typeof used && 'number' === typeof limit
@@ -37,20 +37,8 @@ declare const LicensePayloadSchema: z.ZodObject<{
37
37
  org: z.ZodString;
38
38
  plan: z.ZodString;
39
39
  exp: z.ZodNumber;
40
- features: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
41
- }, "strip", z.ZodTypeAny, {
42
- plan: string;
43
- org: string;
44
- lid: string;
45
- exp: number;
46
- features?: string[] | undefined;
47
- }, {
48
- plan: string;
49
- org: string;
50
- lid: string;
51
- exp: number;
52
- features?: string[] | undefined;
53
- }>;
40
+ features: z.ZodOptional<z.ZodArray<z.ZodString>>;
41
+ }, z.core.$strip>;
54
42
  export type LicensePayload = z.infer<typeof LicensePayloadSchema>;
55
43
  type LicenseCheck = {
56
44
  status: typeof LicenseStatus.VALID;
@@ -4,10 +4,15 @@ export interface ShotOptions {
4
4
  step?: string;
5
5
  verdict?: boolean;
6
6
  }
7
- /** What a tool result carries: where the picture is and how it was taken, or why there is none. */
7
+ /**
8
+ * What a tool result carries: where the picture is and how it was taken, or why there is none.
9
+ *
10
+ * `pending: true` means the path is reserved and the capture has started, but the file may not yet be on disk. This happens on the fast path when a prior capture on the same tab proved the source works: the step does not wait for the write to land. Copy the file only after a short delay, or poll until it appears.
11
+ */
8
12
  export type ScreenshotField = {
9
13
  path: string;
10
14
  source: ScreenshotSource;
15
+ pending?: true;
11
16
  } | {
12
17
  error: string;
13
18
  };
@@ -29,3 +34,30 @@ export declare function jpegSize(bytes: Uint8Array): {
29
34
  export declare function takeStepShot(deps: ToolDeps, sessionId: string, tool: string, opts?: ShotOptions): Promise<ScreenshotField>;
30
35
  /** The replay hook that gives every reported flow step its screenshot, filed as `<flow>#<step>`. */
31
36
  export declare function replayStepShooter(deps: ToolDeps, sessionId: string): (result: FlowStepResult, flow: string) => Promise<void>;
37
+ /**
38
+ * Frames: the pictures between the steps.
39
+ *
40
+ * A run had one picture per step, so the cloud replay jumped from step to step and showed nothing of
41
+ * what happened between them. A tab that Reticle drives (a leased tab, or the page `reticle drive`
42
+ * opened) is filmed about once a second into the run of its last step. The frames go in the same
43
+ * directory and record as the step shots, with the tool `frame`, so the existing upload sends them
44
+ * and the replay plays them in `seq` order.
45
+ *
46
+ * Bounded twice. A page that did not change is not filmed again. A run keeps at most
47
+ * `FRAME.MAX_PER_RUN` frames, and the gap between frames doubles each quarter of that budget, so a
48
+ * long run is thinned, not cut off at its start. The step shots keep the rest of the per-run limit.
49
+ *
50
+ * ponytail: a desktop shell is not filmed (its capture is a PNG, see the header), and an undriven
51
+ * tab is not filmed (only the page could draw itself, once a second, in the user's own tab).
52
+ */
53
+ export declare const FRAME: {
54
+ readonly TOOL: "frame";
55
+ readonly EVERY_MS: 1000;
56
+ readonly MAX_PER_RUN: 100;
57
+ /** CDP quality for a frame: lower than a step shot, as for the chat's live view. */
58
+ readonly JPEG_QUALITY: 50;
59
+ };
60
+ /** Stop filming a tab. Safe to call for a tab that is not filmed. */
61
+ export declare function stopFilming(sessionId: string): void;
62
+ /** One tick of a tab's film: one frame, when the budget, the gap and the page allow. Never throws. */
63
+ export declare function filmNow(sessionId: string): Promise<void>;
@@ -171,6 +171,7 @@ async function shoot(deps, session, tool, { step, verdict }) {
171
171
  if (!isValidRunId(runId))
172
172
  return { error: `no screenshot: unusable run id ${runId}` };
173
173
  const dir = stepShotDir(root, runId);
174
+ void filmTab(deps, session, dir);
174
175
  const seq = await allocate(deps.fs, dir);
175
176
  if (seq > STEP_SCREENSHOT.MAX_PER_RUN) {
176
177
  return {
@@ -215,7 +216,7 @@ async function shoot(deps, session, tool, { step, verdict }) {
215
216
  });
216
217
  noteLanding(dir, land);
217
218
  if (predicted !== undefined)
218
- return { path, source: predicted };
219
+ return { path, source: predicted, pending: true };
219
220
  // Nothing worked last time: wait, and tell the truth either way.
220
221
  const pixels = await taken;
221
222
  await land;
@@ -229,3 +230,156 @@ export function replayStepShooter(deps, sessionId) {
229
230
  });
230
231
  };
231
232
  }
233
+ /**
234
+ * Frames: the pictures between the steps.
235
+ *
236
+ * A run had one picture per step, so the cloud replay jumped from step to step and showed nothing of
237
+ * what happened between them. A tab that Reticle drives (a leased tab, or the page `reticle drive`
238
+ * opened) is filmed about once a second into the run of its last step. The frames go in the same
239
+ * directory and record as the step shots, with the tool `frame`, so the existing upload sends them
240
+ * and the replay plays them in `seq` order.
241
+ *
242
+ * Bounded twice. A page that did not change is not filmed again. A run keeps at most
243
+ * `FRAME.MAX_PER_RUN` frames, and the gap between frames doubles each quarter of that budget, so a
244
+ * long run is thinned, not cut off at its start. The step shots keep the rest of the per-run limit.
245
+ *
246
+ * ponytail: a desktop shell is not filmed (its capture is a PNG, see the header), and an undriven
247
+ * tab is not filmed (only the page could draw itself, once a second, in the user's own tab).
248
+ */
249
+ export const FRAME = {
250
+ TOOL: STEP_SCREENSHOT.FRAME_TOOL,
251
+ EVERY_MS: 1_000,
252
+ MAX_PER_RUN: 100,
253
+ /** CDP quality for a frame: lower than a step shot, as for the chat's live view. */
254
+ JPEG_QUALITY: 50,
255
+ };
256
+ /** The quarters the budget is split into: the gap between frames doubles at each. */
257
+ const FRAME_STAGES = 4;
258
+ /**
259
+ * The frames a new one is compared with. A page that flips between a few looks (a blinking caret,
260
+ * a spinner) is unchanged, not a new frame every tick.
261
+ */
262
+ const RECENT_FRAMES = 4;
263
+ /** The longest wait, in ticks, between captures of a page that keeps looking the same. */
264
+ const MAX_STILL_TICKS = 32;
265
+ const films = new Map();
266
+ /** Frames kept per run directory. */
267
+ const framesIn = new Map();
268
+ /** Is this a tab Reticle drives, with a real browser behind it? */
269
+ async function driven(deps, session) {
270
+ if (true === deps.pool?.leasedSessionIds().includes(session.id))
271
+ return true;
272
+ return (deps.realInput?.screenshot !== undefined &&
273
+ true === (await deps.realInput.isAvailableFor(session.url)));
274
+ }
275
+ /** Start filming a driven tab, or point its film at the run its newest step went to. */
276
+ async function filmTab(deps, session, dir) {
277
+ const film = films.get(session.id);
278
+ if (film !== undefined) {
279
+ film.dir = dir;
280
+ // A step usually changes the page: look again at the next tick.
281
+ film.still = 1;
282
+ return;
283
+ }
284
+ if (!(await driven(deps, session).catch(() => false)))
285
+ return;
286
+ if (films.has(session.id))
287
+ return;
288
+ const timer = setInterval(() => {
289
+ void filmNow(session.id);
290
+ }, FRAME.EVERY_MS);
291
+ // A film never holds a process open.
292
+ timer.unref?.();
293
+ films.set(session.id, { deps, dir, timer, busy: undefined, recent: [], idle: 0, still: 1 });
294
+ }
295
+ /** Stop filming a tab. Safe to call for a tab that is not filmed. */
296
+ export function stopFilming(sessionId) {
297
+ const film = films.get(sessionId);
298
+ if (film === undefined)
299
+ return;
300
+ clearInterval(film.timer);
301
+ films.delete(sessionId);
302
+ }
303
+ /** One tick of a tab's film: one frame, when the budget, the gap and the page allow. Never throws. */
304
+ export async function filmNow(sessionId) {
305
+ const film = films.get(sessionId);
306
+ if (film === undefined || film.busy !== undefined)
307
+ return;
308
+ film.busy = frame(sessionId, film).finally(() => {
309
+ film.busy = undefined;
310
+ });
311
+ await film.busy;
312
+ }
313
+ async function frame(sessionId, film) {
314
+ let session;
315
+ try {
316
+ session = film.deps.sessions.resolve(sessionId);
317
+ // An ended tab has nothing more to show.
318
+ if (session.isEnded())
319
+ session = undefined;
320
+ }
321
+ catch {
322
+ session = undefined;
323
+ }
324
+ if (session === undefined) {
325
+ stopFilming(sessionId);
326
+ return;
327
+ }
328
+ const dir = film.dir;
329
+ const kept = framesIn.get(dir) ?? 0;
330
+ if (kept >= FRAME.MAX_PER_RUN)
331
+ return;
332
+ film.idle += 1;
333
+ const gap = 2 ** Math.floor(kept / (FRAME.MAX_PER_RUN / FRAME_STAGES));
334
+ if (film.idle < Math.max(gap, film.still))
335
+ return;
336
+ film.idle = 0;
337
+ try {
338
+ const bytes = await framePixels(film.deps, session);
339
+ const size = bytes === undefined ? undefined : jpegSize(bytes);
340
+ if (bytes === undefined || size === undefined)
341
+ return;
342
+ const sha256 = createHash('sha256').update(bytes).digest('hex');
343
+ if (film.recent.includes(sha256)) {
344
+ film.still = Math.min(film.still * 2, MAX_STILL_TICKS);
345
+ return;
346
+ }
347
+ film.recent = [...film.recent, sha256].slice(-RECENT_FRAMES);
348
+ film.still = 1;
349
+ const seq = await allocate(film.deps.fs, dir);
350
+ // The step shots' own limit is the platform's: a frame never takes the last of it.
351
+ if (seq > STEP_SCREENSHOT.MAX_PER_RUN)
352
+ return;
353
+ framesIn.set(dir, kept + 1);
354
+ const file = `${String(seq).padStart(SEQ_WIDTH, '0')}-${FRAME.TOOL}${JPEG_EXT}`;
355
+ const record = {
356
+ seq,
357
+ file,
358
+ tool: FRAME.TOOL,
359
+ source: ScreenshotSource.BROWSER,
360
+ ...size,
361
+ sha256,
362
+ };
363
+ const fs = film.deps.fs;
364
+ const land = (async () => {
365
+ await fs.mkdir(dir);
366
+ await fs.writeFileBytes(join(dir, file), bytes);
367
+ await fs.appendFile(join(dir, STEP_SCREENSHOT.MANIFEST_FILE), `${JSON.stringify(record)}\n`);
368
+ })().catch(() => undefined);
369
+ noteLanding(dir, land);
370
+ await land;
371
+ }
372
+ catch {
373
+ // A frame is a courtesy: the next tick tries again.
374
+ }
375
+ }
376
+ /** The real pixels of a driven tab, as a frame. */
377
+ async function framePixels(deps, session) {
378
+ const opts = { jpegQuality: FRAME.JPEG_QUALITY, cssScale: true };
379
+ const leased = await deps.pool?.screenshotLease(session.id, opts);
380
+ if (leased !== undefined)
381
+ return leased;
382
+ if (true !== (await deps.realInput?.isAvailableFor(session.url)))
383
+ return undefined;
384
+ return deps.realInput?.screenshot?.(session.url, opts);
385
+ }
@@ -205,8 +205,8 @@ function runtimeOf(deps, sessionId) {
205
205
  * to one app and the screenshot aimed at a different (desktop) session, CDP fails and the shell
206
206
  * capture is still correct.
207
207
  *
208
- * `clip`/`ref` are honoured only on the CDP path — the shell photographs the whole window. Scoping is
209
- * left to the caller rather than cropped here, so a clip never silently becomes a full-window image.
208
+ * CDP and leased pages honor `clip`/`ref`. The desktop shell photographs the whole window,
209
+ * so scoped desktop captures are refused instead of saved or compared as full-window images.
210
210
  *
211
211
  * `fullPage` is different, because it cannot be emulated by cropping: only WebKitGTK (Tauri on Linux)
212
212
  * can render a full document offscreen. Where the shell cannot, it REFUSES and this reports
@@ -238,8 +238,14 @@ async function capture(deps, sessionId, args) {
238
238
  // The window's own backing store, via the Electron/Tauri adapter — the only route whose pixels
239
239
  // really are the desktop app.
240
240
  const desktop = await desktopCapture(deps, sessionId, true === args['fullPage']);
241
- if (desktop.png !== undefined)
241
+ if (desktop.png !== undefined) {
242
+ // Check the route that supplied the pixels, not the session runtime: a desktop session can
243
+ // use CDP, and a page without desktop capture can still fall back to a leased browser.
244
+ if (args['clip'] !== undefined || args['ref'] !== undefined) {
245
+ return { reason: VisualReason.CROP_UNSUPPORTED };
246
+ }
242
247
  return { png: desktop.png, runtime: runtimeOf(deps, sessionId) };
248
+ }
243
249
  if (desktop.reason !== undefined)
244
250
  return desktop;
245
251
  /*
@@ -251,7 +257,9 @@ async function capture(deps, sessionId, args) {
251
257
  */
252
258
  const leased = sessionId === undefined
253
259
  ? undefined
254
- : await deps.pool?.screenshotLease(sessionId, { fullPage: true === args['fullPage'] });
260
+ : // The same scope as the provider route: `clip` and `ref` were dropped here, so a scoped
261
+ // shot of a lease saved the whole viewport and answered `saved: true`.
262
+ await deps.pool?.screenshotLease(sessionId, await buildOpts(deps, sessionId, args));
255
263
  // A leased page is a real browser page, whatever the session is.
256
264
  if (leased !== undefined)
257
265
  return { png: leased, runtime: AppRuntime.WEB };
@@ -4,6 +4,12 @@ export declare function agentLabel(name: string): string;
4
4
  export declare function agentClientOf(name: string | undefined): AgentClient | undefined;
5
5
  /** An MCP connection finished its handshake as `name`. */
6
6
  export declare function noteAgentAttached(attachId: string, name: string): void;
7
+ /** Connection `attachId` announced the agent session `session`. */
8
+ export declare function noteAgentSession(attachId: string, session: string): void;
9
+ /** The agent session connection `attachId` announced, if any. */
10
+ export declare function agentSessionOf(attachId: string | undefined): string | undefined;
11
+ /** The name connection `attachId` gave in its handshake, while it is attached. */
12
+ export declare function agentNameOf(attachId: string | undefined): string | undefined;
7
13
  /** That connection closed. */
8
14
  export declare function noteAgentDetached(attachId: string): void;
9
15
  /** The friendly names of the agents attached now, each once. */
@@ -40,8 +40,9 @@ export function agentLabel(name) {
40
40
  }
41
41
  /** The closed telemetry value for a client name: never the name itself, which is the client's text. */
42
42
  export function agentClientOf(name) {
43
- if (name === undefined || 0 === name.trim().length)
43
+ if (name === undefined || 0 === name.trim().length) {
44
44
  return undefined;
45
+ }
45
46
  return knownAgent(name)?.[2] ?? AgentClient.OTHER;
46
47
  }
47
48
  /** An MCP connection finished its handshake as `name`. */
@@ -49,10 +50,29 @@ export function noteAgentAttached(attachId, name) {
49
50
  byAttach.set(attachId, name);
50
51
  changed();
51
52
  }
53
+ /**
54
+ * The agent's own session id per connection, as its MCP server announced it. Kept after the
55
+ * connection closes: a run written at a session's end still needs it.
56
+ * ponytail: never pruned; one short string per MCP connect for the daemon's lifetime.
57
+ */
58
+ const sessionByAttach = new Map();
59
+ /** Connection `attachId` announced the agent session `session`. */
60
+ export function noteAgentSession(attachId, session) {
61
+ sessionByAttach.set(attachId, session);
62
+ }
63
+ /** The agent session connection `attachId` announced, if any. */
64
+ export function agentSessionOf(attachId) {
65
+ return attachId === undefined ? undefined : sessionByAttach.get(attachId);
66
+ }
67
+ /** The name connection `attachId` gave in its handshake, while it is attached. */
68
+ export function agentNameOf(attachId) {
69
+ return attachId === undefined ? undefined : byAttach.get(attachId);
70
+ }
52
71
  /** That connection closed. */
53
72
  export function noteAgentDetached(attachId) {
54
- if (byAttach.delete(attachId))
73
+ if (byAttach.delete(attachId)) {
55
74
  changed();
75
+ }
56
76
  }
57
77
  /** The friendly names of the agents attached now, each once. */
58
78
  export function connectedAgents() {
@@ -95,8 +115,9 @@ export function callerClientName() {
95
115
  export function callingClientName() {
96
116
  const own = calling.getStore();
97
117
  const name = own === undefined ? undefined : byAttach.get(own);
98
- if (name !== undefined)
118
+ if (name !== undefined) {
99
119
  return name;
120
+ }
100
121
  const all = [...new Set(byAttach.values())];
101
122
  return 1 === all.length ? all[0] : undefined;
102
123
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Which episode a run belongs to, the commit it ran against, and the agent session behind it.
3
+ *
4
+ * The episode log notes each episode here as it writes; the run store reads it back to stamp a run
5
+ * with `episodeId`, `agentSession` and `project.commit`, so a run joins to the agent's trajectory
6
+ * exactly instead of by time and file. A leaf: it imports nothing, so both sides can reach it.
7
+ */
8
+ export interface EpisodeStamp {
9
+ episodeId: string;
10
+ /** The git HEAD at the episode's start, once git has answered. */
11
+ head?: string;
12
+ /**
13
+ * The coding agent's own session id, as its MCP server announced it (Claude Code's
14
+ * `CLAUDE_CODE_SESSION_ID`, which is the `session_id` its hooks receive). Names the
15
+ * `agent-<session>.jsonl` the agent hooks write.
16
+ */
17
+ agentSession?: string;
18
+ }
19
+ /** What one write to an episode says. Every field may be absent: a HEAD arrives later, alone. */
20
+ export interface EpisodeNote {
21
+ head?: string;
22
+ sessionId?: string;
23
+ agentSession?: string;
24
+ }
25
+ /** An episode wrote to `root`. */
26
+ export declare function noteEpisode(root: string, episodeId: string, note?: EpisodeNote): void;
27
+ /**
28
+ * The episode a run written to `root` belongs to: the calling connection's; else, outside a call,
29
+ * the one whose calls last drove the run's tab; else the project's only episode. Two episodes and
30
+ * nothing to tell them apart is undefined, never the newest one.
31
+ */
32
+ export declare function episodeStampFor(root: string, attachId?: string, sessionId?: string): EpisodeStamp | undefined;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Which episode a run belongs to, the commit it ran against, and the agent session behind it.
3
+ *
4
+ * The episode log notes each episode here as it writes; the run store reads it back to stamp a run
5
+ * with `episodeId`, `agentSession` and `project.commit`, so a run joins to the agent's trajectory
6
+ * exactly instead of by time and file. A leaf: it imports nothing, so both sides can reach it.
7
+ */
8
+ /** Per project root, each episode by id. */
9
+ const byRoot = new Map();
10
+ /** Orders calls across episodes, so "the last episode to drive a tab" is well defined. */
11
+ let tick = 0;
12
+ /** An episode wrote to `root`. */
13
+ export function noteEpisode(root, episodeId, note = {}) {
14
+ const episodes = byRoot.get(root) ?? new Map();
15
+ const known = episodes.get(episodeId) ?? { episodeId, tabs: new Map() };
16
+ if (note.head !== undefined) {
17
+ known.head = note.head;
18
+ }
19
+ if (note.agentSession !== undefined) {
20
+ known.agentSession = note.agentSession;
21
+ }
22
+ if (note.sessionId !== undefined) {
23
+ known.tabs.set(note.sessionId, (tick += 1));
24
+ }
25
+ episodes.set(episodeId, known);
26
+ byRoot.set(root, episodes);
27
+ }
28
+ const stampOf = ({ episodeId, head, agentSession }) => ({
29
+ episodeId,
30
+ ...(head === undefined ? {} : { head }),
31
+ ...(agentSession === undefined ? {} : { agentSession }),
32
+ });
33
+ /**
34
+ * The episode a run written to `root` belongs to: the calling connection's; else, outside a call,
35
+ * the one whose calls last drove the run's tab; else the project's only episode. Two episodes and
36
+ * nothing to tell them apart is undefined, never the newest one.
37
+ */
38
+ export function episodeStampFor(root, attachId, sessionId) {
39
+ const episodes = byRoot.get(root);
40
+ if (episodes === undefined) {
41
+ return undefined;
42
+ }
43
+ const own = attachId === undefined ? undefined : episodes.get(attachId);
44
+ if (own !== undefined) {
45
+ return stampOf(own);
46
+ }
47
+ if (sessionId !== undefined) {
48
+ let driver;
49
+ for (const episode of episodes.values()) {
50
+ const at = episode.tabs.get(sessionId);
51
+ if (at !== undefined && (driver === undefined || at > (driver.tabs.get(sessionId) ?? 0))) {
52
+ driver = episode;
53
+ }
54
+ }
55
+ if (driver !== undefined) {
56
+ return stampOf(driver);
57
+ }
58
+ }
59
+ const [only, ...more] = episodes.values();
60
+ return only !== undefined && 0 === more.length ? stampOf(only) : undefined;
61
+ }
@@ -49,12 +49,20 @@ const MAX_IN_FLIGHT = 8;
49
49
  let inFlight = 0;
50
50
  const reported = new Set();
51
51
  function reportOnce(key, message) {
52
- if (reported.has(key))
52
+ if (reported.has(key)) {
53
53
  return;
54
+ }
54
55
  reported.add(key);
55
56
  log(`hook: ${message}`);
56
57
  }
57
- /** Cached config plus the mtime it was read at, so an edit takes effect without a daemon restart. */
58
+ /**
59
+ * Cached config plus the file and mtime it was read at, so an edit takes effect without a
60
+ * daemon restart.
61
+ *
62
+ * The path is part of the key. Two roots can share an mtime — a coarse filesystem stamps
63
+ * every write in the same millisecond — and a cache that remembers only the time returns
64
+ * the other root's commands.
65
+ */
58
66
  let cached;
59
67
  /**
60
68
  * Read `.reticle/hooks.json`, or nothing.
@@ -76,21 +84,22 @@ export function readHookConfig(reticleRoot) {
76
84
  return {};
77
85
  }
78
86
  try {
79
- return readOpenHookConfig(fd);
87
+ return readOpenHookConfig(fd, path);
80
88
  }
81
89
  finally {
82
90
  closeSync(fd);
83
91
  }
84
92
  }
85
- function readOpenHookConfig(fd) {
93
+ function readOpenHookConfig(fd, path) {
86
94
  const mtime = fstatSync(fd).mtimeMs;
87
- if (cached !== undefined && cached.at === mtime)
95
+ if (cached !== undefined && cached.path === path && cached.at === mtime) {
88
96
  return cached.config;
97
+ }
89
98
  try {
90
99
  const parsed = HookConfigSchema.safeParse(JSON.parse(readFileSync(fd, 'utf8')));
91
100
  if (!parsed.success) {
92
101
  reportOnce(`config:${String(mtime)}`, `${ReticleDir.HOOKS_FILE} is not a map of event→command`);
93
- cached = { at: mtime, config: {} };
102
+ cached = { path, at: mtime, config: {} };
94
103
  return {};
95
104
  }
96
105
  // An unknown event name is the likeliest mistake in this file and the one that is otherwise
@@ -103,12 +112,12 @@ function readOpenHookConfig(fd) {
103
112
  }
104
113
  reportOnce(`unknown:${event}`, `${ReticleDir.HOOKS_FILE} names "${event}", which is not a Reticle event. Known events: ${HOOK_EVENT_NAMES.join(', ')}`);
105
114
  }
106
- cached = { at: mtime, config: known };
115
+ cached = { path, at: mtime, config: known };
107
116
  return known;
108
117
  }
109
118
  catch (error) {
110
119
  reportOnce(`parse:${String(mtime)}`, `${ReticleDir.HOOKS_FILE} could not be read: ${error instanceof Error ? error.message : String(error)}`);
111
- cached = { at: mtime, config: {} };
120
+ cached = { path, at: mtime, config: {} };
112
121
  return {};
113
122
  }
114
123
  }
@@ -167,8 +176,9 @@ export function runHookCommand(command, payload, cwd) {
167
176
  export function installCommandHooks(reticleRoot) {
168
177
  return onHook(undefined, (payload) => {
169
178
  const command = readHookConfig(reticleRoot)[payload.event];
170
- if (command === undefined || 0 === command.trim().length)
179
+ if (command === undefined || 0 === command.trim().length) {
171
180
  return;
181
+ }
172
182
  runHookCommand(command, payload, reticleRoot);
173
183
  });
174
184
  }
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { replayVerdictLine } from './language/flows/replay-from-hud.js';
6
6
  export { ReticleTool } from '@reticlehq/core';
7
7
  export { RingBuffer } from '@reticlehq/engine/window/ring-buffer.js';
8
8
  export { Bridge } from './portal/bridge/bridge.js';
9
+ export type { FollowNavigation, OriginFollowRequest, } from './portal/bridge/origin/origin-follow.js';
9
10
  export { Session } from './portal/session/session.js';
10
11
  export { SessionManager } from './portal/session/session-manager.js';
11
12
  export type { SessionInfo, SessionHealth } from './portal/session/session.js';
@@ -14,7 +15,8 @@ export type { RecommendationInputs } from './portal/session/presence/session-rec
14
15
  export { TOOLS } from './surface/tools/tools.js';
15
16
  export type { ToolDeps, ToolDef } from './surface/tools/tools.js';
16
17
  export { createToolInvoker, UNKNOWN_TOOL_ERROR } from './surface/tools/tool-invoker.js';
17
- export { runTool, SESSION_BOUND_TOOLS, SESSION_EXEMPT_TOOLS } from './surface/tools/invoke-tool.js';
18
+ export { runTool } from './surface/tools/invoke-tool.js';
19
+ export { SESSION_BOUND_TOOLS, SESSION_EXEMPT_TOOLS } from './surface/tools/tool-kit.js';
18
20
  export type { ToolInvoker } from './surface/tools/tool-invoker.js';
19
21
  /**
20
22
  * The port-presence check the CLI commands (`drive`, `verify`, `status`, `doctor`, `kill`) all share,
@@ -72,6 +74,8 @@ export interface RunningServer {
72
74
  * the client owns the process and there is no stream to warn. See SharedServer.announceShutdown.
73
75
  */
74
76
  announceShutdown?: () => void;
77
+ /** Daemon only: run `handler` when a caller with the pairing token POSTs SHUTDOWN_PATH. */
78
+ onShutdownRequest?: (handler: () => void) => void;
75
79
  close: () => Promise<void>;
76
80
  }
77
81
  export { resolveBridgeSecurity } from './portal/bridge/bridge-security.js';