@reticlehq/server 3.5.0 → 3.7.0

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 (721) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +123 -116
  3. package/dist/chromium-launch-options.d.ts +3 -1
  4. package/dist/chromium-launch-options.js +2 -1
  5. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  6. package/dist/command/cli/adhoc-suite.js +42 -7
  7. package/dist/command/cli/adhoc-verdict.d.ts +19 -2
  8. package/dist/command/cli/adhoc-verdict.js +76 -9
  9. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  10. package/dist/command/cli/answers/gate-exit.js +45 -0
  11. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  12. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  13. package/dist/command/cli/answers/open-note.d.ts +2 -0
  14. package/dist/command/cli/answers/open-note.js +22 -0
  15. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  16. package/dist/command/cli/auth/device-flow.js +17 -0
  17. package/dist/command/cli/cli-doctor.js +14 -0
  18. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  19. package/dist/command/cli/cli-flow-commands.js +31 -112
  20. package/dist/command/cli/cli-kill.js +3 -2
  21. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  22. package/dist/command/cli/cli-parse-grammar.js +75 -0
  23. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  24. package/dist/command/cli/cli-parse-verify.js +18 -0
  25. package/dist/command/cli/cli-parse.d.ts +19 -28
  26. package/dist/command/cli/cli-parse.js +82 -182
  27. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  28. package/dist/command/cli/cli-update-commands.js +61 -9
  29. package/dist/command/cli/cli-usage.d.ts +33 -0
  30. package/dist/command/cli/cli-usage.js +287 -0
  31. package/dist/command/cli/cli-verify.d.ts +35 -5
  32. package/dist/command/cli/cli-verify.js +114 -35
  33. package/dist/command/cli/cloud-cli.d.ts +13 -0
  34. package/dist/command/cli/cloud-cli.js +192 -341
  35. package/dist/command/cli/cloud-kit.d.ts +12 -0
  36. package/dist/command/cli/cloud-kit.js +41 -2
  37. package/dist/command/cli/cloud-link.d.ts +57 -0
  38. package/dist/command/cli/cloud-link.js +308 -0
  39. package/dist/command/cli/cloud-login.d.ts +22 -0
  40. package/dist/command/cli/cloud-login.js +96 -8
  41. package/dist/command/cli/context-command.d.ts +1 -0
  42. package/dist/command/cli/context-command.js +33 -0
  43. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  44. package/dist/command/cli/daemon-start-options.js +24 -3
  45. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
  46. package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
  47. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  48. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  49. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  50. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  51. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  52. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  53. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  54. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  55. package/dist/command/cli/drive/drive-attach.d.ts +27 -2
  56. package/dist/command/cli/drive/drive-attach.js +71 -4
  57. package/dist/command/cli/drive/drive-command.d.ts +2 -1
  58. package/dist/command/cli/drive/drive-command.js +13 -7
  59. package/dist/command/cli/known-regression.d.ts +13 -0
  60. package/dist/command/cli/known-regression.js +34 -0
  61. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  62. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  63. package/dist/command/cli/lifecycle/daemon-lifecycle.js +15 -3
  64. package/dist/command/cli/mcp-command.d.ts +6 -0
  65. package/dist/command/cli/mcp-command.js +13 -5
  66. package/dist/command/cli/ports/port-holder.d.ts +10 -0
  67. package/dist/command/cli/ports/port-holder.js +25 -1
  68. package/dist/command/cli/project-name.d.ts +29 -1
  69. package/dist/command/cli/project-name.js +107 -2
  70. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  71. package/dist/command/cli/setup-mcp-cli.js +35 -12
  72. package/dist/command/cli/status/status-lines.d.ts +1 -0
  73. package/dist/command/cli/status/status-lines.js +47 -2
  74. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  75. package/dist/command/cli/status/workspace-links.js +29 -0
  76. package/dist/command/cli/try-command.d.ts +96 -0
  77. package/dist/command/cli/try-command.js +362 -0
  78. package/dist/command/cli/tutorial.d.ts +0 -100
  79. package/dist/command/cli/tutorial.js +0 -181
  80. package/dist/command/cli/verify-results.d.ts +19 -0
  81. package/dist/command/cli/verify-results.js +29 -0
  82. package/dist/command/cli-onboarding.d.ts +0 -11
  83. package/dist/command/cli-onboarding.js +0 -15
  84. package/dist/command/cli.d.ts +20 -0
  85. package/dist/command/cli.js +130 -104
  86. package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
  87. package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
  88. package/dist/command/daemon/daemon-resilience.js +4 -4
  89. package/dist/command/daemon/daemon-resolve.d.ts +23 -1
  90. package/dist/command/daemon/daemon-resolve.js +79 -9
  91. package/dist/command/setup/agent-writer.d.ts +1 -1
  92. package/dist/command/setup/agent-writer.js +3 -2
  93. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  94. package/dist/command/setup/bringup/bridge-port.js +13 -3
  95. package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
  96. package/dist/command/setup/bringup/connect-lease.js +1 -0
  97. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  98. package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
  99. package/dist/command/setup/bringup/dev-server-wait.js +19 -0
  100. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  101. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  102. package/dist/command/setup/init/agent-restart.js +28 -0
  103. package/dist/command/setup/init/init-port.d.ts +14 -1
  104. package/dist/command/setup/init/init-port.js +32 -2
  105. package/dist/command/setup/init/init-runtime.d.ts +22 -2
  106. package/dist/command/setup/init/init-runtime.js +114 -38
  107. package/dist/command/setup/node-effects.d.ts +2 -0
  108. package/dist/command/setup/node-effects.js +38 -9
  109. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  110. package/dist/command/setup/probe/existing-app.js +14 -0
  111. package/dist/command/setup/remaining-steps.js +2 -1
  112. package/dist/command/setup/run-setup.d.ts +34 -9
  113. package/dist/command/setup/run-setup.js +65 -51
  114. package/dist/command/setup/setup-command.d.ts +25 -1
  115. package/dist/command/setup/setup-command.js +59 -4
  116. package/dist/command/setup/setup-mcp.js +25 -2
  117. package/dist/command/setup/tauri-signing.d.ts +19 -0
  118. package/dist/command/setup/tauri-signing.js +79 -0
  119. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  120. package/dist/command/setup/terminal/listeners.js +37 -6
  121. package/dist/command/update/update-nudge.d.ts +9 -0
  122. package/dist/command/update/update-nudge.js +1 -1
  123. package/dist/command/update/updater.js +11 -15
  124. package/dist/command/version/version-nudge.js +3 -0
  125. package/dist/command/version/version-skew.d.ts +20 -1
  126. package/dist/command/version/version-skew.js +49 -4
  127. package/dist/features/crawl/crawl-tools.js +4 -0
  128. package/dist/features/crawl/crawl.d.ts +6 -0
  129. package/dist/features/crawl/crawl.js +23 -2
  130. package/dist/features/exhaust/ledger.d.ts +21 -14
  131. package/dist/features/exhaust/ledger.js +35 -9
  132. package/dist/features/harness/app-findings.d.ts +2 -0
  133. package/dist/features/harness/app-findings.js +52 -0
  134. package/dist/features/harness/drive-report.d.ts +61 -1
  135. package/dist/features/harness/drive-report.js +394 -26
  136. package/dist/features/harness/drive-runs.d.ts +120 -0
  137. package/dist/features/harness/drive-runs.js +289 -0
  138. package/dist/features/harness/drivers.d.ts +10 -14
  139. package/dist/features/harness/drivers.js +10 -14
  140. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  141. package/dist/features/harness/explore/console-pages.js +146 -0
  142. package/dist/features/harness/explore/disparity.d.ts +19 -0
  143. package/dist/features/harness/explore/disparity.js +71 -0
  144. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  145. package/dist/features/harness/explore/fake-app.js +49 -0
  146. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  147. package/dist/features/harness/explore/goal-search.js +144 -0
  148. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  149. package/dist/features/harness/explore/page-tree.js +148 -0
  150. package/dist/features/harness/explore/site-map.d.ts +34 -0
  151. package/dist/features/harness/explore/site-map.js +150 -0
  152. package/dist/features/harness/fill-values.d.ts +3 -73
  153. package/dist/features/harness/fill-values.js +3 -169
  154. package/dist/features/harness/goals.d.ts +82 -0
  155. package/dist/features/harness/goals.js +330 -0
  156. package/dist/features/harness/harness.d.ts +51 -1
  157. package/dist/features/harness/harness.js +207 -6
  158. package/dist/features/harness/platform/drive-target.d.ts +30 -0
  159. package/dist/features/harness/platform/drive-target.js +81 -0
  160. package/dist/features/harness/platform/local-apps.d.ts +127 -0
  161. package/dist/features/harness/platform/local-apps.js +280 -0
  162. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  163. package/dist/features/harness/platform/persona-credentials.js +69 -0
  164. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  165. package/dist/features/harness/platform/platform-drives.js +114 -0
  166. package/dist/features/harness/platform/refusal.d.ts +52 -0
  167. package/dist/features/harness/platform/refusal.js +71 -0
  168. package/dist/features/harness/platform/remote-drive.d.ts +186 -0
  169. package/dist/features/harness/platform/remote-drive.js +378 -0
  170. package/dist/features/harness/platform/script.d.ts +94 -0
  171. package/dist/features/harness/platform/script.js +260 -0
  172. package/dist/features/harness/platform/server-driver.d.ts +54 -0
  173. package/dist/features/harness/platform/server-driver.js +182 -0
  174. package/dist/features/harness/platform-config.d.ts +41 -1
  175. package/dist/features/harness/platform-config.js +106 -9
  176. package/dist/features/harness/route-guess.d.ts +13 -0
  177. package/dist/features/harness/route-guess.js +49 -0
  178. package/dist/features/harness/script/app-controls.d.ts +5 -0
  179. package/dist/features/harness/script/app-controls.js +40 -0
  180. package/dist/features/harness/script/lane-ids.d.ts +14 -0
  181. package/dist/features/harness/script/lane-ids.js +16 -0
  182. package/dist/features/harness/script/script-run.d.ts +70 -0
  183. package/dist/features/harness/script/script-run.js +606 -0
  184. package/dist/features/license/license.d.ts +2 -2
  185. package/dist/features/visual/step-shots.d.ts +31 -0
  186. package/dist/features/visual/step-shots.js +231 -0
  187. package/dist/features/visual/visual-tools.d.ts +10 -1
  188. package/dist/features/visual/visual-tools.js +62 -17
  189. package/dist/hooks/client-directory.d.ts +18 -0
  190. package/dist/hooks/client-directory.js +57 -0
  191. package/dist/hooks/coding-agents.d.ts +34 -0
  192. package/dist/hooks/coding-agents.js +117 -0
  193. package/dist/hooks/driven-by.d.ts +23 -0
  194. package/dist/hooks/driven-by.js +56 -0
  195. package/dist/hooks/hook-bus.d.ts +4 -0
  196. package/dist/hooks/hook-bus.js +18 -0
  197. package/dist/hooks/hook-commands.js +15 -4
  198. package/dist/hooks/tool-log.d.ts +9 -0
  199. package/dist/hooks/tool-log.js +29 -0
  200. package/dist/index.d.ts +2 -0
  201. package/dist/index.js +80 -243
  202. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  203. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  204. package/dist/judgement/capsule/causal-summary.js +33 -0
  205. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  206. package/dist/judgement/runs/artifact/build-verification-run.js +25 -3
  207. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  208. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  209. package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
  210. package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
  211. package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
  212. package/dist/judgement/runs/artifact/run-store.js +195 -3
  213. package/dist/judgement/runs/context-tools.js +59 -1
  214. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  215. package/dist/judgement/runs/default-run-id.js +16 -0
  216. package/dist/judgement/runs/drive-run.d.ts +71 -1
  217. package/dist/judgement/runs/drive-run.js +317 -5
  218. package/dist/judgement/runs/repair-prompt.js +1 -1
  219. package/dist/judgement/runs/resume.d.ts +44 -0
  220. package/dist/judgement/runs/resume.js +137 -0
  221. package/dist/judgement/runs/reticle-runner.js +13 -3
  222. package/dist/judgement/runs/runner-port.d.ts +5 -1
  223. package/dist/judgement/runs/runner-port.js +8 -2
  224. package/dist/judgement/runs/verification-sync.d.ts +5 -2
  225. package/dist/judgement/runs/verification-sync.js +40 -18
  226. package/dist/language/flows/change/gate.d.ts +10 -0
  227. package/dist/language/flows/change/gate.js +22 -0
  228. package/dist/language/flows/decision.js +36 -1
  229. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  230. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  231. package/dist/language/flows/flow-anchor.d.ts +61 -10
  232. package/dist/language/flows/flow-anchor.js +98 -6
  233. package/dist/language/flows/flow-cross-step.d.ts +15 -0
  234. package/dist/language/flows/flow-cross-step.js +21 -0
  235. package/dist/language/flows/flow-intent.d.ts +1 -0
  236. package/dist/language/flows/flow-journey.d.ts +6 -0
  237. package/dist/language/flows/flow-journey.js +20 -0
  238. package/dist/language/flows/flow-learning.d.ts +4 -0
  239. package/dist/language/flows/flow-learning.js +45 -14
  240. package/dist/language/flows/flow-mutate-tools.js +5 -3
  241. package/dist/language/flows/flow-replay-run.d.ts +23 -9
  242. package/dist/language/flows/flow-replay-run.js +115 -110
  243. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  244. package/dist/language/flows/flow-replay.d.ts +40 -1
  245. package/dist/language/flows/flow-replay.js +110 -22
  246. package/dist/language/flows/flow-result.d.ts +22 -1
  247. package/dist/language/flows/flow-result.js +47 -2
  248. package/dist/language/flows/flow-scope.js +5 -1
  249. package/dist/language/flows/flow-step-runners.d.ts +22 -2
  250. package/dist/language/flows/flow-step-runners.js +247 -47
  251. package/dist/language/flows/flow-store-for-session.d.ts +2 -2
  252. package/dist/language/flows/flow-store-for-session.js +7 -3
  253. package/dist/language/flows/flow-tools.d.ts +10 -0
  254. package/dist/language/flows/flow-tools.js +112 -89
  255. package/dist/language/flows/flows.d.ts +16 -1
  256. package/dist/language/flows/flows.js +74 -12
  257. package/dist/language/flows/heal-run.js +6 -4
  258. package/dist/language/flows/narrow-write.d.ts +7 -0
  259. package/dist/language/flows/narrow-write.js +36 -1
  260. package/dist/language/flows/recording/flake.d.ts +2 -2
  261. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  262. package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
  263. package/dist/language/flows/recording/tape/recordings.js +95 -13
  264. package/dist/language/flows/replay-from-hud.d.ts +20 -0
  265. package/dist/language/flows/replay-from-hud.js +51 -0
  266. package/dist/language/flows/replay.d.ts +9 -5
  267. package/dist/language/flows/replay.js +56 -15
  268. package/dist/language/flows/single-replay.d.ts +7 -0
  269. package/dist/language/flows/single-replay.js +26 -0
  270. package/dist/language/flows/suite/suite-flakes.js +2 -0
  271. package/dist/language/flows/suite-selection.d.ts +2 -15
  272. package/dist/language/flows/suite-selection.js +4 -3
  273. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  274. package/dist/language/flows/verify-change-tools.js +202 -191
  275. package/dist/launch-chromium.d.ts +27 -5
  276. package/dist/launch-chromium.js +38 -8
  277. package/dist/memory/cloud/cloud-config.d.ts +22 -1
  278. package/dist/memory/cloud/cloud-config.js +34 -5
  279. package/dist/memory/cloud/cloud-sync.d.ts +17 -14
  280. package/dist/memory/cloud/cloud-sync.js +15 -4
  281. package/dist/memory/cloud/harness-config.d.ts +75 -1
  282. package/dist/memory/cloud/harness-config.js +115 -24
  283. package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
  284. package/dist/memory/cloud/hud-notices-source.js +128 -0
  285. package/dist/memory/cloud/memory-scope.d.ts +161 -0
  286. package/dist/memory/cloud/memory-scope.js +227 -0
  287. package/dist/memory/cloud/sync-cycle.d.ts +44 -7
  288. package/dist/memory/cloud/sync-cycle.js +129 -15
  289. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  290. package/dist/memory/cloud/sync-daemon.js +121 -9
  291. package/dist/memory/cloud/sync-disk.d.ts +1 -1
  292. package/dist/memory/cloud/sync-disk.js +31 -10
  293. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  294. package/dist/memory/cloud/sync-screenshots.js +105 -0
  295. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  296. package/dist/memory/cloud/unsynced-roots.js +166 -0
  297. package/dist/memory/impact/account-watch.d.ts +34 -0
  298. package/dist/memory/impact/account-watch.js +59 -0
  299. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  300. package/dist/memory/impact/impact-recorder.js +12 -2
  301. package/dist/memory/impact/impact-store.d.ts +17 -4
  302. package/dist/memory/impact/impact-store.js +169 -63
  303. package/dist/memory/intent/inline-intent.d.ts +1 -0
  304. package/dist/memory/intent/intent-shard-store.js +16 -4
  305. package/dist/memory/intent/intent-shard.d.ts +14 -2
  306. package/dist/memory/intent/intent-store.d.ts +1 -0
  307. package/dist/memory/intent/intent-tools.js +122 -4
  308. package/dist/memory/intent/open-intents.d.ts +6 -0
  309. package/dist/memory/intent/open-intents.js +10 -1
  310. package/dist/memory/intent/settled-words.d.ts +24 -0
  311. package/dist/memory/intent/settled-words.js +130 -0
  312. package/dist/memory/journal/drive-flow.d.ts +16 -0
  313. package/dist/memory/journal/drive-flow.js +34 -2
  314. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  315. package/dist/memory/journal/drive-run-flush.js +20 -5
  316. package/dist/memory/journal/envelope.d.ts +8 -8
  317. package/dist/memory/journal/journal-recorder.js +52 -3
  318. package/dist/memory/journal/on-disk/retention.d.ts +8 -0
  319. package/dist/memory/journal/on-disk/retention.js +32 -2
  320. package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
  321. package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
  322. package/dist/memory/journal/session-end.d.ts +15 -1
  323. package/dist/memory/journal/session-end.js +42 -9
  324. package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
  325. package/dist/memory/project/artifact-root-resolver.js +125 -16
  326. package/dist/memory/project/artifact-root.d.ts +46 -8
  327. package/dist/memory/project/artifact-root.js +89 -10
  328. package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
  329. package/dist/memory/project/dir/reticle-dir.js +26 -3
  330. package/dist/memory/project/link-directory.d.ts +15 -0
  331. package/dist/memory/project/link-directory.js +44 -0
  332. package/dist/memory/project/project-tools.js +22 -3
  333. package/dist/memory/project/root-claims.d.ts +6 -0
  334. package/dist/memory/project/root-claims.js +39 -0
  335. package/dist/memory/project/session-root.d.ts +26 -1
  336. package/dist/memory/project/session-root.js +49 -5
  337. package/dist/memory/project/sync-status.d.ts +85 -0
  338. package/dist/memory/project/sync-status.js +224 -0
  339. package/dist/memory/recall/memory-tools.js +47 -2
  340. package/dist/memory/recall/platform-memory.d.ts +34 -0
  341. package/dist/memory/recall/platform-memory.js +139 -0
  342. package/dist/memory/recall/project-memory.d.ts +19 -0
  343. package/dist/memory/recall/project-memory.js +80 -13
  344. package/dist/portal/bridge/bridge.d.ts +9 -3
  345. package/dist/portal/bridge/bridge.js +82 -22
  346. package/dist/portal/bridge/harness-request.d.ts +23 -0
  347. package/dist/portal/bridge/harness-request.js +27 -0
  348. package/dist/portal/bridge/pairing-token.d.ts +9 -0
  349. package/dist/portal/bridge/pairing-token.js +17 -0
  350. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  351. package/dist/portal/bridge/wrong-path.js +35 -0
  352. package/dist/portal/input/network-mock-tools.js +11 -2
  353. package/dist/portal/input/real-input.d.ts +83 -10
  354. package/dist/portal/input/real-input.js +218 -30
  355. package/dist/portal/input/viewport-tools.js +3 -3
  356. package/dist/portal/pool/browser-pool.d.ts +70 -9
  357. package/dist/portal/pool/browser-pool.js +190 -37
  358. package/dist/portal/pool/context-permissions.d.ts +33 -0
  359. package/dist/portal/pool/context-permissions.js +33 -0
  360. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  361. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  362. package/dist/portal/pool/playwright-launcher.d.ts +35 -0
  363. package/dist/portal/pool/playwright-launcher.js +64 -3
  364. package/dist/portal/pool/pool-contract.d.ts +28 -5
  365. package/dist/portal/session/agent-link.d.ts +8 -0
  366. package/dist/portal/session/agent-link.js +17 -0
  367. package/dist/portal/session/command-payload.d.ts +8 -0
  368. package/dist/portal/session/command-payload.js +24 -0
  369. package/dist/portal/session/daemon-answers.d.ts +3 -3
  370. package/dist/portal/session/daemon-answers.js +4 -2
  371. package/dist/portal/session/dev-server/dev-command.d.ts +21 -0
  372. package/dist/portal/session/dev-server/dev-command.js +87 -12
  373. package/dist/portal/session/facts/departure-note.d.ts +22 -0
  374. package/dist/portal/session/facts/departure-note.js +47 -0
  375. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  376. package/dist/portal/session/facts/observed-state.js +46 -3
  377. package/dist/portal/session/facts/session-replaced.d.ts +5 -0
  378. package/dist/portal/session/facts/session-replaced.js +5 -0
  379. package/dist/portal/session/first-run-wiring.d.ts +42 -0
  380. package/dist/portal/session/first-run-wiring.js +132 -0
  381. package/dist/portal/session/human/live-control.d.ts +9 -2
  382. package/dist/portal/session/human/live-control.js +12 -3
  383. package/dist/portal/session/human/notes-ledger.d.ts +20 -0
  384. package/dist/portal/session/human/notes-ledger.js +55 -0
  385. package/dist/portal/session/human/review-store.d.ts +12 -0
  386. package/dist/portal/session/human/review-store.js +18 -10
  387. package/dist/portal/session/live-control-tools.d.ts +0 -13
  388. package/dist/portal/session/live-control-tools.js +107 -13
  389. package/dist/portal/session/narration-args.d.ts +5 -0
  390. package/dist/portal/session/narration-args.js +17 -0
  391. package/dist/portal/session/no-session-diagnosis.d.ts +8 -1
  392. package/dist/portal/session/no-session-diagnosis.js +46 -9
  393. package/dist/portal/session/no-session-next-action.d.ts +31 -0
  394. package/dist/portal/session/no-session-next-action.js +159 -60
  395. package/dist/portal/session/no-session-watch.d.ts +14 -1
  396. package/dist/portal/session/no-session-watch.js +227 -17
  397. package/dist/portal/session/presence/session-lease.js +1 -1
  398. package/dist/portal/session/presence/session-mirror.js +3 -0
  399. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  400. package/dist/portal/session/recorded-gaps.js +251 -0
  401. package/dist/portal/session/serving-directory.d.ts +27 -0
  402. package/dist/portal/session/serving-directory.js +45 -0
  403. package/dist/portal/session/session-health.d.ts +18 -0
  404. package/dist/portal/session/session-health.js +9 -1
  405. package/dist/portal/session/session-info.d.ts +8 -1
  406. package/dist/portal/session/session-info.js +8 -1
  407. package/dist/portal/session/session-manager.d.ts +39 -0
  408. package/dist/portal/session/session-manager.js +98 -11
  409. package/dist/portal/session/session-reaper.js +4 -1
  410. package/dist/portal/session/session-successor.d.ts +13 -0
  411. package/dist/portal/session/session-successor.js +1 -1
  412. package/dist/portal/session/session-tools.js +26 -3
  413. package/dist/portal/session/session.d.ts +22 -30
  414. package/dist/portal/session/session.js +81 -79
  415. package/dist/portal/session/timing/command-timeout.js +25 -1
  416. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  417. package/dist/portal/session/timing/wall-clock.js +1 -1
  418. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  419. package/dist/portal/session/zero-install-first-call.js +88 -0
  420. package/dist/start-options.d.ts +12 -0
  421. package/dist/start-wiring.d.ts +63 -0
  422. package/dist/start-wiring.js +169 -0
  423. package/dist/status-payload.d.ts +23 -1
  424. package/dist/status-payload.js +36 -1
  425. package/dist/surface/http-server.js +18 -2
  426. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  427. package/dist/surface/mcp/attach-memory.js +12 -1
  428. package/dist/surface/mcp/mcp-proxy.d.ts +9 -0
  429. package/dist/surface/mcp/mcp-proxy.js +65 -13
  430. package/dist/surface/mcp/mcp.d.ts +34 -6
  431. package/dist/surface/mcp/mcp.js +61 -17
  432. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  433. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  434. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  435. package/dist/surface/mcp/server-instructions.d.ts +4 -2
  436. package/dist/surface/mcp/server-instructions.js +32 -14
  437. package/dist/surface/mcp/shared-params.js +2 -2
  438. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  439. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  440. package/dist/surface/tools/account-tool.d.ts +22 -0
  441. package/dist/surface/tools/account-tool.js +157 -0
  442. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  443. package/dist/surface/tools/act/act-danger.js +38 -1
  444. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  445. package/dist/surface/tools/act/act-observation.js +57 -0
  446. package/dist/surface/tools/act/act-preflight.js +25 -2
  447. package/dist/surface/tools/act/act-target.js +8 -3
  448. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
  449. package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
  450. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  451. package/dist/surface/tools/act/resolve-target.js +18 -3
  452. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  453. package/dist/surface/tools/act/screen-request.js +113 -0
  454. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  455. package/dist/surface/tools/act/sequence-grade.js +13 -2
  456. package/dist/surface/tools/act/settle-in-flight.js +25 -3
  457. package/dist/surface/tools/act-sequence-tool.js +138 -29
  458. package/dist/surface/tools/act-tools.d.ts +0 -9
  459. package/dist/surface/tools/act-tools.js +71 -41
  460. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  461. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  462. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  463. package/dist/surface/tools/agent/app-notes.js +48 -0
  464. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  465. package/dist/surface/tools/agent/build-staleness.js +62 -0
  466. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  467. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  468. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  469. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  470. package/dist/surface/tools/agent/notices.d.ts +50 -0
  471. package/dist/surface/tools/agent/notices.js +152 -0
  472. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  473. package/dist/surface/tools/agent/reteach.js +50 -0
  474. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  475. package/dist/surface/tools/args/alias-args.js +10 -0
  476. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  477. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  478. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  479. package/dist/surface/tools/assert/assert-source.js +40 -0
  480. package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
  481. package/dist/surface/tools/assert/assert-verdict.js +42 -17
  482. package/dist/surface/tools/browser-tools.js +51 -2
  483. package/dist/surface/tools/chat-drives.d.ts +101 -0
  484. package/dist/surface/tools/chat-drives.js +409 -0
  485. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  486. package/dist/surface/tools/coverage-tools.js +2 -53
  487. package/dist/surface/tools/dynamic-tools.js +29 -1
  488. package/dist/surface/tools/empty-session-list.d.ts +51 -0
  489. package/dist/surface/tools/empty-session-list.js +120 -0
  490. package/dist/surface/tools/error-recovery.d.ts +14 -0
  491. package/dist/surface/tools/error-recovery.js +105 -8
  492. package/dist/surface/tools/explore-tools.d.ts +31 -1
  493. package/dist/surface/tools/explore-tools.js +438 -66
  494. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  495. package/dist/surface/tools/feedback-tools.js +18 -3
  496. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  497. package/dist/surface/tools/gap-novelty.js +8 -1
  498. package/dist/surface/tools/harness-explore.d.ts +118 -57
  499. package/dist/surface/tools/harness-explore.js +344 -292
  500. package/dist/surface/tools/harness-gate.d.ts +88 -0
  501. package/dist/surface/tools/harness-gate.js +235 -0
  502. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  503. package/dist/surface/tools/harness-hunt.js +215 -0
  504. package/dist/surface/tools/harness-plan.d.ts +17 -0
  505. package/dist/surface/tools/harness-plan.js +38 -0
  506. package/dist/surface/tools/harness-script.d.ts +30 -0
  507. package/dist/surface/tools/harness-script.js +560 -0
  508. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  509. package/dist/surface/tools/harness-tab-guard.js +27 -0
  510. package/dist/surface/tools/harness-toolset.d.ts +22 -1
  511. package/dist/surface/tools/harness-toolset.js +101 -7
  512. package/dist/surface/tools/human-notes.d.ts +16 -0
  513. package/dist/surface/tools/human-notes.js +27 -0
  514. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  515. package/dist/surface/tools/invoke-tool.js +263 -85
  516. package/dist/surface/tools/lease-hint.js +26 -5
  517. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  518. package/dist/surface/tools/lease-permissions.js +73 -0
  519. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  520. package/dist/surface/tools/lease-readiness.js +57 -0
  521. package/dist/surface/tools/lease-seed.d.ts +49 -0
  522. package/dist/surface/tools/lease-seed.js +167 -0
  523. package/dist/surface/tools/lease-tools.d.ts +13 -24
  524. package/dist/surface/tools/lease-tools.js +146 -197
  525. package/dist/surface/tools/live-call-text.js +4 -4
  526. package/dist/surface/tools/merge-tools.js +42 -2
  527. package/dist/surface/tools/merged-name-redirect.js +4 -0
  528. package/dist/surface/tools/next-step.d.ts +29 -0
  529. package/dist/surface/tools/next-step.js +214 -0
  530. package/dist/surface/tools/observe-tools.js +45 -9
  531. package/dist/surface/tools/platform-moment.d.ts +72 -0
  532. package/dist/surface/tools/platform-moment.js +296 -0
  533. package/dist/surface/tools/query-hint-schema.d.ts +7 -0
  534. package/dist/surface/tools/query-hint-schema.js +10 -0
  535. package/dist/surface/tools/read-tools.js +71 -14
  536. package/dist/surface/tools/real-input-attempt.js +96 -13
  537. package/dist/surface/tools/reticle-result.d.ts +120 -0
  538. package/dist/surface/tools/reticle-result.js +364 -0
  539. package/dist/surface/tools/tool-kit.d.ts +83 -3
  540. package/dist/surface/tools/tool-kit.js +77 -7
  541. package/dist/surface/tools/tools.js +43 -59
  542. package/dist/telemetry/account-envelope.d.ts +7 -0
  543. package/dist/telemetry/account-envelope.js +61 -0
  544. package/dist/telemetry/agent-client.d.ts +15 -0
  545. package/dist/telemetry/agent-client.js +57 -0
  546. package/dist/telemetry/app-instrumented.js +9 -2
  547. package/dist/telemetry/argument-shape.d.ts +7 -0
  548. package/dist/telemetry/argument-shape.js +86 -1
  549. package/dist/telemetry/automation-hint.d.ts +2 -3
  550. package/dist/telemetry/automation-hint.js +33 -8
  551. package/dist/telemetry/cli-telemetry.js +7 -2
  552. package/dist/telemetry/daemon-telemetry.js +3 -0
  553. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  554. package/dist/telemetry/error-fingerprint.js +61 -5
  555. package/dist/telemetry/feedback-cli.d.ts +0 -13
  556. package/dist/telemetry/feedback-cli.js +0 -77
  557. package/dist/telemetry/feedback.d.ts +13 -0
  558. package/dist/telemetry/feedback.js +183 -17
  559. package/dist/telemetry/harness-run.d.ts +18 -0
  560. package/dist/telemetry/harness-run.js +80 -0
  561. package/dist/telemetry/hud-events.d.ts +16 -0
  562. package/dist/telemetry/hud-events.js +27 -0
  563. package/dist/telemetry/hud-metrics.d.ts +29 -6
  564. package/dist/telemetry/hud-metrics.js +116 -25
  565. package/dist/telemetry/init-telemetry.js +2 -2
  566. package/dist/telemetry/install-source.d.ts +13 -25
  567. package/dist/telemetry/install-source.js +44 -3
  568. package/dist/telemetry/mcp-connection.d.ts +0 -14
  569. package/dist/telemetry/mcp-connection.js +5 -1
  570. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  571. package/dist/telemetry/onboarding-firsts.js +81 -6
  572. package/dist/telemetry/platform-linked.d.ts +5 -0
  573. package/dist/telemetry/platform-linked.js +32 -0
  574. package/dist/telemetry/project-profile.js +5 -3
  575. package/dist/telemetry/proxy-telemetry.js +4 -1
  576. package/dist/telemetry/session-metrics.d.ts +15 -4
  577. package/dist/telemetry/session-metrics.js +88 -52
  578. package/dist/telemetry/telemetry.d.ts +38 -2
  579. package/dist/telemetry/telemetry.js +144 -34
  580. package/dist/telemetry/verification-of.d.ts +3 -1
  581. package/dist/telemetry/verification-of.js +13 -4
  582. package/dist/wire-journal.d.ts +2 -2
  583. package/dist/wire-journal.js +20 -6
  584. package/docs/README.md +3 -3
  585. package/docs/actions.mdx +6 -3
  586. package/docs/adapters.md +1 -1
  587. package/docs/agent-cheatsheet.md +25 -28
  588. package/docs/architecture.md +5 -5
  589. package/docs/autodrive.md +33 -28
  590. package/docs/benchmarks.md +5 -5
  591. package/docs/best-practices.mdx +27 -9
  592. package/docs/capabilities.mdx +14 -16
  593. package/docs/cli/affected.mdx +1 -1
  594. package/docs/cli/cloud.mdx +54 -75
  595. package/docs/cli/doctor.mdx +14 -3
  596. package/docs/cli/drive.mdx +20 -14
  597. package/docs/cli/feedback.mdx +3 -3
  598. package/docs/cli/gate.mdx +7 -2
  599. package/docs/cli/help.mdx +50 -55
  600. package/docs/cli/init.mdx +43 -28
  601. package/docs/cli/license.mdx +12 -8
  602. package/docs/cli/mcp.mdx +4 -4
  603. package/docs/cli/open.mdx +3 -3
  604. package/docs/cli/report.mdx +4 -2
  605. package/docs/cli/restart.mdx +2 -2
  606. package/docs/cli/rollback.mdx +14 -8
  607. package/docs/cli/serve.mdx +4 -4
  608. package/docs/cli/setup.mdx +23 -0
  609. package/docs/cli/status.mdx +18 -5
  610. package/docs/cli/stop.mdx +67 -8
  611. package/docs/cli/try.mdx +62 -0
  612. package/docs/cli/update.mdx +4 -3
  613. package/docs/cli/verify.mdx +17 -6
  614. package/docs/cli/version.mdx +5 -4
  615. package/docs/cli.mdx +111 -42
  616. package/docs/debugging.md +3 -3
  617. package/docs/deploy-checks.md +1 -1
  618. package/docs/desktop.mdx +9 -3
  619. package/docs/enterprise.md +11 -10
  620. package/docs/environment.mdx +7 -8
  621. package/docs/faq.mdx +3 -3
  622. package/docs/first-drive.md +5 -4
  623. package/docs/flows.md +35 -27
  624. package/docs/for-agents.md +4 -5
  625. package/docs/frameworks.mdx +32 -21
  626. package/docs/getting-started.md +65 -61
  627. package/docs/human-control.md +16 -16
  628. package/docs/index.mdx +15 -42
  629. package/docs/install-agentic.mdx +22 -37
  630. package/docs/install-manual.mdx +23 -13
  631. package/docs/instrumentation.mdx +5 -3
  632. package/docs/integration-patterns.md +7 -7
  633. package/docs/license-activation.mdx +1 -1
  634. package/docs/multi-agent-testing.md +24 -6
  635. package/docs/packages/babel-plugin.mdx +4 -2
  636. package/docs/packages/browser.mdx +16 -10
  637. package/docs/packages/core.mdx +12 -5
  638. package/docs/packages/electron.mdx +3 -2
  639. package/docs/packages/engine.mdx +1 -1
  640. package/docs/packages/eslint-plugin.mdx +18 -12
  641. package/docs/packages/next.mdx +8 -7
  642. package/docs/packages/open-verification.mdx +1 -1
  643. package/docs/packages/server.mdx +5 -5
  644. package/docs/packages/tauri.mdx +9 -9
  645. package/docs/packages/test.mdx +4 -10
  646. package/docs/packages/vite-plugin.mdx +32 -4
  647. package/docs/packages.mdx +11 -15
  648. package/docs/platform-integration.md +6 -5
  649. package/docs/predicates.mdx +40 -24
  650. package/docs/quickstart.mdx +69 -30
  651. package/docs/required-checks.md +8 -7
  652. package/docs/reticle-manual.md +15 -5
  653. package/docs/skill-file.mdx +17 -79
  654. package/docs/skill-setup.md +9 -9
  655. package/docs/skill.md +200 -0
  656. package/docs/system-map.md +7 -7
  657. package/docs/telemetry.md +23 -25
  658. package/docs/testing.md +4 -4
  659. package/docs/token-efficiency.md +12 -12
  660. package/docs/tools/act-and-wait.mdx +9 -2
  661. package/docs/tools/act-sequence.mdx +6 -7
  662. package/docs/tools/act.mdx +2 -2
  663. package/docs/tools/assert.mdx +18 -17
  664. package/docs/tools/console.mdx +9 -9
  665. package/docs/tools/inspect.mdx +16 -7
  666. package/docs/tools/look.mdx +24 -0
  667. package/docs/tools/navigate.mdx +5 -3
  668. package/docs/tools/network.mdx +2 -2
  669. package/docs/tools/observe.mdx +6 -6
  670. package/docs/tools/overview.mdx +34 -33
  671. package/docs/tools/query.mdx +5 -5
  672. package/docs/tools/session-and-feedback.mdx +22 -13
  673. package/docs/tools/sessions.mdx +8 -8
  674. package/docs/tools/snapshot.mdx +6 -5
  675. package/docs/tools/state.mdx +9 -9
  676. package/docs/tools/tools-and-run.mdx +26 -24
  677. package/docs/tools/verify.mdx +28 -0
  678. package/docs/tools/wait-for.mdx +8 -4
  679. package/docs/troubleshooting.mdx +21 -6
  680. package/docs/usage.md +55 -46
  681. package/docs/use-cases.mdx +3 -3
  682. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  683. package/docs/vs-playwright-mcp.mdx +3 -1
  684. package/docs/what-is-recorded.md +17 -5
  685. package/docs/what-is-reticle.mdx +5 -3
  686. package/docs/why-reticle.mdx +1 -1
  687. package/package.json +9 -12
  688. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  689. package/dist/command/cli/demo/demo-page.js +0 -241
  690. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  691. package/dist/command/cli/demo/demo-run.js +0 -138
  692. package/dist/features/harness/driver.d.ts +0 -50
  693. package/dist/features/harness/driver.js +0 -236
  694. package/dist/features/harness/jev-driver.d.ts +0 -188
  695. package/dist/features/harness/jev-driver.js +0 -678
  696. package/dist/features/harness/openai-driver.d.ts +0 -58
  697. package/dist/features/harness/openai-driver.js +0 -206
  698. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  699. package/dist/judgement/hunt/hunt-report.js +0 -84
  700. package/dist/language/flows/buddy-status.d.ts +0 -25
  701. package/dist/language/flows/buddy-status.js +0 -32
  702. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  703. package/dist/language/flows/change/watch-batcher.js +0 -19
  704. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  705. package/dist/memory/cloud/harness-offer.js +0 -145
  706. package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
  707. package/dist/memory/project/dir/fill-value-store.js +0 -88
  708. package/dist/surface/tools/feature-capture.d.ts +0 -151
  709. package/dist/surface/tools/feature-capture.js +0 -235
  710. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  711. package/dist/surface/tools/tool-hit-rate.js +0 -90
  712. package/dist/telemetry/harness-drive.d.ts +0 -4
  713. package/dist/telemetry/harness-drive.js +0 -35
  714. package/dist/telemetry/identify.d.ts +0 -22
  715. package/dist/telemetry/identify.js +0 -73
  716. package/docs/cli/capsules.mdx +0 -70
  717. package/docs/cli/hunt.mdx +0 -73
  718. package/docs/cli/identify.mdx +0 -76
  719. package/docs/cli/kill.mdx +0 -91
  720. package/docs/cli/watch.mdx +0 -62
  721. package/docs/local-registry.md +0 -143
@@ -13,6 +13,7 @@ import { fixturePortFor, seedFromStorageState, } from '../../portal/input/storag
13
13
  import { mutationPortFor } from '../../portal/input/network-mutation.js';
14
14
  import { z } from 'zod';
15
15
  import { leaseNotConnectedHint } from './lease-hint.js';
16
+ import { probeLeaseAlive, tabHidden } from './lease-readiness.js';
16
17
  import { probeSdkMarker } from './gaps/sdk-marker-probe.js';
17
18
  import { observeWebDocument } from '../../portal/session/dev-server/served-document.js';
18
19
  import { diagnoseObservedWebCsp } from '@reticlehq/init';
@@ -20,10 +21,13 @@ import { readProjectFramework, readProjectId } from '../../command/cli/ports/res
20
21
  import { hasAnyAppConnectedBefore } from '../../memory/recall/prior/connection-memory.js';
21
22
  import { AGENT_DRIVING_ELSEWHERE, AGENT_DRIVING_HERE_AGAIN, watchersToNotify, } from '../../portal/session/lease-visibility.js';
22
23
  import { reticleStateHome } from '../../command/daemon/daemon.js';
23
- import { LeaseNotReadyReason, REDACTED_VALUE, RETICLE_URL_PARAM, RETICLE_DEFAULT_PORT, ReticleCommand, SeedStorageSchema, scrubKnownSecrets, } from '@reticlehq/core';
24
- import { ReticleTool, SESSION_HEALTH } from '@reticlehq/core';
24
+ import { claimArtifactRoot, dropArtifactRootClaim } from '../../memory/project/root-claims.js';
25
+ import { LeaseNotReadyReason, RETICLE_URL_PARAM, RETICLE_DEFAULT_PORT, SeedStorageSchema, } from '@reticlehq/core';
26
+ import { HudVisibility, ReticleTool, SESSION_HEALTH } from '@reticlehq/core';
27
+ import { HOST_STUB_NOTE } from './tool-kit.js';
25
28
  import { asString } from '@reticlehq/core';
26
- import { chromiumHint } from '../../command/cli/doctor/browser/chromium-hint.js';
29
+ import { chromiumPreflightRefusal } from '../../command/cli/doctor/browser/chromium-hint.js';
30
+ import { LEASE_PERMISSIONS_ARG, hintOf, notificationReadBack, parseLeasePermissions, permissionRefusal, refuseRegrant, } from './lease-permissions.js';
27
31
  /**
28
32
  * Everything the daemon already knows about why a leased tab might not have dialled in.
29
33
  *
@@ -89,19 +93,23 @@ function originOf(url) {
89
93
  const ALREADY_HELD_LEASE = 'you already hold a lease on this origin';
90
94
  function alreadyHeldHint(sessionId, origin) {
91
95
  return (`${ALREADY_HELD_LEASE} (${origin}): ${sessionId} — reused it rather than opening a second ` +
92
- 'tab, which would make every later call require sessionId. Release first if you want a fresh one.');
96
+ 'tab, which would make every later call require sessionId. It is still signed in as whoever ' +
97
+ 'used it last (cookies and storage come with it): release it first for a fresh context or ' +
98
+ 'another identity.');
93
99
  }
94
100
  /**
95
101
  * Append Reticle identity params (__reticle_session, optional __reticle_project) to a URL so the app's own SDK
96
102
  * adopts them on connect. Pure; falls back to plain concatenation if the URL can't be parsed.
97
103
  */
98
- export function appendReticleParams(url, session, projectId) {
104
+ export function appendReticleParams(url, session, projectId, hud) {
99
105
  try {
100
106
  const u = new URL(url);
101
107
  u.searchParams.set(RETICLE_URL_PARAM.SESSION, session);
102
108
  if (projectId !== undefined && projectId.length > 0) {
103
109
  u.searchParams.set(RETICLE_URL_PARAM.PROJECT, projectId);
104
110
  }
111
+ if (hud !== undefined)
112
+ u.searchParams.set(RETICLE_URL_PARAM.HUD, hud);
105
113
  return u.toString();
106
114
  }
107
115
  catch {
@@ -112,124 +120,8 @@ export function appendReticleParams(url, session, projectId) {
112
120
  return `${url}${sep}${RETICLE_URL_PARAM.SESSION}=${encodeURIComponent(session)}${proj}`;
113
121
  }
114
122
  }
115
- function redactExactValue(text, value) {
116
- if (0 === value.length)
117
- return text;
118
- const escaped = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
119
- return text.replace(new RegExp(`(^|[^a-zA-Z0-9])${escaped}(?=$|[^a-zA-Z0-9])`, 'g'), `$1${REDACTED_VALUE}`);
120
- }
121
- /**
122
- * Scrub known secret shapes and raw seedStorage values (cookies, localStorage, sessionStorage)
123
- * from an error string before it reaches daemon logs, metrics, or MCP error responses.
124
- */
125
- export function scrubSeedFromError(text, seed) {
126
- let out = scrubKnownSecrets(text);
127
- if (undefined !== seed && null !== seed && 'object' === typeof seed) {
128
- const s = seed;
129
- const cookies = s['cookies'];
130
- if (undefined !== cookies && null !== cookies) {
131
- if (Array.isArray(cookies)) {
132
- for (const c of cookies) {
133
- if (undefined !== c && null !== c && 'object' === typeof c) {
134
- const val = c['value'];
135
- if (undefined !== val && 'string' === typeof val) {
136
- out = redactExactValue(out, val);
137
- }
138
- }
139
- }
140
- }
141
- else if ('object' === typeof cookies) {
142
- for (const v of Object.values(cookies)) {
143
- if ('string' === typeof v) {
144
- out = redactExactValue(out, v);
145
- }
146
- }
147
- }
148
- }
149
- const local = s['local'];
150
- if (undefined !== local && null !== local && 'object' === typeof local) {
151
- for (const v of Object.values(local)) {
152
- if ('string' === typeof v) {
153
- out = redactExactValue(out, v);
154
- }
155
- }
156
- }
157
- const session = s['session'];
158
- if (undefined !== session && null !== session && 'object' === typeof session) {
159
- for (const v of Object.values(session)) {
160
- if ('string' === typeof v) {
161
- out = redactExactValue(out, v);
162
- }
163
- }
164
- }
165
- }
166
- return out;
167
- }
168
- /** True for a Playwright `storageState()` export (`{ origins: [...] }`), not our seed shape. */
169
- function looksLikeStorageStateExport(seed) {
170
- return Array.isArray(seed?.origins);
171
- }
172
- /**
173
- * Turn a raw navigation failure (Playwright's `page.goto: net::ERR_… at <url>\nCall log:…`, often
174
- * with ANSI codes) into a short, clean reason — so the agent/user sees "is the app running?" instead
175
- * of an internals-leaking wall of text.
176
- */
177
- export function cleanNavError(err, seed) {
178
- const rawMsg = err instanceof Error ? err.message : String(err);
179
- const msg = scrubSeedFromError(rawMsg, seed);
180
- // Strip ANSI color codes (ESC[…m) Playwright emits — built via fromCharCode to keep the
181
- // control character out of a regex literal (no-control-regex).
182
- const ansi = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, 'g');
183
- const firstLine = (msg.split('\n')[0] ?? msg).replace(ansi, '');
184
- const netCode = /net::[A-Z_]+/.exec(firstLine);
185
- if (netCode !== null)
186
- return netCode[0];
187
- if (/timeout/i.test(firstLine))
188
- return 'navigation timed out';
189
- return firstLine
190
- .replace(/^page\.goto:\s*/, '')
191
- .replace(/\s+at\s+https?:\/\/\S+.*$/, '')
192
- .trim()
193
- .slice(0, 100);
194
- }
195
- /**
196
- * Determine if a required seedStorage application precondition failed.
197
- *
198
- * Checks strong signals:
199
- * 1. HTTP 401/403 status on the initial navigation.
200
- * 2. Cross-origin redirect when localStorage or sessionStorage was requested (skipped by origin-scoping).
201
- * 3. Clear redirect to an authentication/login endpoint when the requested URL was not a login page.
202
- *
203
- * Normal app redirects (e.g. / → /dashboard) are valid and return undefined.
204
- */
205
- export function evaluateSeedPrecondition(requestedUrl, actualUrl, seed, navStatus) {
206
- if (401 === navStatus || 403 === navStatus) {
207
- return `HTTP ${navStatus} returned on initial seeded navigation to ${requestedUrl}`;
208
- }
209
- if (actualUrl === undefined || '' === actualUrl.trim())
210
- return undefined;
211
- let reqParsed;
212
- let actParsed;
213
- try {
214
- reqParsed = new URL(requestedUrl);
215
- actParsed = new URL(actualUrl);
216
- }
217
- catch {
218
- return undefined;
219
- }
220
- // Cross-origin redirect when local or session storage was requested
221
- const hasStorage = (undefined !== seed.local && 0 < Object.keys(seed.local).length) ||
222
- (undefined !== seed.session && 0 < Object.keys(seed.session).length);
223
- if (hasStorage && reqParsed.origin !== actParsed.origin) {
224
- return `seeded storage precondition not established: cross-origin redirect from ${reqParsed.origin} to ${actParsed.origin} skipped origin-scoped storage injection`;
225
- }
226
- // Clear redirect to an authentication/login endpoint when the requested URL was not a login page
227
- const isAuthPath = (pathname) => /(?:^|\/)(?:login|signin|sign-in|auth\/login|auth\/signin|session\/new)(?:$|\/)/i.test(pathname);
228
- if (!isAuthPath(reqParsed.pathname) && isAuthPath(actParsed.pathname)) {
229
- return `seeded authentication precondition not established: redirected from ${reqParsed.pathname} to login page (${actParsed.pathname})`;
230
- }
231
- return undefined;
232
- }
123
+ export { cleanNavError, evaluateSeedPrecondition, scrubSeedFromError } from './lease-seed.js';
124
+ import { evaluateSeedPrecondition, looksLikeStorageStateExport, navFailureMessage, scrubSeedFromError, } from './lease-seed.js';
233
125
  /** A fresh, collision-resistant lease id. Uses crypto at the I/O boundary (not pure logic). */
234
126
  function newLeaseId() {
235
127
  const uuid = 'function' === typeof globalThis.crypto?.randomUUID
@@ -300,46 +192,6 @@ function sessionParamOf(url) {
300
192
  }
301
193
  const LEASE_READY_ATTEMPTS = 100;
302
194
  const LEASE_READY_POLL_MS = 100;
303
- /**
304
- * How long a liveness probe waits for the tab to say anything at all.
305
- *
306
- * Short on purpose. This is not "finish the work", it is "are you there" — a page executing
307
- * JavaScript answers a no-argument command in single-digit milliseconds, and a wedged one is not
308
- * going to answer in two seconds either.
309
- */
310
- const LEASE_PROBE_TIMEOUT_MS = 1_500;
311
- /**
312
- * Does this tab still answer?
313
- *
314
- * PRESENCE IS NOT LIVENESS. The sessions map still holds a tab that is attached, streaming events,
315
- * and answering nothing, so `ready` read off a row in that map hands back a lease that `snapshot`,
316
- * `state` and `console` then reject (#692). It has to mean the tab replied.
317
- *
318
- * ANY reply counts, including one that reports the command failed. The question is whether the SDK
319
- * answers at all, not what it says — so an SDK too old to know the command replies
320
- * `unknown command '…'`, and that is proof. Only the absence of a reply is evidence of absence:
321
- * `PendingCommands.track` REJECTS on timeout and on a dropped socket, and resolves on every real
322
- * answer, so the two cases are already separated for us.
323
- *
324
- * `CAPABILITIES` is the probe because it takes no arguments and returns a small fixed list. No new
325
- * wire command is introduced: this rides an existing round trip.
326
- *
327
- * Fails OPEN. A registry entry with no `command` is a shape this code did not put there, and
328
- * turning a lease that works into a refusal over a probe that could not run would be a worse
329
- * failure than the one being fixed.
330
- */
331
- async function probeLeaseAlive(session, timeoutMs = LEASE_PROBE_TIMEOUT_MS) {
332
- const send = session?.command;
333
- if (send === undefined)
334
- return true;
335
- try {
336
- await send.call(session, ReticleCommand.CAPABILITIES, {}, timeoutMs);
337
- return true;
338
- }
339
- catch {
340
- return false;
341
- }
342
- }
343
195
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
344
196
  /**
345
197
  * Poll until the leased tab's SDK has actually registered on the bridge, so the sessionId we return
@@ -428,7 +280,7 @@ export function hasOriginLock(origin) {
428
280
  }
429
281
  export const LEASE_ACQUIRE_TOOL = {
430
282
  name: ReticleTool.LEASE_ACQUIRE,
431
- description: 'Lease a fresh isolated headless browser context from the shared pool 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.',
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.',
432
284
  inputSchema: {
433
285
  url: z
434
286
  .string()
@@ -437,22 +289,51 @@ export const LEASE_ACQUIRE_TOOL = {
437
289
  .string()
438
290
  .optional()
439
291
  .describe('Stable project id to stamp on the leased tab so the agent can scope to it.'),
440
- seedStorage: SeedStorageSchema.optional().describe('Initial storage state (localStorage, sessionStorage, cookies) to seed before the first navigation (e.g. to start already authenticated).'),
292
+ seedStorage: SeedStorageSchema.optional().describe('Initial storage state (local, session and cookies) to seed before the first navigation (e.g. `seedStorage: { local: { token: "..." } }` to start already authenticated).'),
293
+ initScript: z
294
+ .string()
295
+ .optional()
296
+ .describe("JavaScript installed in the tab BEFORE any of the page's own scripts run. Use it for TEST DOUBLES of the host bindings a desktop shell injects — Wails `window.go.*`, Tauri `window.runtime`/`__TAURI_INTERNALS__`, an Electron preload object — so a view that calls them on mount is driven against the stub instead of throwing. It stays on for this lease only, and it is disposed with the lease. Every verdict on this lease carries a note that a stub was installed, so a green is never read as one against the real shell."),
297
+ headed: z
298
+ .boolean()
299
+ .optional()
300
+ .describe('Open it in a browser window somebody can watch, instead of headless.'),
301
+ ignoreHTTPSErrors: z
302
+ .boolean()
303
+ .optional()
304
+ .describe('Accept a self-signed or mkcert certificate on an https dev server, for this lease only. Off by default.'),
305
+ hud: z
306
+ .enum([HudVisibility.SHOWN, HudVisibility.HIDDEN, HudVisibility.REMOVED])
307
+ .optional()
308
+ .describe('How the HUD starts on the page: shown (default), hidden, or removed.'),
309
+ permissions: LEASE_PERMISSIONS_ARG,
310
+ root: z
311
+ .string()
312
+ .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."),
441
314
  },
442
315
  outputSchema: {
443
316
  sessionId: z.string(),
444
317
  url: z.string(),
445
318
  ready: z
446
319
  .boolean()
447
- .describe('Whether the leased tab is connected AND answering. On a reused lease this is probed, not assumed — a row in the session map is presence, not liveness. False ⇒ read notReadyReason.'),
320
+ .describe('Whether the leased tab is connected AND answering. It is NOT a claim that the app has hydrated, so an act can miss: make the first act reticle_act_and_wait with an `until`, or reticle_assert { action: "wait" }. Empty reads may mean not hydrated. False ⇒ read notReadyReason.'),
448
321
  zeroInstall: z
449
322
  .boolean()
450
323
  .optional()
451
324
  .describe('Present when this app ships no Reticle SDK and the lease supplied one. Verdicts work on the DOM, network, console and routes; there is no framework adapter, so no component state and no source file:line. Install with `npx @reticlehq/server init` for those.'),
325
+ hostStub: z
326
+ .string()
327
+ .optional()
328
+ .describe('Present when this leased tab runs an init script stubbing the bindings a desktop shell injects. Verdicts on this lease are about the app with that stub, not about the real shell.'),
452
329
  notReadyReason: z
453
- .enum([LeaseNotReadyReason.SDK_NEVER_DIALLED, LeaseNotReadyReason.SDK_STOPPED_ANSWERING])
330
+ .enum([
331
+ LeaseNotReadyReason.SDK_NEVER_DIALLED,
332
+ LeaseNotReadyReason.SDK_STOPPED_ANSWERING,
333
+ LeaseNotReadyReason.TAB_HIDDEN,
334
+ ])
454
335
  .optional()
455
- .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.'),
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.'),
456
337
  expiresInMs: z
457
338
  .number()
458
339
  .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.'),
@@ -487,12 +368,18 @@ export const LEASE_ACQUIRE_TOOL = {
487
368
  // fine. Say the real thing at the first refusal instead. The phrasing carries "Chromium is not
488
369
  // installed" so error-recovery routes it to the NO_POOL fix (install + drive a human tab).
489
370
  if (deps.browserProbe !== undefined) {
490
- const probe = await deps.browserProbe();
491
- if (!probe.exists) {
492
- throw new Error(`Chromium is not installed for Playwright — ${chromiumHint(probe)}`);
493
- }
371
+ const refusal = chromiumPreflightRefusal(await deps.browserProbe());
372
+ if (refusal !== undefined)
373
+ throw new Error(refusal);
494
374
  }
495
375
  const projectId = asString(args['projectId']);
376
+ const root = asString(args['root']);
377
+ const headed = true === args['headed'];
378
+ const hud = Object.values(HudVisibility).find((v) => v === args['hud']);
379
+ const permissions = parseLeasePermissions(args['permissions']);
380
+ // The stub of the shell bindings, when the caller supplied one. Installed by the pool before
381
+ // the first navigation, so it is already defined when the app's first module runs.
382
+ const initScript = asString(args['initScript']);
496
383
  const seedStorageArg = args['seedStorage'];
497
384
  let validatedSeed;
498
385
  if (seedStorageArg !== undefined) {
@@ -526,10 +413,33 @@ export const LEASE_ACQUIRE_TOOL = {
526
413
  await priorLock.catch(() => undefined);
527
414
  }
528
415
  try {
529
- const existing = origin === undefined ? undefined : pool.leaseIdOnOrigin?.(origin);
530
- if (validatedSeed !== undefined && existing !== undefined) {
531
- // Caller explicitly requested storage seeding: do not reuse an existing context on this origin,
532
- // release it so the new lease starts clean with the caller-provided state.
416
+ // Only a lease THIS caller took: another agent's tab is never reused or released (#1226).
417
+ // A window asked for is never answered with the headless tab on that origin, nor the reverse.
418
+ // A held lease that already runs the SAME stub is exactly what the caller asked for, so it is
419
+ // left alone and reused below — releasing it would throw away the tab, and everything loaded
420
+ // in it, for nothing. A lease with no stub, or with a different one, is released FIRST instead:
421
+ // an init script has to exist before the page's own scripts run, which a loaded page cannot
422
+ // do, and the resolve below then finds nothing and mints a fresh context with the stub. A
423
+ // lease of the other kind is left alone, exactly as it is when a window was asked for.
424
+ const heldForStub = origin === undefined ? undefined : pool.leaseIdOnOrigin(origin, deps.attachId);
425
+ if (initScript !== undefined &&
426
+ heldForStub !== undefined &&
427
+ pool.isHeaded(heldForStub) === headed &&
428
+ pool.hostStubScript?.(heldForStub) !== initScript) {
429
+ await pool.release(heldForStub);
430
+ }
431
+ const held = origin === undefined ? undefined : pool.leaseIdOnOrigin(origin, deps.attachId);
432
+ const existing = held !== undefined && pool.isHeaded(held) === headed ? held : undefined;
433
+ // A context's certificate setting is fixed when it is made, so an explicit request for the
434
+ // other one cannot be answered by the held lease: handing it back would keep checks off after
435
+ // `false`, or keep a local certificate refused after `true` (#1255). Omitted keeps the lease.
436
+ const certAsked = args['ignoreHTTPSErrors'];
437
+ const certMismatch = existing !== undefined &&
438
+ 'boolean' === typeof certAsked &&
439
+ pool.ignoresHTTPSErrors(existing) !== certAsked;
440
+ if ((validatedSeed !== undefined || certMismatch) && existing !== undefined) {
441
+ // Seeding or a different certificate setting asked for: release its own context so the new
442
+ // lease starts with what was asked.
533
443
  await pool.release(existing);
534
444
  }
535
445
  else if (existing !== undefined && origin !== undefined) {
@@ -546,23 +456,33 @@ export const LEASE_ACQUIRE_TOOL = {
546
456
  // A no-op when the id resolved to itself; load-bearing when it did not, because every later
547
457
  // touch and release arrives under the id being handed back here.
548
458
  pool.alias(resolved, existing);
459
+ refuseRegrant(pool, existing, permissions);
549
460
  pool.touch(existing);
550
461
  // Probed only HERE, never on the mint path below. There, the readiness wait resolved
551
462
  // moments ago and IS the liveness evidence; on reuse the last evidence may be minutes
552
463
  // old, or there may be none at all — `unresponsive` is set by past commands failing, and
553
464
  // its own contract says absence means "answering, OR NOT ASKED YET". So the happy path of
554
465
  // a first acquire pays nothing for this.
555
- const alive = await probeLeaseAlive(deps.sessions.get(resolved));
466
+ 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;
556
473
  return {
557
474
  sessionId: resolved,
558
475
  url,
559
- ready: alive,
560
- ...(alive ? {} : { notReadyReason: LeaseNotReadyReason.SDK_STOPPED_ANSWERING }),
476
+ ready: reuseReason === undefined,
477
+ ...(reuseReason === undefined ? {} : { notReadyReason: reuseReason }),
561
478
  reused: true,
562
479
  expiresInMs: pool.leaseTtlMs(),
563
480
  leased: pool.activeCount(),
564
481
  queued: pool.queuedCount(),
565
482
  hint: alreadyHeldHint(resolved, origin),
483
+ // Asked of the pool, not remembered here: the stub was installed when THIS lease was
484
+ // minted, and the caller reusing it now may be seeing it for the first time.
485
+ ...(true === pool.stubInstalled?.(existing) ? { hostStub: HOST_STUB_NOTE } : {}),
566
486
  ...(alreadyOpen === undefined
567
487
  ? {}
568
488
  : { preferExisting: { sessionId: alreadyOpen, note: PREFER_EXISTING_NOTE } }),
@@ -574,21 +494,32 @@ export const LEASE_ACQUIRE_TOOL = {
574
494
  await pool.release(existing);
575
495
  }
576
496
  const sessionId = newLeaseId();
577
- const navUrl = appendReticleParams(url, sessionId, projectId);
497
+ // Before the page can dial in: the session is stamped with its root the moment it registers.
498
+ if (root !== undefined)
499
+ claimArtifactRoot(sessionId, root);
500
+ const navUrl = appendReticleParams(url, sessionId, projectId, hud);
578
501
  let lease;
579
502
  try {
580
503
  lease = await pool.acquire(navUrl, {
581
504
  sessionId,
505
+ ...(headed ? { headed } : {}),
506
+ ...(deps.attachId === undefined ? {} : { owner: deps.attachId }),
582
507
  ...(validatedSeed !== undefined ? { seedStorage: validatedSeed } : {}),
508
+ ...(initScript !== undefined ? { initScript } : {}),
509
+ ...(permissions !== undefined ? { permissions } : {}),
510
+ ...(true === args['ignoreHTTPSErrors'] ? { ignoreHTTPSErrors: true } : {}),
583
511
  });
584
512
  }
585
513
  catch (err) {
514
+ const refusal = permissionRefusal(err);
515
+ if (refusal !== undefined)
516
+ throw refusal;
586
517
  if (err instanceof Error && err.message.startsWith('Storage seeding failed')) {
587
518
  throw new Error(scrubSeedFromError(err.message, validatedSeed));
588
519
  }
589
520
  // A raw page.goto failure is noisy and leaks the internal URL params — surface a clean,
590
- // actionable message instead.
591
- throw new Error(`could not open ${url} — is the app running there? (${cleanNavError(err, validatedSeed)})`);
521
+ // actionable message instead, one that tells a slow first compile from a missing app.
522
+ throw new Error(navFailureMessage(url, err, validatedSeed));
592
523
  }
593
524
  // Wait for the leased tab's SDK to connect so the returned sessionId is usable right away.
594
525
  // Resolved rather than assumed: an app that names its own session registers under that name,
@@ -616,15 +547,21 @@ export const LEASE_ACQUIRE_TOOL = {
616
547
  tellWatchers(deps, projectId, AGENT_DRIVING_ELSEWHERE);
617
548
  // ready means the SDK dialled in — not that contracts match. Carry the skew warning on acquire
618
549
  // 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;
619
555
  const versionSkew = registeredId === undefined ? undefined : deps.sessions.get(registeredId)?.versionSkew;
620
556
  return {
621
557
  sessionId: registeredId ?? lease.sessionId,
622
558
  url,
623
- ready,
559
+ ready: mintReason === undefined,
624
560
  // The other half of the pair. `ready: false` carried two opposite situations under one
625
561
  // word: no SDK ever dialled in (look at the install) versus one dialled in and stopped
626
- // answering (recover the tab). They want different next actions, so they get names.
627
- ...(ready ? {} : { notReadyReason: LeaseNotReadyReason.SDK_NEVER_DIALLED }),
562
+ // answering (recover the tab). They want different next actions, so they get names — and so
563
+ // does a third: dialled in and answering, but hidden, so nothing on it verifies (#1351).
564
+ ...(mintReason === undefined ? {} : { notReadyReason: mintReason }),
628
565
  ...(zeroInstall ? { zeroInstall: true } : {}),
629
566
  expiresInMs: pool.leaseTtlMs(),
630
567
  leased: pool.activeCount(),
@@ -638,9 +575,10 @@ export const LEASE_ACQUIRE_TOOL = {
638
575
  },
639
576
  }),
640
577
  ...(versionSkew === undefined ? {} : { versionSkew }),
641
- ...(ready
642
- ? {}
643
- : { hint: await notConnectedHint(deps, url, pool.dialFailureUrl?.(lease.sessionId)) }),
578
+ ...(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),
644
582
  };
645
583
  }
646
584
  finally {
@@ -680,17 +618,28 @@ const LEASE_RELEASE_TOOL = {
680
618
  if (sessionId === undefined || 0 === sessionId.length) {
681
619
  throw new Error('reticle_lease{action:"release"} requires a sessionId');
682
620
  }
683
- // Read the project BEFORE releasing: afterwards the session is gone and there is nothing to
684
- // ask which project it belonged to.
685
- const projectId = deps.sessions.get(sessionId)?.projectId;
686
- await pool.release(sessionId);
687
- // Only once the LAST lease is gone. Announcing "live again" while another lease still drives
688
- // would be a lie, and a HUD that says the wrong thing is worse than one that says nothing.
689
- if (0 === pool.activeCount())
690
- tellWatchers(deps, projectId, AGENT_DRIVING_HERE_AGAIN);
691
- return { released: true, leased: pool.activeCount() };
621
+ return { released: true, leased: await releaseLease(deps, pool, sessionId) };
692
622
  },
693
623
  };
624
+ /**
625
+ * Release one lease and everything that hangs off it. Returns how many leases are still held.
626
+ *
627
+ * Shared with `reticle_session { action: "end" }`: an ended session that kept its lease stayed
628
+ * connected until the reaper took it, and every id-less call from the next agent was refused as
629
+ * ambiguous in the meantime.
630
+ */
631
+ export async function releaseLease(deps, pool, sessionId) {
632
+ // Read the project BEFORE releasing: afterwards the session is gone and there is nothing to
633
+ // ask which project it belonged to.
634
+ const projectId = deps.sessions.get(sessionId)?.projectId;
635
+ await pool.release(sessionId);
636
+ dropArtifactRootClaim(sessionId);
637
+ // Only once the LAST lease is gone. Announcing "live again" while another lease still drives
638
+ // would be a lie, and a HUD that says the wrong thing is worse than one that says nothing.
639
+ if (0 === pool.activeCount())
640
+ tellWatchers(deps, projectId, AGENT_DRIVING_HERE_AGAIN);
641
+ return pool.activeCount();
642
+ }
694
643
  /**
695
644
  * What to say when a lease was taken while a real tab was already open.
696
645
  *
@@ -42,13 +42,13 @@ const NO_TOOL_EQUIVALENT = [
42
42
  // hint used to put `action` and `url` beside `tool`, which reticle_run refuses, and a `[^}]*\}`
43
43
  // body stopped at the inner brace and left ` }` behind once the hint was corrected.
44
44
  pattern: /`?reticle_run\s*\{\s*tool:\s*\\?"reticle_lease\\?"(?:[^{}]|\{[^{}]*\})*\}`?(\s*\([^)]*\))?(\s*[-\u2014]+\s*reticle_lease is[^.]*\.)?/g,
45
- instead: 'the CLI: `reticle open <url>` (a human can equivalently run `reticle drive <url>`)',
45
+ instead: 'the CLI: `npx @reticlehq/server open <url>` (a human can equivalently run `npx @reticlehq/server drive <url>`)',
46
46
  },
47
47
  {
48
48
  needs: [ReticleTool.LEASE],
49
49
  // The bare cross-reference, left behind once the call above is gone.
50
50
  pattern: /\breticle_lease\s*\{[^}]*\}/g,
51
- instead: '`reticle open <url>`',
51
+ instead: '`npx @reticlehq/server open <url>`',
52
52
  },
53
53
  {
54
54
  needs: [ReticleTool.FLOW],
@@ -80,8 +80,8 @@ const NO_TOOL_EQUIVALENT = [
80
80
  * every session, and the longer two-route version cost 67 bytes there against a budget measured
81
81
  * in whole-session terms — for advice that is read once, on a first run.
82
82
  *
83
- * `explore` needs ANTHROPIC_API_KEY and says so itself when it is missing, naming the fallback in
84
- * the same breath ("flows are recorded by your own coding agent through the MCP tools"). That
83
+ * `explore` runs on the platform and says so itself when it is not linked, naming the fallback in
84
+ * the same breath (drive the journey yourself with the MCP tools). That
85
85
  * error is now recognised as ours, so the reader who hits it gets the next step instead of an
86
86
  * invitation to file a defect report. One hop, and every hop is honest.
87
87
  */
@@ -1,6 +1,34 @@
1
1
  import { z } from 'zod';
2
+ import { allowParamValues } from '../../telemetry/argument-shape.js';
2
3
  /** The field the merged tool dispatches on. A member may not declare one of its own — see below. */
3
4
  const DISCRIMINATOR = 'action';
5
+ /**
6
+ * Keys a member may receive without declaring them. `sessionId` is pinned onto the arguments by the
7
+ * dispatch routes (`reticle_run`, the harness toolset) whatever the member, so refusing it would
8
+ * refuse the routes themselves.
9
+ */
10
+ const SHARED_KEYS = new Set(['sessionId']);
11
+ /**
12
+ * The refusal for keys another action of this tool takes (#1536).
13
+ *
14
+ * The SDK checks unknown keys against the UNION of every action's parameters, so a key that belongs
15
+ * to a sibling action passed, reached a handler that does not read it, and was dropped:
16
+ * `verify { action: "change", names }` replayed every affected flow, and `look { action: "page",
17
+ * limit }` returned the whole tree. Same words as the unknown-key refusal, plus the action that
18
+ * does take each key, which is the correction the caller needs.
19
+ */
20
+ function strayKeysRefusal(tool, action, stray, actions) {
21
+ const owners = stray.map((key) => {
22
+ const takes = Object.entries(actions)
23
+ .filter(([, member]) => key in member.inputSchema)
24
+ .map(([name]) => `"${name}"`);
25
+ return `\`${key}\` is a parameter of action ${takes.join(' or ')}`;
26
+ });
27
+ const declared = Object.keys(actions[action]?.inputSchema ?? {}).join(', ');
28
+ return (`${tool} { action: "${action}" } does not take ${stray.map((k) => `\`${k}\``).join(', ')}, ` +
29
+ 'so it was NOT applied — a result computed without it would look like an answer. ' +
30
+ `${owners.join('; ')}. Action "${action}" takes: ${declared}.`);
31
+ }
4
32
  /** The union of member input shapes, every field optional so one schema serves every action. */
5
33
  function unionShape(actions) {
6
34
  const shape = {};
@@ -82,6 +110,8 @@ export function mergeTools(spec) {
82
110
  const actionNames = Object.keys(spec.actions);
83
111
  if (0 === actionNames.length)
84
112
  throw new Error(`mergeTools(${spec.name}): no actions`);
113
+ // Our own action names: telemetry may report them by value rather than as `other`.
114
+ allowParamValues(DISCRIMINATOR, actionNames);
85
115
  refuseDiscriminatorCollision(spec.name, spec.actions);
86
116
  if (spec.defaultAction !== undefined && !(spec.defaultAction in spec.actions)) {
87
117
  throw new Error(`mergeTools(${spec.name}): defaultAction '${spec.defaultAction}' is not one of its actions`);
@@ -94,7 +124,7 @@ export function mergeTools(spec) {
94
124
  [DISCRIMINATOR]: discriminatorSchema(actionNames, spec.defaultAction),
95
125
  ...unionShape(spec.actions),
96
126
  },
97
- handler: (deps, args) => {
127
+ handler: (deps, args, call) => {
98
128
  const named = args[DISCRIMINATOR];
99
129
  const action = 'string' === typeof named ? named : spec.defaultAction;
100
130
  const chosen = action === undefined ? undefined : spec.actions[action];
@@ -104,7 +134,17 @@ export function mergeTools(spec) {
104
134
  expected: actionNames,
105
135
  });
106
136
  }
107
- return chosen.handler(deps, args);
137
+ // A key no action declares is refused before this, against the union; one that another action
138
+ // declares is refused here, against the action that was chosen.
139
+ const stray = Object.keys(args).filter((key) => DISCRIMINATOR !== key &&
140
+ !SHARED_KEYS.has(key) &&
141
+ !(key in chosen.inputSchema) &&
142
+ args[key] !== undefined &&
143
+ Object.values(spec.actions).some((member) => key in member.inputSchema));
144
+ if (0 < stray.length && action !== undefined) {
145
+ return Promise.reject(new Error(strayKeysRefusal(spec.name, action, stray, spec.actions)));
146
+ }
147
+ return chosen.handler(deps, args, call);
108
148
  },
109
149
  };
110
150
  }
@@ -77,6 +77,10 @@ export function mergedNameRedirect(name) {
77
77
  export function retiredToolNames() {
78
78
  const tombstones = {};
79
79
  for (const [old, redirect] of BY_OLD_NAME) {
80
+ // A bare call that redirects to an action on the SAME tool (`reticle_assert` → `{ action: "now" }`)
81
+ // is a live tool, not a retired one. Listing it here told every reader not to use it.
82
+ if (old === redirect.tool)
83
+ continue;
80
84
  tombstones[old] =
81
85
  redirect.action === undefined
82
86
  ? `retired; ${redirect.note ?? `use ${redirect.tool}`}`
@@ -0,0 +1,29 @@
1
+ export declare const NextText: {
2
+ readonly DECLARE: "Record what the user asked, once per task, verbatim: reticle_run { tool: \"reticle_intent\", args: { action: \"declare\", request: \"<their words>\" } }. It travels with every run.";
3
+ readonly SYNC_PROBLEM: (why: string) => string;
4
+ readonly FINISH_LINKED: "Done driving? reticle_session { action: \"yield\" } hands the tab back; this run syncs to the platform on its own.";
5
+ readonly FINISH: "Done driving? reticle_session { action: \"yield\" } hands the tab back.";
6
+ /**
7
+ * The evidence of this app is landing outside any project, so nothing will send it. A second
8
+ * checkout's runs and flows went to `~/.reticle/unmatched/<id>` and the agent was told nothing.
9
+ */
10
+ readonly UNMATCHED: (root: string, contenders: readonly string[], serving?: string) => string;
11
+ readonly REPLAY: (flows: number) => string;
12
+ };
13
+ /** Tests only. */
14
+ export declare function resetNextStep(): void;
15
+ export interface NextStepInput {
16
+ tool: string;
17
+ /** Where this app's evidence goes when no project claims it, and the folders that compete for it. */
18
+ unmatched?: {
19
+ root: string;
20
+ contenders: readonly string[];
21
+ serving?: string;
22
+ } | undefined;
23
+ /** Whether this result carries a verdict. */
24
+ verdict: boolean;
25
+ root: string | undefined;
26
+ now: number;
27
+ }
28
+ /** The line, or undefined when there is nothing the agent should be told right now. */
29
+ export declare function nextStep(input: NextStepInput): string | undefined;