@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
@@ -9,11 +9,10 @@
9
9
  *
10
10
  * Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
11
11
  */
12
- import { fixturePortFor, seedFromStorageState, } from '../../portal/input/storage-fixture.js';
13
- import { mutationPortFor } from '../../portal/input/network-mutation.js';
12
+ import * as production from '../../portal/production/production-activation.js';
14
13
  import { z } from 'zod';
15
- import { leaseNotConnectedHint } from './lease-hint.js';
16
- import { probeLeaseAlive, tabHidden } from './lease-readiness.js';
14
+ import { leaseNotConnectedHint, leaseReaderFailedHint, leaseStillLoadingHint, } from './lease-hint.js';
15
+ import { connectOrInject, moveReusedLease, notReadyReason, probeLeaseAlive, } from './lease-readiness.js';
17
16
  import { probeSdkMarker } from './gaps/sdk-marker-probe.js';
18
17
  import { observeWebDocument } from '../../portal/session/dev-server/served-document.js';
19
18
  import { diagnoseObservedWebCsp } from '@reticlehq/init';
@@ -22,12 +21,15 @@ import { hasAnyAppConnectedBefore } from '../../memory/recall/prior/connection-m
22
21
  import { AGENT_DRIVING_ELSEWHERE, AGENT_DRIVING_HERE_AGAIN, watchersToNotify, } from '../../portal/session/lease-visibility.js';
23
22
  import { reticleStateHome } from '../../command/daemon/daemon.js';
24
23
  import { claimArtifactRoot, dropArtifactRootClaim } from '../../memory/project/root-claims.js';
25
- import { LeaseNotReadyReason, RETICLE_URL_PARAM, RETICLE_DEFAULT_PORT, SeedStorageSchema, } from '@reticlehq/core';
24
+ import { LeaseNotReadyReason, RETICLE_URL_PARAM, RETICLE_DEFAULT_PORT, SeedStorageSchema, originOf, } from '@reticlehq/core';
26
25
  import { HudVisibility, ReticleTool, SESSION_HEALTH } from '@reticlehq/core';
27
26
  import { HOST_STUB_NOTE } from './tool-kit.js';
27
+ import { PoolAtCapacityError } from '../../portal/pool/browser-pool.js';
28
28
  import { asString } from '@reticlehq/core';
29
29
  import { chromiumPreflightRefusal } from '../../command/cli/doctor/browser/chromium-hint.js';
30
30
  import { LEASE_PERMISSIONS_ARG, hintOf, notificationReadBack, parseLeasePermissions, permissionRefusal, refuseRegrant, } from './lease-permissions.js';
31
+ import { LEASE_EMULATE_ARG, leaseEmulationOf } from '../../portal/input/viewport-tools.js';
32
+ export { sessionMutationPort, sessionPerturbationPort, suiteFixturePort, suiteFixtureSeed, } from './session-ports.js';
31
33
  /**
32
34
  * Everything the daemon already knows about why a leased tab might not have dialled in.
33
35
  *
@@ -51,11 +53,13 @@ import { LEASE_PERMISSIONS_ARG, hintOf, notificationReadBack, parseLeasePermissi
51
53
  */
52
54
  async function observedCspBlock(url, port) {
53
55
  const document = await observeWebDocument(url);
54
- if (document === undefined)
56
+ if (document === undefined) {
55
57
  return undefined;
58
+ }
56
59
  const refusesSocket = diagnoseObservedWebCsp(document, port).some((finding) => `${finding.problem} ${finding.fix}`.includes(CONNECT_SRC));
57
- if (!refusesSocket)
60
+ if (!refusesSocket) {
58
61
  return undefined;
62
+ }
59
63
  const allow = `ws://localhost:${String(port)} ws://127.0.0.1:${String(port)}`;
60
64
  return {
61
65
  problem: `its ${CONNECT_SRC} does not allow ws://localhost:${String(port)}`,
@@ -81,15 +85,6 @@ async function leaseEvidence(deps, port, url) {
81
85
  };
82
86
  }
83
87
  const POOL_UNAVAILABLE = 'browser pool unavailable — the lease tools need the daemon-managed pool (start Reticle via `reticle mcp`).';
84
- /** The origin of a URL, or undefined when it does not parse. */
85
- function originOf(url) {
86
- try {
87
- return new URL(url).origin;
88
- }
89
- catch {
90
- return undefined;
91
- }
92
- }
93
88
  const ALREADY_HELD_LEASE = 'you already hold a lease on this origin';
94
89
  function alreadyHeldHint(sessionId, origin) {
95
90
  return (`${ALREADY_HELD_LEASE} (${origin}): ${sessionId} — reused it rather than opening a second ` +
@@ -108,8 +103,9 @@ export function appendReticleParams(url, session, projectId, hud) {
108
103
  if (projectId !== undefined && projectId.length > 0) {
109
104
  u.searchParams.set(RETICLE_URL_PARAM.PROJECT, projectId);
110
105
  }
111
- if (hud !== undefined)
106
+ if (hud !== undefined) {
112
107
  u.searchParams.set(RETICLE_URL_PARAM.HUD, hud);
108
+ }
113
109
  return u.toString();
114
110
  }
115
111
  catch {
@@ -143,8 +139,9 @@ function newLeaseId() {
143
139
  * so `lease-abc` cannot claim `lease-abcdef`.
144
140
  */
145
141
  export function resolveLeasedSessionId(sessions, leaseId) {
146
- if (sessions.get(leaseId) !== undefined)
142
+ if (sessions.get(leaseId) !== undefined) {
147
143
  return leaseId;
144
+ }
148
145
  return sessions.all().find((s) => sessionParamOf(s.url) === leaseId)?.id;
149
146
  }
150
147
  /**
@@ -162,17 +159,20 @@ export function resolveLeasedSessionId(sessions, leaseId) {
162
159
  */
163
160
  export function carryReticleIdentity(fromUrl, toUrl) {
164
161
  const session = sessionParamOf(fromUrl);
165
- if (session === undefined)
162
+ if (session === undefined) {
166
163
  return toUrl;
164
+ }
167
165
  // Already addressed (a caller passing the stamped URL back) — appending would be a no-op at best.
168
- if (sessionParamOf(toUrl) !== undefined)
166
+ if (sessionParamOf(toUrl) !== undefined) {
169
167
  return toUrl;
168
+ }
170
169
  const projectId = projectParamOf(fromUrl);
171
170
  return appendReticleParams(toUrl, session, projectId);
172
171
  }
173
172
  function projectParamOf(url) {
174
- if (url === undefined)
173
+ if (url === undefined) {
175
174
  return undefined;
175
+ }
176
176
  try {
177
177
  return new URL(url).searchParams.get(RETICLE_URL_PARAM.PROJECT) ?? undefined;
178
178
  }
@@ -181,8 +181,9 @@ function projectParamOf(url) {
181
181
  }
182
182
  }
183
183
  function sessionParamOf(url) {
184
- if (url === undefined)
184
+ if (url === undefined) {
185
185
  return undefined;
186
+ }
186
187
  try {
187
188
  return new URL(url).searchParams.get(RETICLE_URL_PARAM.SESSION) ?? undefined;
188
189
  }
@@ -190,15 +191,6 @@ function sessionParamOf(url) {
190
191
  return undefined;
191
192
  }
192
193
  }
193
- const LEASE_READY_ATTEMPTS = 100;
194
- const LEASE_READY_POLL_MS = 100;
195
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
196
- /**
197
- * Poll until the leased tab's SDK has actually registered on the bridge, so the sessionId we return
198
- * is immediately usable (the page navigates first, then connects a moment later — without this wait
199
- * an agent's very next call could race and hit "no connected session"). Returns whether it connected
200
- * in time. `isConnected`, `sleeper`, and `attempts` are injected so this is fast to unit-test.
201
- */
202
194
  /**
203
195
  * Acquire a leased, SDK-connected context for a caller that is not the lease TOOL (the parallel suite).
204
196
  * Returns the session id plus its release; the caller must release in a finally so a crashed flow never
@@ -224,8 +216,9 @@ export async function acquireLeasedSession(pool, sessions, url, projectId, seedS
224
216
  registeredId = resolveLeasedSessionId(sessions, lease.sessionId);
225
217
  return registeredId !== undefined;
226
218
  });
227
- if (registeredId !== undefined)
219
+ if (registeredId !== undefined) {
228
220
  pool.alias?.(registeredId, lease.sessionId);
221
+ }
229
222
  const effectiveId = registeredId ?? lease.sessionId;
230
223
  if (seedStorage !== undefined) {
231
224
  const session = sessions.get(effectiveId);
@@ -238,31 +231,6 @@ export async function acquireLeasedSession(pool, sessions, url, projectId, seedS
238
231
  }
239
232
  return { sessionId: effectiveId, release: () => lease.release() };
240
233
  }
241
- export async function waitForLeasedSession(isConnected, sleeper = sleep, attempts = LEASE_READY_ATTEMPTS, pollMs = LEASE_READY_POLL_MS) {
242
- for (let i = 0; i < attempts; i++) {
243
- if (isConnected())
244
- return true;
245
- await sleeper(pollMs);
246
- }
247
- return isConnected();
248
- }
249
- /**
250
- * Wait for the leased tab to connect; if its app never does, hand it the zero-install reader.
251
- *
252
- * The decision is taken HERE, by the daemon, on the one fact that settles it: no HELLO arrived. A
253
- * timer inside the page cannot know that — an app can connect from a dynamic import that resolves
254
- * after `load` — and a reader injected into a page whose app was about to connect would take its
255
- * place and drop the app's own options. So an app that connected itself is never touched, and a page
256
- * that stayed silent through the whole readiness wait is the one that gets a reader.
257
- */
258
- export async function connectOrInject(lease, isConnected, wait = waitForLeasedSession) {
259
- if (await wait(isConnected))
260
- return { ready: true, zeroInstall: false };
261
- if (true !== (await lease.injectReader?.()))
262
- return { ready: false, zeroInstall: false };
263
- const ready = await wait(isConnected);
264
- return { ready, zeroInstall: ready };
265
- }
266
234
  /**
267
235
  * Named on its own because `reticle drive <url>` runs it too.
268
236
  *
@@ -280,11 +248,12 @@ export function hasOriginLock(origin) {
280
248
  }
281
249
  export const LEASE_ACQUIRE_TOOL = {
282
250
  name: ReticleTool.LEASE_ACQUIRE,
283
- description: 'Lease a fresh isolated browser context from the shared pool (shown or hidden as the daemon was started; `headed: true` forces a window) and navigate it to the app URL (the app must already be running; one with no Reticle SDK gets one supplied, reported as zeroInstall). If this origin is already leased and still connected, this returns THAT session rather than minting a second tab — a second acquire on the same origin poisons default session resolution. Returns the sessionId the leased tab registers — pass it to other tools. The pool keeps all leases in ONE browser and caps concurrency; if at capacity this waits for a free slot. Release with reticle_lease{action:"release"} when the flow is done. PREFER AN ALREADY-OPEN TAB: if reticle_sessions lists a non-leased session for this app, drive THAT instead — a lease is invisible to the person watching the app, whose HUD lives in their own tab, and a tab flagged hidden/throttled is often still driveable. Lease for isolation you actually need (a second identity, a clean context, parallel flows) or when driving the open tab has failed — this call answers with `preferExisting` when a live tab was available.',
251
+ description: 'Lease a fresh isolated browser context from the shared pool (shown or hidden as the daemon was started; `headed: true` forces a window) and navigate it to the app URL (the app must already be running; one with no Reticle SDK gets one supplied, reported as zeroInstall). If this origin is already leased and still connected, this returns THAT session rather than minting a second tab — a second acquire on the same origin poisons default session resolution. Returns the sessionId the leased tab registers — pass it to other tools. The pool keeps all leases in ONE browser and caps concurrency; if every slot is taken this is refused at once, naming the cap, rather than queued. Release with reticle_lease{action:"release"} when the flow is done. PREFER AN ALREADY-OPEN TAB: if reticle_sessions lists a non-leased session for this app, drive THAT instead — a lease is invisible to the person watching the app, whose HUD lives in their own tab, and a tab flagged hidden/throttled is often still driveable. Lease for isolation you actually need (a second identity, a clean context, parallel flows) or when driving the open tab has failed — this call answers with `preferExisting` when a live tab was available.',
284
252
  inputSchema: {
285
253
  url: z
286
254
  .string()
287
- .describe('URL of the already-running app to drive (e.g. http://localhost:3000/dashboard).'),
255
+ .optional()
256
+ .describe('URL of the already-running app to drive (e.g. http://localhost:3000/dashboard). Omit it to lease the one dev server that runs in this project folder.'),
288
257
  projectId: z
289
258
  .string()
290
259
  .optional()
@@ -307,10 +276,12 @@ export const LEASE_ACQUIRE_TOOL = {
307
276
  .optional()
308
277
  .describe('How the HUD starts on the page: shown (default), hidden, or removed.'),
309
278
  permissions: LEASE_PERMISSIONS_ARG,
279
+ emulate: LEASE_EMULATE_ARG,
280
+ production: production.PRODUCTION_LEASE_ARG,
310
281
  root: z
311
282
  .string()
312
283
  .optional()
313
- .describe("Absolute path of the .reticle folder this lease's runs belong in — the caller's project. Without it, the page's project id decides, and a page with none lands in ~/.reticle/unmatched, which nothing syncs."),
284
+ .describe("Absolute path of the .reticle folder this lease's runs belong in — the caller's project. The project folder itself is accepted when it contains a .reticle. Without it, the page's project id decides, and a page with none lands in ~/.reticle/unmatched, which nothing syncs."),
314
285
  },
315
286
  outputSchema: {
316
287
  sessionId: z.string(),
@@ -331,9 +302,11 @@ export const LEASE_ACQUIRE_TOOL = {
331
302
  LeaseNotReadyReason.SDK_NEVER_DIALLED,
332
303
  LeaseNotReadyReason.SDK_STOPPED_ANSWERING,
333
304
  LeaseNotReadyReason.TAB_HIDDEN,
305
+ LeaseNotReadyReason.NOT_HTML_DOCUMENT,
306
+ LeaseNotReadyReason.READER_FAILED,
334
307
  ])
335
308
  .optional()
336
- .describe('Present only when ready is false. sdk_never_dialled ⇒ nothing connected within the wait, so check the install (the app may not embed @reticlehq/core). sdk_stopped_answering ⇒ an SDK did connect and has stopped replying, so the tab is wedged and needs recovering, not reinstalling. tab_hidden ⇒ the SDK answers but its tab is hidden, so timers and animations are throttled and nothing on it verifies; bring the tab to the front, or release and re-acquire.'),
309
+ .describe('Present only when ready is false. sdk_never_dialled ⇒ nothing connected within the wait, so check the install (the app may not embed @reticlehq/core), unless the hint says the page was still loading, in which case it is a slow first compile and checking reticle_session { action: "list" } shortly is the next step. sdk_stopped_answering ⇒ an SDK did connect and has stopped replying, so the tab is wedged and needs recovering, not reinstalling. tab_hidden ⇒ the SDK answers but its tab is hidden, so timers and animations are throttled and nothing on it verifies; bring the tab to the front, or release and re-acquire. not_html_document ⇒ the URL is not an HTML page (an `.svg`, for example), so acquire an HTML page of the app instead. reader_failed ⇒ the zero-install reader failed, for example because the tab closed during setup; the hint gives the cause. For both, the lease is already released.'),
337
310
  expiresInMs: z
338
311
  .number()
339
312
  .describe('Milliseconds until this lease expires if untouched. Each tool call that targets this session resets the clock. Plan your work to finish or re-acquire before this runs out.'),
@@ -347,7 +320,12 @@ export const LEASE_ACQUIRE_TOOL = {
347
320
  .boolean()
348
321
  .optional()
349
322
  .describe('True when this acquire returned an existing live lease on the same origin rather than minting a second context.'),
323
+ navigated: z
324
+ .boolean()
325
+ .optional()
326
+ .describe('Present when a reused lease was on another page. True: its tab was moved to url. False: it could not be moved, and url is the page it is on.'),
350
327
  hint: z.string().optional(),
328
+ production: production.PRODUCTION_LEASE_OUTPUT,
351
329
  versionSkew: z
352
330
  .string()
353
331
  .optional()
@@ -357,11 +335,14 @@ export const LEASE_ACQUIRE_TOOL = {
357
335
  },
358
336
  handler: async (deps, args) => {
359
337
  const pool = deps.pool;
360
- if (pool === undefined)
338
+ if (pool === undefined) {
361
339
  throw new Error(POOL_UNAVAILABLE);
362
- const url = asString(args['url']);
363
- if (url === undefined || 0 === url.length)
364
- throw new Error('reticle_lease{action:"acquire"} requires a url');
340
+ }
341
+ const given = asString(args['url']);
342
+ const url = given === undefined || 0 === given.length ? await deps.projectAppUrl?.() : given;
343
+ if (url === undefined) {
344
+ throw new Error('reticle_lease{action:"acquire"} requires a url: no single dev server runs in this project folder. Start the app, or pass the url it serves.');
345
+ }
365
346
  // Preflight the browser before spending the round trip. Without it a missing Playwright Chromium
366
347
  // only surfaces inside pool.acquire, where the launch failure is caught and reported as
367
348
  // "could not open <url> — is the app running?" — sending the caller to debug an app that is
@@ -369,14 +350,16 @@ export const LEASE_ACQUIRE_TOOL = {
369
350
  // installed" so error-recovery routes it to the NO_POOL fix (install + drive a human tab).
370
351
  if (deps.browserProbe !== undefined) {
371
352
  const refusal = chromiumPreflightRefusal(await deps.browserProbe());
372
- if (refusal !== undefined)
353
+ if (refusal !== undefined) {
373
354
  throw new Error(refusal);
355
+ }
374
356
  }
375
357
  const projectId = asString(args['projectId']);
376
358
  const root = asString(args['root']);
377
359
  const headed = true === args['headed'];
378
360
  const hud = Object.values(HudVisibility).find((v) => v === args['hud']);
379
- const permissions = parseLeasePermissions(args['permissions']);
361
+ const permissions = production.leasePermissions(parseLeasePermissions(args['permissions']), args['production']);
362
+ const emulate = leaseEmulationOf(args['emulate']);
380
363
  // The stub of the shell bindings, when the caller supplied one. Installed by the pool before
381
364
  // the first navigation, so it is already defined when the app's first module runs.
382
365
  const initScript = asString(args['initScript']);
@@ -395,6 +378,10 @@ export const LEASE_ACQUIRE_TOOL = {
395
378
  }
396
379
  validatedSeed = parsed.data;
397
380
  }
381
+ // Awaited only when asked: an extra tick here reorders concurrent acquires on the origin lock.
382
+ const activated = args['production'] === undefined
383
+ ? undefined
384
+ : await production.activationFor(deps, args['production'], url, root);
398
385
  // Sampled BEFORE acquiring: afterwards this lease is itself a session, and the point is to name
399
386
  // a tab that already existed. A human's open tab is the one they can watch, so if one is here
400
387
  // the agent should be told at the moment it is choosing — not after it has gone dark on them.
@@ -437,7 +424,12 @@ export const LEASE_ACQUIRE_TOOL = {
437
424
  const certMismatch = existing !== undefined &&
438
425
  'boolean' === typeof certAsked &&
439
426
  pool.ignoresHTTPSErrors(existing) !== certAsked;
440
- if ((validatedSeed !== undefined || certMismatch) && existing !== undefined) {
427
+ // Emulation is set before the first paint, so a held lease is replaced like a seeded one.
428
+ if ((validatedSeed !== undefined ||
429
+ certMismatch ||
430
+ emulate !== undefined ||
431
+ activated !== undefined) &&
432
+ existing !== undefined) {
441
433
  // Seeding or a different certificate setting asked for: release its own context so the new
442
434
  // lease starts with what was asked.
443
435
  await pool.release(existing);
@@ -463,16 +455,16 @@ export const LEASE_ACQUIRE_TOOL = {
463
455
  // old, or there may be none at all — `unresponsive` is set by past commands failing, and
464
456
  // its own contract says absence means "answering, OR NOT ASKED YET". So the happy path of
465
457
  // a first acquire pays nothing for this.
458
+ const tabUrl = () => deps.sessions.get(resolved)?.url;
459
+ const moved = await moveReusedLease(tabUrl, url, () => pool.gotoLease(existing, carryReticleIdentity(tabUrl(), url)), deps.now);
466
460
  const reusedSession = deps.sessions.get(resolved);
467
- const alive = await probeLeaseAlive(reusedSession);
468
- const reuseReason = !alive
469
- ? LeaseNotReadyReason.SDK_STOPPED_ANSWERING
470
- : tabHidden(reusedSession)
471
- ? LeaseNotReadyReason.TAB_HIDDEN
472
- : undefined;
461
+ const reuseReason = false === moved?.arrived
462
+ ? LeaseNotReadyReason.SDK_NEVER_DIALLED
463
+ : notReadyReason(await probeLeaseAlive(reusedSession), reusedSession);
473
464
  return {
474
465
  sessionId: resolved,
475
- url,
466
+ url: moved?.url ?? url,
467
+ ...(moved === undefined ? {} : { navigated: moved.navigated }),
476
468
  ready: reuseReason === undefined,
477
469
  ...(reuseReason === undefined ? {} : { notReadyReason: reuseReason }),
478
470
  reused: true,
@@ -495,25 +487,34 @@ export const LEASE_ACQUIRE_TOOL = {
495
487
  }
496
488
  const sessionId = newLeaseId();
497
489
  // Before the page can dial in: the session is stamped with its root the moment it registers.
498
- if (root !== undefined)
490
+ if (root !== undefined) {
499
491
  claimArtifactRoot(sessionId, root);
500
- const navUrl = appendReticleParams(url, sessionId, projectId, hud);
492
+ }
493
+ const navUrl = appendReticleParams(activated?.url ?? url, sessionId, projectId, hud);
501
494
  let lease;
502
495
  try {
503
496
  lease = await pool.acquire(navUrl, {
504
497
  sessionId,
498
+ // An agent, or `reticle drive` behind it, is waiting on this answer and cannot see a queue:
499
+ // a full pool is said at once, not discovered as a 60 s silence (#1535).
500
+ whenFull: 'refuse',
505
501
  ...(headed ? { headed } : {}),
506
502
  ...(deps.attachId === undefined ? {} : { owner: deps.attachId }),
507
503
  ...(validatedSeed !== undefined ? { seedStorage: validatedSeed } : {}),
508
504
  ...(initScript !== undefined ? { initScript } : {}),
509
505
  ...(permissions !== undefined ? { permissions } : {}),
510
506
  ...(true === args['ignoreHTTPSErrors'] ? { ignoreHTTPSErrors: true } : {}),
507
+ ...(emulate === undefined ? {} : { emulate }),
511
508
  });
512
509
  }
513
510
  catch (err) {
511
+ if (err instanceof PoolAtCapacityError) {
512
+ throw err;
513
+ }
514
514
  const refusal = permissionRefusal(err);
515
- if (refusal !== undefined)
515
+ if (refusal !== undefined) {
516
516
  throw refusal;
517
+ }
517
518
  if (err instanceof Error && err.message.startsWith('Storage seeding failed')) {
518
519
  throw new Error(scrubSeedFromError(err.message, validatedSeed));
519
520
  }
@@ -525,7 +526,9 @@ export const LEASE_ACQUIRE_TOOL = {
525
526
  // Resolved rather than assumed: an app that names its own session registers under that name,
526
527
  // and the id we hand back has to be the one the agent can actually drive.
527
528
  let registeredId;
528
- const { ready, zeroInstall } = await connectOrInject(lease, () => {
529
+ const waitStartedAt = Date.now();
530
+ const waited = await production.guardedForProduction(pool, lease, activated);
531
+ const { ready, zeroInstall, stillLoading, readerFailure } = await connectOrInject(waited, () => {
529
532
  registeredId = resolveLeasedSessionId(deps.sessions, lease.sessionId);
530
533
  return registeredId !== undefined;
531
534
  });
@@ -533,8 +536,9 @@ export const LEASE_ACQUIRE_TOOL = {
533
536
  // under the id we are about to hand back, and the pool is keyed by the id it navigated with;
534
537
  // without this the touches miss, the lease ages out despite continuous activity, and the
535
538
  // reaper closes the context mid-flow. See BrowserPool.alias and #157.
536
- if (registeredId !== undefined)
539
+ if (registeredId !== undefined) {
537
540
  pool.alias(registeredId, lease.sessionId);
541
+ }
538
542
  const effectiveSessionId = registeredId ?? lease.sessionId;
539
543
  const session = deps.sessions.get(effectiveSessionId);
540
544
  if (validatedSeed !== undefined && session !== undefined) {
@@ -543,16 +547,31 @@ export const LEASE_ACQUIRE_TOOL = {
543
547
  session.setPreconditionFailure?.(failureReason);
544
548
  }
545
549
  }
546
- // The lease now exists, so any HUD a human is watching has just gone dark. Say so.
547
- tellWatchers(deps, projectId, AGENT_DRIVING_ELSEWHERE);
550
+ // The lease now exists, so any HUD a human is watching has just gone dark. Say so. A lease whose
551
+ // reader failed is already released, so there is nothing to say.
552
+ if (readerFailure === undefined) {
553
+ tellWatchers(deps, projectId, AGENT_DRIVING_ELSEWHERE);
554
+ }
548
555
  // ready means the SDK dialled in — not that contracts match. Carry the skew warning on acquire
549
556
  // so the agent does not learn it only after a CDP tool invents a closed page (#688).
550
- const mintReason = !ready
551
- ? LeaseNotReadyReason.SDK_NEVER_DIALLED
552
- : tabHidden(session)
553
- ? LeaseNotReadyReason.TAB_HIDDEN
554
- : undefined;
557
+ const mintReason = readerFailure?.reason ??
558
+ notReadyReason(ready, session, LeaseNotReadyReason.SDK_NEVER_DIALLED);
555
559
  const versionSkew = registeredId === undefined ? undefined : deps.sessions.get(registeredId)?.versionSkew;
560
+ let notReadyHint;
561
+ if (!ready) {
562
+ if (readerFailure !== undefined) {
563
+ notReadyHint = leaseReaderFailedHint(url, readerFailure);
564
+ }
565
+ else if (true === stillLoading) {
566
+ notReadyHint = leaseStillLoadingHint(url, Date.now() - waitStartedAt);
567
+ }
568
+ else if (activated !== undefined) {
569
+ notReadyHint = production.notActivatedHint(url);
570
+ }
571
+ else {
572
+ notReadyHint = await notConnectedHint(deps, url, pool.dialFailureUrl?.(lease.sessionId));
573
+ }
574
+ }
556
575
  return {
557
576
  sessionId: registeredId ?? lease.sessionId,
558
577
  url,
@@ -575,10 +594,9 @@ export const LEASE_ACQUIRE_TOOL = {
575
594
  },
576
595
  }),
577
596
  ...(versionSkew === undefined ? {} : { versionSkew }),
597
+ ...production.summary(activated),
578
598
  ...(initScript === undefined ? {} : { hostStub: HOST_STUB_NOTE }),
579
- ...hintOf(ready
580
- ? undefined
581
- : await notConnectedHint(deps, url, pool.dialFailureUrl?.(lease.sessionId)), ready ? await notificationReadBack(pool, lease.sessionId, permissions) : undefined),
599
+ ...hintOf(notReadyHint, ready ? await notificationReadBack(pool, lease.sessionId, permissions) : undefined),
582
600
  };
583
601
  }
584
602
  finally {
@@ -612,12 +630,19 @@ const LEASE_RELEASE_TOOL = {
612
630
  },
613
631
  handler: async (deps, args) => {
614
632
  const pool = deps.pool;
615
- if (pool === undefined)
633
+ if (pool === undefined) {
616
634
  throw new Error(POOL_UNAVAILABLE);
635
+ }
617
636
  const sessionId = asString(args['sessionId']);
618
637
  if (sessionId === undefined || 0 === sessionId.length) {
619
638
  throw new Error('reticle_lease{action:"release"} requires a sessionId');
620
639
  }
640
+ // An id that holds no lease (a typo, or one that expired) answered `released: true`.
641
+ if (pool.leaseUrl(sessionId) === undefined) {
642
+ const held = pool.leasedSessionIds();
643
+ throw new Error(`reticle_lease{action:"release"}: no lease '${sessionId}' is held, so nothing was released. ` +
644
+ (0 === held.length ? 'No lease is held now.' : `Leases held now: ${held.join(', ')}.`));
645
+ }
621
646
  return { released: true, leased: await releaseLease(deps, pool, sessionId) };
622
647
  },
623
648
  };
@@ -636,8 +661,9 @@ export async function releaseLease(deps, pool, sessionId) {
636
661
  dropArtifactRootClaim(sessionId);
637
662
  // Only once the LAST lease is gone. Announcing "live again" while another lease still drives
638
663
  // would be a lie, and a HUD that says the wrong thing is worse than one that says nothing.
639
- if (0 === pool.activeCount())
664
+ if (0 === pool.activeCount()) {
640
665
  tellWatchers(deps, projectId, AGENT_DRIVING_HERE_AGAIN);
666
+ }
641
667
  return pool.activeCount();
642
668
  }
643
669
  /**
@@ -665,11 +691,13 @@ const PREFER_EXISTING_NOTE = 'a non-leased tab for this app was already connecte
665
691
  */
666
692
  function liveTabFor(deps, projectId, url) {
667
693
  const pool = deps.pool;
668
- if (pool === undefined)
694
+ if (pool === undefined) {
669
695
  return undefined;
696
+ }
670
697
  const wanted = originOf(url);
671
- if (wanted === undefined)
698
+ if (wanted === undefined) {
672
699
  return undefined;
700
+ }
673
701
  try {
674
702
  const candidates = deps.sessions
675
703
  .all()
@@ -693,8 +721,9 @@ function liveTabFor(deps, projectId, url) {
693
721
  */
694
722
  function tellWatchers(deps, projectId, text) {
695
723
  const pool = deps.pool;
696
- if (pool === undefined)
724
+ if (pool === undefined) {
697
725
  return;
726
+ }
698
727
  try {
699
728
  const candidates = deps.sessions
700
729
  .all()
@@ -708,96 +737,3 @@ function tellWatchers(deps, projectId, text) {
708
737
  }
709
738
  }
710
739
  export const LEASE_TOOLS = [LEASE_ACQUIRE_TOOL, LEASE_RELEASE_TOOL];
711
- /**
712
- * The state a suite should boot its flows from: whatever the agent is already sitting in.
713
- *
714
- * This is the join the fixture work was building toward. A suite's flows each start from cold, so
715
- * fifty of them prove the login works fifty times — and the flow that LOGS OUT leaves every flow
716
- * after it signed out, which no navigation repairs, because the problem is not where the subject is
717
- * but what it holds. A seed is applied to an isolated context BEFORE the first navigation, which is
718
- * exactly and only when a fixture can work.
719
- *
720
- * Best-effort, deliberately. A fixture is an OPTIMISATION over running from cold, and running from
721
- * cold is correct: a suite that refused to start because a cookie jar could not be read would have
722
- * traded a slow answer for no answer. Every "no" here — no provider, no storage support, nothing
723
- * driven, a browser that threw, nothing worth seeding — produces the same honest `undefined`, and
724
- * the suite runs exactly as it did before any of this existed.
725
- */
726
- export async function suiteFixtureSeed(realInput, appUrl) {
727
- if (realInput === undefined)
728
- return undefined;
729
- try {
730
- const port = await fixturePortFor(realInput, appUrl);
731
- if (port === undefined)
732
- return undefined;
733
- return seedFromStorageState(await port.capture(), appUrl);
734
- }
735
- catch {
736
- return undefined;
737
- }
738
- }
739
- /**
740
- * A way to make this session's page SLOW on purpose, or nothing.
741
- *
742
- * The third of these seams, for the same reason as the other two: a feature reaching into the input
743
- * layer directly is a feature depending on a driver, and the boundary guard asks about it.
744
- *
745
- * Installs delays and NOTHING else. A rule that carried a status or a body would substitute a
746
- * response the server never sent, and an app raced against invented data produces invented races —
747
- * a fabricated defect handed to somebody at 3am, which is worse than finding nothing.
748
- */
749
- export async function sessionPerturbationPort(realInput, appUrl) {
750
- if (realInput === undefined || appUrl === undefined)
751
- return undefined;
752
- const setMocks = realInput.setMocks?.bind(realInput);
753
- if (setMocks === undefined)
754
- return undefined;
755
- if (!(await realInput.isAvailableFor(appUrl)))
756
- return undefined;
757
- return {
758
- slow: async (rules) => {
759
- await setMocks(appUrl, [...rules]);
760
- },
761
- /** Clearing is the undo. A page left slowed is damage the next run inherits. */
762
- clear: async () => {
763
- await setMocks(appUrl, []);
764
- },
765
- };
766
- }
767
- /**
768
- * Save/restore for this session's page, or nothing.
769
- *
770
- * The same job as `suiteFixtureSeed` next door, stopping one step earlier: that one captures and
771
- * converts, this hands back the PORT so a caller can re-apply what it captured later. It lives here
772
- * for the reason written above — a feature reaching into the input layer directly is a feature
773
- * depending on a driver, and the boundary guard asks about it. It asked.
774
- */
775
- export async function suiteFixturePort(realInput, appUrl) {
776
- if (realInput === undefined || appUrl === undefined)
777
- return undefined;
778
- try {
779
- return await fixturePortFor(realInput, appUrl);
780
- }
781
- catch {
782
- return undefined;
783
- }
784
- }
785
- /**
786
- * A way to break this session's page, or nothing.
787
- *
788
- * Sits beside `suiteFixtureSeed` because it is the same shape of job: turning a provider capability
789
- * into something a feature can use, on the one side of the graph that is allowed to know about both.
790
- * A flow tool reaching into the input layer directly would be a feature depending on a driver, which
791
- * is the reach the boundary guard exists to ask about.
792
- */
793
- export async function sessionMutationPort(realInput, appUrl) {
794
- if (realInput === undefined || appUrl === undefined)
795
- return undefined;
796
- try {
797
- return await mutationPortFor(realInput, appUrl);
798
- }
799
- catch {
800
- // A provider that cannot answer is the same answer as a provider that cannot break anything.
801
- return undefined;
802
- }
803
- }
@@ -0,0 +1,20 @@
1
+ import { type AppMap, type JournalAction, type ReticleEvent } from '@reticlehq/core';
2
+ import { type ToolDef } from './tool-kit.js';
3
+ /** One session, as the fold reads it. */
4
+ export interface MapSession {
5
+ id: string;
6
+ actions: readonly JournalAction[];
7
+ events: readonly ReticleEvent[];
8
+ }
9
+ /** One screen on the map, with how much of it was pressed and proven. */
10
+ export interface MapScreen {
11
+ screen: string;
12
+ actions: number;
13
+ pressed: number;
14
+ proven: number;
15
+ }
16
+ /** The project's sessions folded into one graph; undefined when none pressed anything. */
17
+ export declare function graphOfSessions(sessions: readonly MapSession[]): AppMap | undefined;
18
+ /** Each screen with its actions counted: what is there, what was pressed, what held. */
19
+ export declare function screensOf(map: AppMap): MapScreen[];
20
+ export declare const MAP_TOOLS: ToolDef[];