@reticlehq/server 3.6.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 (614) hide show
  1. package/SKILL.md +122 -123
  2. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  3. package/dist/command/cli/adhoc-suite.js +42 -7
  4. package/dist/command/cli/adhoc-verdict.d.ts +18 -2
  5. package/dist/command/cli/adhoc-verdict.js +70 -6
  6. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  7. package/dist/command/cli/answers/gate-exit.js +45 -0
  8. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  9. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  10. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  11. package/dist/command/cli/auth/device-flow.js +17 -0
  12. package/dist/command/cli/cli-doctor.js +14 -0
  13. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  14. package/dist/command/cli/cli-flow-commands.js +28 -105
  15. package/dist/command/cli/cli-kill.js +3 -2
  16. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  17. package/dist/command/cli/cli-parse-grammar.js +75 -0
  18. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  19. package/dist/command/cli/cli-parse-verify.js +18 -0
  20. package/dist/command/cli/cli-parse.d.ts +19 -28
  21. package/dist/command/cli/cli-parse.js +82 -182
  22. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  23. package/dist/command/cli/cli-update-commands.js +61 -9
  24. package/dist/command/cli/cli-usage.d.ts +33 -0
  25. package/dist/command/cli/cli-usage.js +287 -0
  26. package/dist/command/cli/cli-verify.d.ts +34 -4
  27. package/dist/command/cli/cli-verify.js +81 -12
  28. package/dist/command/cli/cloud-cli.d.ts +13 -0
  29. package/dist/command/cli/cloud-cli.js +145 -333
  30. package/dist/command/cli/cloud-kit.d.ts +12 -0
  31. package/dist/command/cli/cloud-kit.js +41 -2
  32. package/dist/command/cli/cloud-link.d.ts +57 -0
  33. package/dist/command/cli/cloud-link.js +308 -0
  34. package/dist/command/cli/cloud-login.d.ts +15 -1
  35. package/dist/command/cli/cloud-login.js +67 -13
  36. package/dist/command/cli/context-command.d.ts +1 -0
  37. package/dist/command/cli/context-command.js +33 -0
  38. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  39. package/dist/command/cli/daemon-start-options.js +24 -3
  40. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  41. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  42. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  43. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  44. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  45. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  46. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  47. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  48. package/dist/command/cli/known-regression.d.ts +13 -0
  49. package/dist/command/cli/known-regression.js +34 -0
  50. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  51. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  52. package/dist/command/cli/lifecycle/daemon-lifecycle.js +11 -2
  53. package/dist/command/cli/mcp-command.d.ts +6 -0
  54. package/dist/command/cli/mcp-command.js +13 -5
  55. package/dist/command/cli/ports/port-holder.js +1 -1
  56. package/dist/command/cli/project-name.d.ts +29 -1
  57. package/dist/command/cli/project-name.js +107 -2
  58. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  59. package/dist/command/cli/setup-mcp-cli.js +29 -8
  60. package/dist/command/cli/status/status-lines.d.ts +1 -0
  61. package/dist/command/cli/status/status-lines.js +47 -2
  62. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  63. package/dist/command/cli/status/workspace-links.js +29 -0
  64. package/dist/command/cli/try-command.d.ts +96 -0
  65. package/dist/command/cli/try-command.js +362 -0
  66. package/dist/command/cli/tutorial.d.ts +0 -100
  67. package/dist/command/cli/tutorial.js +0 -178
  68. package/dist/command/cli/verify-results.d.ts +19 -0
  69. package/dist/command/cli/verify-results.js +29 -0
  70. package/dist/command/cli-onboarding.d.ts +0 -11
  71. package/dist/command/cli-onboarding.js +0 -15
  72. package/dist/command/cli.d.ts +14 -0
  73. package/dist/command/cli.js +103 -83
  74. package/dist/command/daemon/daemon-resilience.js +4 -4
  75. package/dist/command/daemon/daemon-resolve.d.ts +9 -1
  76. package/dist/command/daemon/daemon-resolve.js +49 -10
  77. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  78. package/dist/command/setup/bringup/bridge-port.js +13 -3
  79. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  80. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  81. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  82. package/dist/command/setup/init/agent-restart.js +28 -0
  83. package/dist/command/setup/init/init-port.d.ts +10 -1
  84. package/dist/command/setup/init/init-port.js +22 -2
  85. package/dist/command/setup/init/init-runtime.d.ts +12 -2
  86. package/dist/command/setup/init/init-runtime.js +96 -37
  87. package/dist/command/setup/node-effects.d.ts +2 -0
  88. package/dist/command/setup/node-effects.js +36 -8
  89. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  90. package/dist/command/setup/probe/existing-app.js +14 -0
  91. package/dist/command/setup/remaining-steps.js +1 -1
  92. package/dist/command/setup/run-setup.d.ts +29 -9
  93. package/dist/command/setup/run-setup.js +34 -28
  94. package/dist/command/setup/setup-command.d.ts +23 -0
  95. package/dist/command/setup/setup-command.js +57 -4
  96. package/dist/command/setup/setup-mcp.js +25 -2
  97. package/dist/command/setup/tauri-signing.d.ts +19 -0
  98. package/dist/command/setup/tauri-signing.js +79 -0
  99. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  100. package/dist/command/setup/terminal/listeners.js +37 -6
  101. package/dist/command/update/update-nudge.d.ts +9 -0
  102. package/dist/command/update/update-nudge.js +1 -1
  103. package/dist/command/update/updater.js +11 -15
  104. package/dist/command/version/version-nudge.js +3 -0
  105. package/dist/command/version/version-skew.d.ts +20 -1
  106. package/dist/command/version/version-skew.js +38 -2
  107. package/dist/features/crawl/crawl.js +14 -1
  108. package/dist/features/exhaust/ledger.d.ts +14 -14
  109. package/dist/features/harness/drive-report.d.ts +39 -5
  110. package/dist/features/harness/drive-report.js +271 -54
  111. package/dist/features/harness/drive-runs.d.ts +120 -0
  112. package/dist/features/harness/drive-runs.js +289 -0
  113. package/dist/features/harness/drivers.d.ts +1 -1
  114. package/dist/features/harness/drivers.js +1 -1
  115. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  116. package/dist/features/harness/explore/console-pages.js +146 -0
  117. package/dist/features/harness/explore/disparity.d.ts +19 -0
  118. package/dist/features/harness/explore/disparity.js +71 -0
  119. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  120. package/dist/features/harness/explore/fake-app.js +49 -0
  121. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  122. package/dist/features/harness/explore/goal-search.js +144 -0
  123. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  124. package/dist/features/harness/explore/page-tree.js +148 -0
  125. package/dist/features/harness/explore/site-map.d.ts +34 -0
  126. package/dist/features/harness/explore/site-map.js +150 -0
  127. package/dist/features/harness/goals.d.ts +68 -7
  128. package/dist/features/harness/goals.js +289 -36
  129. package/dist/features/harness/harness.d.ts +30 -1
  130. package/dist/features/harness/harness.js +141 -7
  131. package/dist/features/harness/platform/local-apps.d.ts +36 -3
  132. package/dist/features/harness/platform/local-apps.js +81 -5
  133. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  134. package/dist/features/harness/platform/persona-credentials.js +69 -0
  135. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  136. package/dist/features/harness/platform/platform-drives.js +114 -0
  137. package/dist/features/harness/platform/refusal.d.ts +52 -0
  138. package/dist/features/harness/platform/refusal.js +71 -0
  139. package/dist/features/harness/platform/remote-drive.d.ts +8 -2
  140. package/dist/features/harness/platform/remote-drive.js +22 -9
  141. package/dist/features/harness/platform/script.d.ts +57 -11
  142. package/dist/features/harness/platform/script.js +144 -12
  143. package/dist/features/harness/platform/server-driver.d.ts +17 -4
  144. package/dist/features/harness/platform/server-driver.js +29 -26
  145. package/dist/features/harness/platform-config.d.ts +38 -5
  146. package/dist/features/harness/platform-config.js +93 -8
  147. package/dist/features/harness/route-guess.d.ts +13 -0
  148. package/dist/features/harness/route-guess.js +49 -0
  149. package/dist/features/harness/script/script-run.d.ts +30 -1
  150. package/dist/features/harness/script/script-run.js +355 -48
  151. package/dist/features/license/license.d.ts +2 -2
  152. package/dist/features/visual/step-shots.d.ts +31 -0
  153. package/dist/features/visual/step-shots.js +231 -0
  154. package/dist/features/visual/visual-tools.js +22 -14
  155. package/dist/hooks/client-directory.d.ts +18 -0
  156. package/dist/hooks/client-directory.js +57 -0
  157. package/dist/hooks/coding-agents.d.ts +34 -0
  158. package/dist/hooks/coding-agents.js +117 -0
  159. package/dist/hooks/driven-by.d.ts +21 -2
  160. package/dist/hooks/driven-by.js +42 -2
  161. package/dist/hooks/hook-bus.d.ts +4 -0
  162. package/dist/hooks/hook-bus.js +18 -0
  163. package/dist/index.d.ts +1 -0
  164. package/dist/index.js +26 -183
  165. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  166. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  167. package/dist/judgement/capsule/causal-summary.js +33 -0
  168. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  169. package/dist/judgement/runs/artifact/build-verification-run.js +20 -4
  170. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  171. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  172. package/dist/judgement/runs/artifact/replay-mapping.js +25 -9
  173. package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
  174. package/dist/judgement/runs/artifact/run-store.js +175 -8
  175. package/dist/judgement/runs/context-tools.js +59 -1
  176. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  177. package/dist/judgement/runs/default-run-id.js +16 -0
  178. package/dist/judgement/runs/drive-run.d.ts +53 -5
  179. package/dist/judgement/runs/drive-run.js +234 -20
  180. package/dist/judgement/runs/resume.d.ts +44 -0
  181. package/dist/judgement/runs/resume.js +137 -0
  182. package/dist/judgement/runs/reticle-runner.js +5 -2
  183. package/dist/judgement/runs/runner-port.d.ts +5 -1
  184. package/dist/judgement/runs/runner-port.js +8 -2
  185. package/dist/judgement/runs/verification-sync.d.ts +2 -0
  186. package/dist/judgement/runs/verification-sync.js +36 -15
  187. package/dist/language/flows/decision.js +2 -1
  188. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  189. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  190. package/dist/language/flows/flow-anchor.d.ts +7 -2
  191. package/dist/language/flows/flow-anchor.js +10 -3
  192. package/dist/language/flows/flow-intent.d.ts +1 -0
  193. package/dist/language/flows/flow-journey.d.ts +6 -0
  194. package/dist/language/flows/flow-journey.js +20 -0
  195. package/dist/language/flows/flow-learning.d.ts +4 -0
  196. package/dist/language/flows/flow-learning.js +37 -3
  197. package/dist/language/flows/flow-replay-run.js +16 -18
  198. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  199. package/dist/language/flows/flow-replay.d.ts +18 -1
  200. package/dist/language/flows/flow-replay.js +22 -7
  201. package/dist/language/flows/flow-result.d.ts +22 -1
  202. package/dist/language/flows/flow-result.js +47 -2
  203. package/dist/language/flows/flow-step-runners.d.ts +2 -0
  204. package/dist/language/flows/flow-step-runners.js +12 -6
  205. package/dist/language/flows/flow-store-for-session.js +5 -1
  206. package/dist/language/flows/flow-tools.d.ts +10 -0
  207. package/dist/language/flows/flow-tools.js +61 -62
  208. package/dist/language/flows/flows.d.ts +16 -1
  209. package/dist/language/flows/flows.js +69 -10
  210. package/dist/language/flows/narrow-write.d.ts +7 -0
  211. package/dist/language/flows/narrow-write.js +36 -1
  212. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  213. package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
  214. package/dist/language/flows/recording/tape/recordings.js +60 -10
  215. package/dist/language/flows/replay.js +29 -6
  216. package/dist/language/flows/single-replay.d.ts +7 -0
  217. package/dist/language/flows/single-replay.js +26 -0
  218. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  219. package/dist/language/flows/verify-change-tools.js +200 -193
  220. package/dist/memory/cloud/cloud-config.d.ts +10 -1
  221. package/dist/memory/cloud/cloud-config.js +19 -5
  222. package/dist/memory/cloud/cloud-sync.js +3 -3
  223. package/dist/memory/cloud/harness-config.d.ts +49 -0
  224. package/dist/memory/cloud/harness-config.js +16 -20
  225. package/dist/memory/cloud/memory-scope.d.ts +17 -0
  226. package/dist/memory/cloud/memory-scope.js +22 -0
  227. package/dist/memory/cloud/sync-cycle.d.ts +32 -4
  228. package/dist/memory/cloud/sync-cycle.js +113 -12
  229. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  230. package/dist/memory/cloud/sync-daemon.js +114 -4
  231. package/dist/memory/cloud/sync-disk.js +26 -2
  232. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  233. package/dist/memory/cloud/sync-screenshots.js +105 -0
  234. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  235. package/dist/memory/cloud/unsynced-roots.js +166 -0
  236. package/dist/memory/impact/account-watch.d.ts +16 -1
  237. package/dist/memory/impact/account-watch.js +26 -1
  238. package/dist/memory/impact/impact-store.d.ts +1 -4
  239. package/dist/memory/impact/impact-store.js +32 -42
  240. package/dist/memory/intent/inline-intent.d.ts +1 -0
  241. package/dist/memory/intent/intent-shard-store.js +16 -4
  242. package/dist/memory/intent/intent-shard.d.ts +12 -0
  243. package/dist/memory/intent/intent-store.d.ts +1 -0
  244. package/dist/memory/intent/intent-tools.js +42 -2
  245. package/dist/memory/intent/open-intents.d.ts +6 -0
  246. package/dist/memory/intent/open-intents.js +10 -1
  247. package/dist/memory/intent/settled-words.d.ts +24 -0
  248. package/dist/memory/intent/settled-words.js +130 -0
  249. package/dist/memory/journal/drive-flow.d.ts +16 -0
  250. package/dist/memory/journal/drive-flow.js +34 -2
  251. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  252. package/dist/memory/journal/drive-run-flush.js +20 -5
  253. package/dist/memory/journal/journal-recorder.js +46 -3
  254. package/dist/memory/journal/on-disk/retention.d.ts +5 -0
  255. package/dist/memory/journal/on-disk/retention.js +27 -2
  256. package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
  257. package/dist/memory/journal/session-end.d.ts +15 -1
  258. package/dist/memory/journal/session-end.js +38 -7
  259. package/dist/memory/project/artifact-root-resolver.js +33 -5
  260. package/dist/memory/project/artifact-root.d.ts +4 -3
  261. package/dist/memory/project/artifact-root.js +2 -2
  262. package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
  263. package/dist/memory/project/dir/reticle-dir.js +23 -2
  264. package/dist/memory/project/link-directory.d.ts +15 -0
  265. package/dist/memory/project/link-directory.js +44 -0
  266. package/dist/memory/project/root-claims.d.ts +6 -0
  267. package/dist/memory/project/root-claims.js +39 -0
  268. package/dist/memory/project/session-root.d.ts +2 -0
  269. package/dist/memory/project/session-root.js +9 -1
  270. package/dist/memory/project/sync-status.d.ts +46 -0
  271. package/dist/memory/project/sync-status.js +135 -1
  272. package/dist/memory/recall/memory-tools.js +46 -3
  273. package/dist/memory/recall/platform-memory.d.ts +34 -0
  274. package/dist/memory/recall/platform-memory.js +139 -0
  275. package/dist/memory/recall/project-memory.js +36 -8
  276. package/dist/portal/bridge/bridge.d.ts +9 -5
  277. package/dist/portal/bridge/bridge.js +66 -23
  278. package/dist/portal/bridge/harness-request.d.ts +23 -0
  279. package/dist/portal/bridge/harness-request.js +27 -0
  280. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  281. package/dist/portal/bridge/wrong-path.js +35 -0
  282. package/dist/portal/input/network-mock-tools.js +11 -2
  283. package/dist/portal/input/real-input.d.ts +2 -0
  284. package/dist/portal/input/real-input.js +13 -10
  285. package/dist/portal/pool/browser-pool.d.ts +48 -0
  286. package/dist/portal/pool/browser-pool.js +120 -2
  287. package/dist/portal/pool/context-permissions.d.ts +33 -0
  288. package/dist/portal/pool/context-permissions.js +33 -0
  289. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  290. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  291. package/dist/portal/pool/playwright-launcher.d.ts +27 -5
  292. package/dist/portal/pool/playwright-launcher.js +59 -14
  293. package/dist/portal/pool/pool-contract.d.ts +21 -1
  294. package/dist/portal/session/agent-link.d.ts +8 -0
  295. package/dist/portal/session/agent-link.js +17 -0
  296. package/dist/portal/session/command-payload.js +6 -1
  297. package/dist/portal/session/daemon-answers.d.ts +3 -3
  298. package/dist/portal/session/daemon-answers.js +4 -2
  299. package/dist/portal/session/dev-server/dev-command.d.ts +9 -0
  300. package/dist/portal/session/dev-server/dev-command.js +27 -1
  301. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  302. package/dist/portal/session/facts/observed-state.js +46 -3
  303. package/dist/portal/session/human/live-control.d.ts +9 -2
  304. package/dist/portal/session/human/live-control.js +12 -3
  305. package/dist/portal/session/live-control-tools.js +82 -13
  306. package/dist/portal/session/narration-args.d.ts +5 -0
  307. package/dist/portal/session/narration-args.js +17 -0
  308. package/dist/portal/session/no-session-diagnosis.d.ts +1 -1
  309. package/dist/portal/session/no-session-diagnosis.js +31 -9
  310. package/dist/portal/session/no-session-next-action.d.ts +20 -0
  311. package/dist/portal/session/no-session-next-action.js +134 -61
  312. package/dist/portal/session/no-session-watch.js +179 -22
  313. package/dist/portal/session/presence/session-lease.js +1 -1
  314. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  315. package/dist/portal/session/recorded-gaps.js +251 -0
  316. package/dist/portal/session/session-health.d.ts +11 -0
  317. package/dist/portal/session/session-health.js +3 -1
  318. package/dist/portal/session/session-info.js +2 -1
  319. package/dist/portal/session/session-manager.d.ts +18 -0
  320. package/dist/portal/session/session-manager.js +54 -3
  321. package/dist/portal/session/session-successor.d.ts +8 -0
  322. package/dist/portal/session/session-successor.js +1 -1
  323. package/dist/portal/session/session.d.ts +15 -28
  324. package/dist/portal/session/session.js +60 -61
  325. package/dist/portal/session/timing/command-timeout.js +25 -1
  326. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  327. package/dist/portal/session/timing/wall-clock.js +1 -1
  328. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  329. package/dist/portal/session/zero-install-first-call.js +88 -0
  330. package/dist/start-options.d.ts +7 -1
  331. package/dist/start-wiring.d.ts +63 -0
  332. package/dist/start-wiring.js +169 -0
  333. package/dist/status-payload.d.ts +13 -1
  334. package/dist/status-payload.js +13 -1
  335. package/dist/surface/http-server.js +7 -1
  336. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  337. package/dist/surface/mcp/attach-memory.js +12 -1
  338. package/dist/surface/mcp/mcp-proxy.d.ts +4 -0
  339. package/dist/surface/mcp/mcp-proxy.js +29 -8
  340. package/dist/surface/mcp/mcp.d.ts +23 -0
  341. package/dist/surface/mcp/mcp.js +34 -4
  342. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  343. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  344. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  345. package/dist/surface/mcp/server-instructions.js +22 -14
  346. package/dist/surface/mcp/shared-params.js +1 -1
  347. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  348. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  349. package/dist/surface/tools/account-tool.d.ts +22 -0
  350. package/dist/surface/tools/account-tool.js +157 -0
  351. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  352. package/dist/surface/tools/act/act-danger.js +38 -1
  353. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  354. package/dist/surface/tools/act/act-observation.js +57 -0
  355. package/dist/surface/tools/act/act-preflight.js +25 -2
  356. package/dist/surface/tools/act/act-target.js +8 -3
  357. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  358. package/dist/surface/tools/act/resolve-target.js +18 -3
  359. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  360. package/dist/surface/tools/act/screen-request.js +113 -0
  361. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  362. package/dist/surface/tools/act/sequence-grade.js +13 -2
  363. package/dist/surface/tools/act-sequence-tool.js +136 -27
  364. package/dist/surface/tools/act-tools.d.ts +0 -9
  365. package/dist/surface/tools/act-tools.js +48 -34
  366. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  367. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  368. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  369. package/dist/surface/tools/agent/app-notes.js +48 -0
  370. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  371. package/dist/surface/tools/agent/build-staleness.js +62 -0
  372. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  373. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  374. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  375. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  376. package/dist/surface/tools/agent/notices.d.ts +50 -0
  377. package/dist/surface/tools/agent/notices.js +152 -0
  378. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  379. package/dist/surface/tools/agent/reteach.js +50 -0
  380. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  381. package/dist/surface/tools/args/alias-args.js +10 -0
  382. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  383. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  384. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  385. package/dist/surface/tools/assert/assert-source.js +40 -0
  386. package/dist/surface/tools/assert/assert-verdict.js +25 -15
  387. package/dist/surface/tools/browser-tools.js +43 -1
  388. package/dist/surface/tools/chat-drives.d.ts +75 -0
  389. package/dist/surface/tools/chat-drives.js +265 -21
  390. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  391. package/dist/surface/tools/coverage-tools.js +2 -53
  392. package/dist/surface/tools/dynamic-tools.js +29 -1
  393. package/dist/surface/tools/empty-session-list.d.ts +10 -0
  394. package/dist/surface/tools/empty-session-list.js +45 -5
  395. package/dist/surface/tools/error-recovery.d.ts +8 -0
  396. package/dist/surface/tools/error-recovery.js +69 -5
  397. package/dist/surface/tools/explore-tools.d.ts +23 -2
  398. package/dist/surface/tools/explore-tools.js +377 -74
  399. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  400. package/dist/surface/tools/feedback-tools.js +4 -3
  401. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  402. package/dist/surface/tools/gap-novelty.js +8 -1
  403. package/dist/surface/tools/harness-explore.d.ts +52 -73
  404. package/dist/surface/tools/harness-explore.js +177 -146
  405. package/dist/surface/tools/harness-gate.d.ts +88 -0
  406. package/dist/surface/tools/harness-gate.js +235 -0
  407. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  408. package/dist/surface/tools/harness-hunt.js +215 -0
  409. package/dist/surface/tools/harness-plan.d.ts +5 -0
  410. package/dist/surface/tools/harness-plan.js +7 -0
  411. package/dist/surface/tools/harness-script.d.ts +22 -0
  412. package/dist/surface/tools/harness-script.js +256 -38
  413. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  414. package/dist/surface/tools/harness-tab-guard.js +27 -0
  415. package/dist/surface/tools/harness-toolset.d.ts +8 -0
  416. package/dist/surface/tools/harness-toolset.js +27 -4
  417. package/dist/surface/tools/human-notes.d.ts +16 -0
  418. package/dist/surface/tools/human-notes.js +27 -0
  419. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  420. package/dist/surface/tools/invoke-tool.js +220 -93
  421. package/dist/surface/tools/lease-hint.js +26 -5
  422. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  423. package/dist/surface/tools/lease-permissions.js +73 -0
  424. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  425. package/dist/surface/tools/lease-readiness.js +57 -0
  426. package/dist/surface/tools/lease-seed.d.ts +20 -0
  427. package/dist/surface/tools/lease-seed.js +45 -1
  428. package/dist/surface/tools/lease-tools.d.ts +10 -1
  429. package/dist/surface/tools/lease-tools.js +119 -69
  430. package/dist/surface/tools/live-call-text.js +2 -2
  431. package/dist/surface/tools/merge-tools.js +42 -2
  432. package/dist/surface/tools/merged-name-redirect.js +4 -0
  433. package/dist/surface/tools/next-step.d.ts +11 -1
  434. package/dist/surface/tools/next-step.js +73 -18
  435. package/dist/surface/tools/observe-tools.js +43 -5
  436. package/dist/surface/tools/platform-moment.d.ts +60 -0
  437. package/dist/surface/tools/platform-moment.js +132 -4
  438. package/dist/surface/tools/read-tools.js +65 -14
  439. package/dist/surface/tools/reticle-result.d.ts +120 -0
  440. package/dist/surface/tools/reticle-result.js +364 -0
  441. package/dist/surface/tools/tool-kit.d.ts +68 -2
  442. package/dist/surface/tools/tool-kit.js +73 -1
  443. package/dist/surface/tools/tools.js +25 -13
  444. package/dist/telemetry/account-envelope.d.ts +7 -0
  445. package/dist/telemetry/account-envelope.js +61 -0
  446. package/dist/telemetry/agent-client.d.ts +15 -0
  447. package/dist/telemetry/agent-client.js +57 -0
  448. package/dist/telemetry/app-instrumented.js +9 -2
  449. package/dist/telemetry/argument-shape.d.ts +7 -0
  450. package/dist/telemetry/argument-shape.js +86 -1
  451. package/dist/telemetry/automation-hint.d.ts +2 -3
  452. package/dist/telemetry/automation-hint.js +33 -8
  453. package/dist/telemetry/cli-telemetry.js +7 -2
  454. package/dist/telemetry/daemon-telemetry.js +3 -0
  455. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  456. package/dist/telemetry/error-fingerprint.js +61 -5
  457. package/dist/telemetry/feedback-cli.d.ts +0 -13
  458. package/dist/telemetry/feedback-cli.js +0 -77
  459. package/dist/telemetry/feedback.d.ts +13 -0
  460. package/dist/telemetry/feedback.js +183 -17
  461. package/dist/telemetry/harness-run.d.ts +18 -0
  462. package/dist/telemetry/harness-run.js +80 -0
  463. package/dist/telemetry/hud-events.d.ts +16 -0
  464. package/dist/telemetry/hud-events.js +27 -0
  465. package/dist/telemetry/hud-metrics.d.ts +27 -6
  466. package/dist/telemetry/hud-metrics.js +99 -25
  467. package/dist/telemetry/init-telemetry.js +2 -2
  468. package/dist/telemetry/install-source.d.ts +13 -25
  469. package/dist/telemetry/install-source.js +44 -3
  470. package/dist/telemetry/mcp-connection.d.ts +0 -14
  471. package/dist/telemetry/mcp-connection.js +5 -1
  472. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  473. package/dist/telemetry/onboarding-firsts.js +81 -6
  474. package/dist/telemetry/platform-linked.d.ts +5 -0
  475. package/dist/telemetry/platform-linked.js +32 -0
  476. package/dist/telemetry/project-profile.js +5 -3
  477. package/dist/telemetry/proxy-telemetry.js +4 -1
  478. package/dist/telemetry/session-metrics.d.ts +15 -4
  479. package/dist/telemetry/session-metrics.js +88 -52
  480. package/dist/telemetry/telemetry.d.ts +26 -2
  481. package/dist/telemetry/telemetry.js +102 -21
  482. package/dist/telemetry/verification-of.d.ts +3 -1
  483. package/dist/telemetry/verification-of.js +12 -4
  484. package/dist/wire-journal.d.ts +2 -2
  485. package/dist/wire-journal.js +16 -5
  486. package/docs/README.md +2 -2
  487. package/docs/actions.mdx +6 -3
  488. package/docs/adapters.md +1 -1
  489. package/docs/agent-cheatsheet.md +24 -27
  490. package/docs/architecture.md +5 -5
  491. package/docs/autodrive.md +13 -12
  492. package/docs/benchmarks.md +5 -5
  493. package/docs/best-practices.mdx +27 -9
  494. package/docs/capabilities.mdx +14 -16
  495. package/docs/cli/affected.mdx +1 -1
  496. package/docs/cli/cloud.mdx +54 -75
  497. package/docs/cli/doctor.mdx +8 -3
  498. package/docs/cli/drive.mdx +12 -12
  499. package/docs/cli/feedback.mdx +3 -3
  500. package/docs/cli/gate.mdx +7 -2
  501. package/docs/cli/help.mdx +50 -55
  502. package/docs/cli/init.mdx +32 -15
  503. package/docs/cli/license.mdx +12 -8
  504. package/docs/cli/mcp.mdx +4 -4
  505. package/docs/cli/open.mdx +3 -3
  506. package/docs/cli/report.mdx +4 -2
  507. package/docs/cli/restart.mdx +2 -2
  508. package/docs/cli/rollback.mdx +14 -8
  509. package/docs/cli/serve.mdx +4 -4
  510. package/docs/cli/setup.mdx +23 -0
  511. package/docs/cli/status.mdx +13 -4
  512. package/docs/cli/stop.mdx +67 -8
  513. package/docs/cli/try.mdx +62 -0
  514. package/docs/cli/update.mdx +4 -3
  515. package/docs/cli/verify.mdx +17 -6
  516. package/docs/cli/version.mdx +3 -2
  517. package/docs/cli.mdx +110 -41
  518. package/docs/debugging.md +3 -3
  519. package/docs/deploy-checks.md +1 -1
  520. package/docs/desktop.mdx +5 -3
  521. package/docs/enterprise.md +11 -10
  522. package/docs/environment.mdx +5 -2
  523. package/docs/faq.mdx +3 -3
  524. package/docs/first-drive.md +5 -4
  525. package/docs/flows.md +35 -27
  526. package/docs/for-agents.md +4 -5
  527. package/docs/frameworks.mdx +32 -21
  528. package/docs/getting-started.md +66 -64
  529. package/docs/human-control.md +15 -14
  530. package/docs/index.mdx +15 -43
  531. package/docs/install-agentic.mdx +22 -37
  532. package/docs/install-manual.mdx +22 -12
  533. package/docs/instrumentation.mdx +5 -3
  534. package/docs/integration-patterns.md +7 -7
  535. package/docs/license-activation.mdx +1 -1
  536. package/docs/multi-agent-testing.md +24 -6
  537. package/docs/packages/babel-plugin.mdx +4 -2
  538. package/docs/packages/browser.mdx +16 -10
  539. package/docs/packages/core.mdx +12 -5
  540. package/docs/packages/electron.mdx +3 -2
  541. package/docs/packages/engine.mdx +1 -1
  542. package/docs/packages/eslint-plugin.mdx +18 -12
  543. package/docs/packages/next.mdx +8 -7
  544. package/docs/packages/open-verification.mdx +1 -1
  545. package/docs/packages/server.mdx +5 -5
  546. package/docs/packages/tauri.mdx +8 -8
  547. package/docs/packages/test.mdx +4 -10
  548. package/docs/packages/vite-plugin.mdx +11 -4
  549. package/docs/packages.mdx +11 -15
  550. package/docs/platform-integration.md +6 -5
  551. package/docs/predicates.mdx +40 -24
  552. package/docs/quickstart.mdx +58 -29
  553. package/docs/required-checks.md +8 -7
  554. package/docs/reticle-manual.md +15 -5
  555. package/docs/skill-file.mdx +17 -79
  556. package/docs/skill-setup.md +9 -9
  557. package/docs/skill.md +200 -0
  558. package/docs/system-map.md +7 -7
  559. package/docs/telemetry.md +22 -24
  560. package/docs/testing.md +4 -4
  561. package/docs/token-efficiency.md +12 -12
  562. package/docs/tools/act-and-wait.mdx +9 -2
  563. package/docs/tools/act-sequence.mdx +6 -7
  564. package/docs/tools/act.mdx +2 -2
  565. package/docs/tools/assert.mdx +18 -17
  566. package/docs/tools/console.mdx +9 -9
  567. package/docs/tools/inspect.mdx +16 -7
  568. package/docs/tools/look.mdx +24 -0
  569. package/docs/tools/navigate.mdx +5 -3
  570. package/docs/tools/network.mdx +2 -2
  571. package/docs/tools/observe.mdx +6 -6
  572. package/docs/tools/overview.mdx +34 -33
  573. package/docs/tools/query.mdx +5 -5
  574. package/docs/tools/session-and-feedback.mdx +13 -4
  575. package/docs/tools/sessions.mdx +8 -8
  576. package/docs/tools/snapshot.mdx +6 -5
  577. package/docs/tools/state.mdx +9 -9
  578. package/docs/tools/tools-and-run.mdx +26 -24
  579. package/docs/tools/verify.mdx +28 -0
  580. package/docs/tools/wait-for.mdx +8 -4
  581. package/docs/troubleshooting.mdx +21 -6
  582. package/docs/usage.md +51 -45
  583. package/docs/use-cases.mdx +3 -3
  584. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  585. package/docs/vs-playwright-mcp.mdx +3 -1
  586. package/docs/what-is-recorded.md +7 -5
  587. package/docs/what-is-reticle.mdx +2 -2
  588. package/docs/why-reticle.mdx +1 -1
  589. package/package.json +6 -5
  590. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  591. package/dist/command/cli/demo/demo-page.js +0 -249
  592. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  593. package/dist/command/cli/demo/demo-run.js +0 -138
  594. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  595. package/dist/judgement/hunt/hunt-report.js +0 -84
  596. package/dist/language/flows/buddy-status.d.ts +0 -25
  597. package/dist/language/flows/buddy-status.js +0 -32
  598. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  599. package/dist/language/flows/change/watch-batcher.js +0 -19
  600. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  601. package/dist/memory/cloud/harness-offer.js +0 -145
  602. package/dist/surface/tools/feature-capture.d.ts +0 -151
  603. package/dist/surface/tools/feature-capture.js +0 -235
  604. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  605. package/dist/surface/tools/tool-hit-rate.js +0 -90
  606. package/dist/telemetry/harness-drive.d.ts +0 -4
  607. package/dist/telemetry/harness-drive.js +0 -35
  608. package/dist/telemetry/identify.d.ts +0 -22
  609. package/dist/telemetry/identify.js +0 -73
  610. package/docs/cli/capsules.mdx +0 -70
  611. package/docs/cli/hunt.mdx +0 -73
  612. package/docs/cli/identify.mdx +0 -76
  613. package/docs/cli/kill.mdx +0 -91
  614. package/docs/cli/watch.mdx +0 -62
@@ -8,26 +8,44 @@
8
8
  */
9
9
  import { randomUUID } from 'node:crypto';
10
10
  import { join } from 'node:path';
11
- import { ReticleCommand, ReticleTool, ScriptStatus, asRecord } from '@reticlehq/core';
12
- import { PromptContextSchema, checkScript } from '@reticlehq/core/artifacts';
11
+ import { ReticleCommand, ReticleTool, ScriptStatus, asRecord, } from '@reticlehq/core';
12
+ import { JourneyBy, PromptContextSchema, checkScript, } from '@reticlehq/core/artifacts';
13
13
  import { runScript, } from '../../features/harness/script/script-run.js';
14
14
  import { CUSTOM_DRIVER_NAME } from '../../features/harness/drivers.js';
15
- import { checkTally, verdictLine } from '../../features/harness/drive-report.js';
15
+ import { actedOnApp, checkTally, pagesReached, typedValues, verdictLine, } from '../../features/harness/drive-report.js';
16
16
  import { runHarness, StopReason, } from '../../features/harness/harness.js';
17
17
  import { reticleDirPaths } from '../../memory/project/dir/reticle-dir.js';
18
- import { harnessRunId, noteHarnessGoal } from '../../judgement/runs/drive-run.js';
18
+ import { harnessRunId, noteHarnessDisparity, noteHarnessGoal, noteHarnessSpan, } from '../../judgement/runs/drive-run.js';
19
19
  import { openSessionIntents } from '../../memory/intent/open-intents.js';
20
20
  import { sessionRoot, sessionTarget } from '../../memory/project/session-root.js';
21
- import { leasableAppUrl } from '../../language/flows/flow-tools.js';
22
- import { acquireLeasedSession } from './lease-tools.js';
21
+ import { leasableAppUrl, sessionUrlOf } from '../../language/flows/flow-tools.js';
22
+ import { acquireLeasedSession, suiteFixtureSeed } from './lease-tools.js';
23
23
  import { reticleToolset } from './harness-toolset.js';
24
24
  import { laneIds } from '../../features/harness/script/lane-ids.js';
25
25
  import { appControlsOf } from '../../features/harness/script/app-controls.js';
26
- import { PlanStepKind, aboutTheApp, planAsText, withoutReplays, } from './harness-plan.js';
27
- import { journeyResults, personasIn, proposeScript, reportPlanResults, } from '../../features/harness/platform/script.js';
28
- import { checkGoals, goalsIn } from '../../features/harness/goals.js';
29
- import { serverOptionsFromEnv } from '../../features/harness/platform/server-driver.js';
30
- import { MSG_HARNESS_DISABLED, bankOpenRecording, buildDriver, flowsThatCheckNothing, maxStepsFromEnv, narrator, pinned, productRules, readFlows, readPlan, reconcileFlows, recordPersona, refusedByPlatform, withProjectFlows, } from './harness-explore.js';
26
+ import { surveyedSince } from '../../features/harness/explore/site-map.js';
27
+ import { PlanStepKind, aboutTheApp, drivingPlan, planAsText, } from './harness-plan.js';
28
+ import { fetchScript, journeyResults, personasIn, proposeScript, reportPlanBlocked, reportPlanResults, } from '../../features/harness/platform/script.js';
29
+ import { endOf, goalOfDrive, parseGoals, readOpening } from '../../features/harness/goals.js';
30
+ import { bestOfLanes, huntAndGrade, knownRoutes, refreshMap, siteMapFor, } from './harness-hunt.js';
31
+ import { serverOptionsFromEnv, } from '../../features/harness/platform/server-driver.js';
32
+ import { MSG_HARNESS_DISABLED, bankOpenRecording, buildDriver, firstLine, flowsThatCheckNothing, maxStepsFromEnv, msgDriveCutOff, narrator, pinned, productRules, readFlows, readPlan, reconcileFlows, recordPersona, refusedByPlatform, steering, withProjectFlows, } from './harness-explore.js';
33
+ /** A saved plan this run was asked for and could not read: said, never swapped for another drive. */
34
+ export const msgSavedPlanUnreadable = (planId) => `The saved plan ${planId} could not be read from the Reticle platform, or it no longer runs as written. Open it on the dashboard, fix it, and run it again.`;
35
+ /** The platform could not plan the run: the drive that follows is the journey alone, unplanned. */
36
+ export const msgNoPlan = (why) => `No plan this time — ${why.replace(/\.$/, '')}. Driving the journey on its own instead.`;
37
+ /** Said when a plan's lanes cannot carry this tab's sign-in into new browsers, so they take turns here. */
38
+ export const MSG_LANES_IN_THIS_TAB = "The plan's lanes take turns in this tab: a new browser would start signed out, and this tab's " +
39
+ 'sign-in could not be copied into one.';
40
+ /**
41
+ * The sign-in a plan's lanes start from: what this tab's browser holds, or undefined when it cannot
42
+ * be copied (no browser this daemon drives, nothing to copy), in which case the lanes take turns here.
43
+ */
44
+ export async function laneSeed(deps, sessionId, appUrl) {
45
+ if (appUrl === undefined)
46
+ return undefined;
47
+ return suiteFixtureSeed(deps.realInput, sessionUrlOf(deps, sessionId) ?? appUrl);
48
+ }
31
49
  /** A request older than this is about some earlier task, not the one being driven. */
32
50
  const REQUEST_FRESH_MS = 6 * 60 * 60 * 1000;
33
51
  const MAX_GOAL_CHARS = 500;
@@ -52,18 +70,45 @@ export async function exploreScript(deps, env, options, before) {
52
70
  ? plan.steps.filter((s) => PlanStepKind.REPLAY === s.kind).map((s) => s.target)
53
71
  : [];
54
72
  const goals = focus === undefined ? await memoryGoals(deps, options.sessionId) : [focus];
55
- const gaps = plan.steps.filter((s) => PlanStepKind.DRIVE === s.kind).map((s) => s.why);
73
+ const gaps = drivingPlan(plan, focus).steps.map((s) => s.why);
56
74
  const flows = await readFlows(reads);
57
75
  const known = await productRules(deps, options.sessionId);
58
76
  // The platform plans: personas, order, branches and the product rules each journey proves.
59
77
  // A platform that cannot plan leaves the caller to drive the journey through it unplanned.
60
78
  const platform = serverOptionsFromEnv(env);
79
+ // A saved plan is the platform's: without it there is nothing to run, and driving something else
80
+ // in its place would answer a question nobody asked.
81
+ if (platform === undefined && options.planId !== undefined)
82
+ throw new Error(msgSavedPlanUnreadable(options.planId));
61
83
  if (platform === undefined)
62
84
  return undefined;
85
+ if (options.planId !== undefined) {
86
+ const planId = options.planId;
87
+ // Refused or broken before a journey ran is still said to the plan, so its history shows it.
88
+ // ponytail: a throw from inside a running plan is reported as all blocked too; runPlan reports
89
+ // real results itself whenever it returns.
90
+ try {
91
+ const saved = await fetchScript(platform, planId);
92
+ if (saved === undefined)
93
+ throw new Error(msgSavedPlanUnreadable(planId));
94
+ return await runPlan(deps, env, options, before, { platform, plan, script: saved, planId });
95
+ }
96
+ catch (error) {
97
+ const why = error instanceof Error ? error.message : String(error);
98
+ await reportPlanBlocked(platform, planId, firstLine(why));
99
+ throw error;
100
+ }
101
+ }
102
+ // The same persona runs the plan it made last time, as it stands on the platform now (edits and
103
+ // replay-first included): a new plan per HUD run meant a passed journey was never replayed.
104
+ const again = focus === undefined ? undefined : await planMadeFor(deps, options.sessionId, focus);
105
+ const reused = again === undefined ? undefined : await fetchScript(platform, again);
106
+ if (again !== undefined && reused !== undefined)
107
+ return runPlan(deps, env, options, before, { platform, plan, script: reused, planId: again });
63
108
  // What the screen offers, for a named journey too. The platform splits a broad request ("test my
64
109
  // app, make a plan") into journeys through these controls and leaves a narrow one whole; without
65
110
  // them, a chat-requested drive of a desktop app planned one step that restated the request.
66
- const about = await aboutTheApp(planAsText(plan), (name, args) => reticleToolset(deps, pinned(options)).invoke(name, args), await controlsSeenBefore(deps, options.sessionId));
111
+ const about = await aboutTheApp(planAsText(focus === undefined ? plan : drivingPlan(plan, focus)), (name, args) => reticleToolset(deps, pinned(options)).invoke(name, args), await controlsSeenBefore(deps, options.sessionId));
67
112
  const personas = focus === undefined ? personasIn(flows) : [];
68
113
  const proposed = await proposeScript(platform, {
69
114
  about,
@@ -74,14 +119,35 @@ export async function exploreScript(deps, env, options, before) {
74
119
  rules: known,
75
120
  personas,
76
121
  });
122
+ if (proposed !== undefined && 'refused' in proposed) {
123
+ // Said where the run is watched: the drive goes on without a plan, and that is not what was asked.
124
+ narrator(deps, options)(msgNoPlan(proposed.refused), true);
125
+ return undefined;
126
+ }
77
127
  if (proposed === undefined || 0 < checkScript(proposed.script).length)
78
128
  return undefined;
79
- const { script, planId } = proposed;
129
+ return runPlan(deps, env, options, before, {
130
+ platform,
131
+ plan,
132
+ script: proposed.script,
133
+ ...(proposed.planId === undefined ? {} : { planId: proposed.planId }),
134
+ ...(proposed.creditsSpent === undefined ? {} : { planCredits: proposed.creditsSpent }),
135
+ });
136
+ }
137
+ /** Run a plan the platform wrote (just now, or saved and maybe edited since), and report how it went. */
138
+ async function runPlan(deps, env, options, before, planned) {
139
+ const { platform, plan, script, planId } = planned;
140
+ const reads = withProjectFlows(deps, options.sessionId);
141
+ const focus = options.focus;
80
142
  // Saved the moment it exists, so a drive that breaks still leaves its plan behind.
81
- const planFile = await savePlan(deps, options.sessionId, { planId, script });
143
+ const planFile = await savePlan(deps, options.sessionId, {
144
+ planId,
145
+ script,
146
+ ...(focus === undefined ? {} : { focus }),
147
+ });
82
148
  const maxSteps = options.maxSteps ?? maxStepsFromEnv(env);
83
149
  // The script replays the saved flows itself; a model handed them too replayed them again per goal.
84
- const open = withoutReplays(plan);
150
+ const open = drivingPlan(plan, focus);
85
151
  // The journey itself leads (its rules are already written into it by the platform): a driver
86
152
  // with nothing named to prove stopped after its first half.
87
153
  const planFor = (goal) => {
@@ -90,16 +156,26 @@ export async function exploreScript(deps, env, options, before) {
90
156
  const journey = { kind: PlanStepKind.DRIVE, target: 'this journey, to its end', why: goal };
91
157
  return { ...open, steps: [journey, ...open.steps] };
92
158
  };
159
+ // Map first: survey the app (no model) unless its map is fresh; every lane's engine looks goals up
160
+ // in it, and the hunt before grading starts from it. The tab is left where it started.
161
+ const mapAsked = deps.now();
162
+ const map = await siteMapFor(deps, options.sessionId, (name, args) => reticleToolset(deps, pinned(options)).invoke(name, args));
93
163
  const driverFor = (persona, goal) => options.driver === undefined
94
- ? buildDriver(env, maxSteps, planFor(goal), options.driverName, persona, persona === undefined ? goal : undefined)
164
+ ? buildDriver(env, maxSteps, planFor(goal), options.driverName, persona, persona === undefined ? goal : undefined, map)
95
165
  : { driver: options.driver, name: CUSTOM_DRIVER_NAME };
96
166
  const driverName = driverFor().name;
97
- const harness = randomUUID();
167
+ const harness = options.harnessId ?? randomUUID();
98
168
  const narrate = narrator(deps, options);
99
169
  // Lanes run side by side only in leased contexts; without a pool they take turns on this tab.
100
170
  const pool = deps.pool;
101
171
  const appUrl = leasableAppUrl(deps, options.sessionId);
102
- const leasing = pool !== undefined && appUrl !== undefined && 1 < script.lanes.length;
172
+ const wantsLanes = pool !== undefined && appUrl !== undefined && 1 < script.lanes.length;
173
+ // A new context starts signed out: lanes once spent a whole run (three lanes, twelve credits) on
174
+ // /login, a page that was not the journey. They start from what this tab holds, or take turns here.
175
+ const seed = wantsLanes ? await laneSeed(deps, options.sessionId, appUrl) : undefined;
176
+ const leasing = wantsLanes && seed !== undefined;
177
+ if (wantsLanes && !leasing)
178
+ narrator(deps, options)(MSG_LANES_IN_THIS_TAB);
103
179
  const projectId = safeProjectId(deps, options.sessionId);
104
180
  let off = false;
105
181
  const poll = setInterval(() => {
@@ -110,15 +186,25 @@ export async function exploreScript(deps, env, options, before) {
110
186
  }, STOP_POLL_MS);
111
187
  poll.unref();
112
188
  const lanes = laneIds(harness, leasing);
189
+ const endGoalsAsked = options.goals ?? parseGoals(focus);
190
+ const laneGrades = [];
113
191
  // Keyed by the tool list, which the script runner's recording wrapper passes through unchanged.
114
192
  const harnessOf = new WeakMap();
193
+ const own = [...(focus === undefined ? [] : [focus]), ...scriptTexts(script)];
115
194
  const ports = {
195
+ own,
116
196
  parallel: leasing ? Math.max(1, Math.min(script.lanes.length, pool.capacity(), MAX_LANES)) : 1,
117
- stopped: () => off,
197
+ stopped: () => off || true === options.stopped?.(),
198
+ // A replay-only plan started without the model's gates; a fallback is the model, so it asks now.
199
+ fallbackRefused: async () => {
200
+ const refusal = await refusedByPlatform(env, options);
201
+ return refusal === undefined ? undefined : firstLine(refusal);
202
+ },
203
+ ...(true === options.confirmDangerous ? { confirmDangerous: true } : {}),
118
204
  lease: async () => {
119
205
  if (!leasing)
120
206
  return { ...pinned(options), release: () => Promise.resolve() };
121
- const acquire = () => acquireLeasedSession(pool, deps.sessions, appUrl, projectId);
207
+ const acquire = () => acquireLeasedSession(pool, deps.sessions, appUrl, projectId, seed);
122
208
  // A cold dev server can miss the first load while other lanes compile it; the second finds it warm.
123
209
  return acquire().catch(acquire);
124
210
  },
@@ -131,6 +217,9 @@ export async function exploreScript(deps, env, options, before) {
131
217
  driver: driverName,
132
218
  ...(persona === undefined ? {} : { persona }),
133
219
  },
220
+ // The person's request, never the planned journey's text: a planner-invented journey
221
+ // ("press Invite") must not be what allows an invite.
222
+ ...(focus === undefined ? {} : { asked: focus }),
134
223
  });
135
224
  harnessOf.set(toolset.tools, id);
136
225
  return toolset;
@@ -141,16 +230,38 @@ export async function exploreScript(deps, env, options, before) {
141
230
  ? undefined
142
231
  : goal);
143
232
  const ahead = new Set(await reads.flows.list());
144
- const result = await runHarness(driverFor(persona, goal).driver, toolset, {
233
+ const driven = await runHarness(driverFor(persona, goal).driver, toolset, {
234
+ ...steering(options),
145
235
  maxSteps: Math.min(steps, maxSteps),
236
+ routes: knownRoutes(map),
146
237
  focus: [planAsText(planFor(goal)), `Focus: ${goal}`].join('\n\n'),
238
+ ...((end) => (end === undefined ? {} : { endsAt: { text: end, own } }))(endOf(goal)),
147
239
  });
240
+ // The driver's word, unless the lane did nothing: then its goal was not met by it.
241
+ const laneGoal = goalOfDrive(driven.goalMet, [], actedOnApp(driven.toolCalls));
242
+ const result = { ...driven, ...(laneGoal === undefined ? {} : { goalMet: laneGoal }) };
148
243
  // Before the lane's session ends and is graded, so its run cannot read "Proved" over a goal
149
244
  // the drive did not reach.
150
245
  noteHarnessGoal(harnessOf.get(toolset.tools) ?? harness, result.goalMet);
151
- await bankOpenRecording(toolset, result, persona);
246
+ const banked = await bankOpenRecording(toolset, result, persona, goal);
247
+ // A lane in its own browser is graded where it drove: the caller's tab never saw its pages.
248
+ if (leasing && 0 < endGoalsAsked.length)
249
+ laneGrades.push(await huntAndGrade(deps, (name, args) => toolset.invoke(name, args), {
250
+ sessionId: options.sessionId,
251
+ goals: endGoalsAsked,
252
+ expect: options.expect,
253
+ opening,
254
+ journey: goal,
255
+ map,
256
+ own,
257
+ reached: pagesReached(result.toolCalls),
258
+ typed: typedValues(result.toolCalls),
259
+ }));
152
260
  if (persona !== undefined) {
153
- const saved = reconcileFlows(ahead, await reads.flows.list(), result.toolCalls);
261
+ const saved = reconcileFlows(ahead, await reads.flows.list(), [
262
+ ...result.toolCalls,
263
+ ...banked,
264
+ ]);
154
265
  await recordPersona(reads, [...saved.savedFlows, ...saved.rewroteFlows], persona);
155
266
  }
156
267
  return result;
@@ -158,6 +269,10 @@ export async function exploreScript(deps, env, options, before) {
158
269
  };
159
270
  narrate(`Harness plan from the platform · ${String(script.journeys.length)} journeys in ${String(script.lanes.length)} lane(s)` +
160
271
  (1 < ports.parallel ? `, ${String(ports.parallel)} at once` : ''));
272
+ // Read before anything is driven: a goal this page already shows proves nothing at the end.
273
+ const endInvoke = (name, args) => ports.toolset(pinned(options).sessionId, focus).invoke(name, args);
274
+ const opening = await readOpening(endInvoke);
275
+ const runStarted = deps.now();
161
276
  let run;
162
277
  try {
163
278
  run = await runScript(script, ports, (view) => {
@@ -177,23 +292,32 @@ export async function exploreScript(deps, env, options, before) {
177
292
  // error in the console. On the merchant dashboard eight blank pages went unreported without it.
178
293
  // After the journeys, so the lanes start sooner. (Run first, it once left every lane unable to
179
294
  // start; that did not reproduce on a clean install, and was the checkout's, not the order's.)
180
- const crawled = focus === undefined && !run.stopped
295
+ // Once per map: a run on a fresh map swept the whole app again, every time.
296
+ const crawled = focus === undefined && !run.stopped && surveyedSince(map, mapAsked)
181
297
  ? await crawlApp(deps, options, harness, driverName)
182
298
  : undefined;
183
299
  // How each journey went: kept beside the plan here, and told to the platform, whose next plan
184
300
  // drives what failed first.
185
- const results = journeyResults(run.view);
186
- await savePlan(deps, options.sessionId, { planId, script, results, ...appControlsOf(run.toolCalls, crawled) }, planFile);
187
- if (planId !== undefined)
188
- await reportPlanResults(platform, planId, results);
301
+ const results = journeyResults(run.view, run.journeys);
302
+ await savePlan(deps, options.sessionId, {
303
+ planId,
304
+ script,
305
+ ...(focus === undefined ? {} : { focus }),
306
+ results,
307
+ ...appControlsOf(run.toolCalls, crawled),
308
+ }, planFile);
189
309
  for (const line of run.lines)
190
310
  narrate(line);
311
+ const cutOff = run.drives.find((d) => StopReason.BROKEN === d.stopReason);
191
312
  narrate(run.stopped
192
313
  ? 'Autonomous driving switched off — the Harness stopped. What it drove is kept.'
193
- : `Harness finished the plan — ${String(run.lines.filter((l) => l.startsWith('✓')).length)} of ${String(run.lines.length)} journeys passed. ${verdictLine(checkTally(run.toolCalls))}`);
314
+ : cutOff !== undefined
315
+ ? msgDriveCutOff(cutOff.error)
316
+ : // One verdict, the journeys': the count of passed journeys is in it, said once.
317
+ `Harness finished the plan${answeredBy(run.journeys)}. ${verdictLine(checkTally(run.toolCalls), undefined, results)}`);
194
318
  const sum = (pick) => run.drives.reduce((n, r) => n + pick(r), 0);
195
319
  // A model drive that broke breaks the run: "finished" over a platform that answered 500 hid it.
196
- const broke = run.drives.find((d) => StopReason.BROKEN === d.stopReason);
320
+ const broke = cutOff;
197
321
  const drive = {
198
322
  stopReason: run.stopped
199
323
  ? StopReason.STOPPED
@@ -215,7 +339,11 @@ export async function exploreScript(deps, env, options, before) {
215
339
  },
216
340
  proved: run.view.lanes.some((lane) => lane.journeys.some((card) => ScriptStatus.PASSED === card.status)),
217
341
  // Unmet if any journey's goal was judged unmet; met only when every judged one was.
218
- ...goalOfRun(run.drives),
342
+ ...goalOfRun(run.drives, results),
343
+ // What every lane cost, as the platform said; a planned run dropped it and read as free.
344
+ ...(run.drives.some((d) => d.creditsSpent !== undefined) || planned.planCredits !== undefined
345
+ ? { creditsSpent: sum((r) => r.creditsSpent ?? 0) + (planned.planCredits ?? 0) }
346
+ : {}),
219
347
  };
220
348
  const reconciled = reconcileFlows(before, await reads.flows.list(), run.toolCalls);
221
349
  const runIds = lanes.all().flatMap((id) => {
@@ -226,22 +354,86 @@ export async function exploreScript(deps, env, options, before) {
226
354
  ...reconciled.savedFlows,
227
355
  ...reconciled.rewroteFlows,
228
356
  ]);
357
+ await refreshMap(deps, options.sessionId, map, run.toolCalls);
358
+ // The texts a named journey quoted must be on the page at the end, hunted for first (a goal the
359
+ // drive walked past or stopped short of is looked for, not graded where it stood), and not counted
360
+ // when the page showed them before the drive began.
361
+ // Lanes in their own browsers were graded where they drove, and a goal any lane proved is proved;
362
+ // lanes taking turns here end on this tab, so it is graded here.
363
+ const graded = 0 < laneGrades.length
364
+ ? bestOfLanes(laneGrades)
365
+ : await huntAndGrade(deps, endInvoke, {
366
+ sessionId: options.sessionId,
367
+ goals: endGoalsAsked,
368
+ expect: options.expect,
369
+ opening,
370
+ journey: focus,
371
+ map,
372
+ own,
373
+ reached: pagesReached(run.toolCalls),
374
+ typed: typedValues(run.toolCalls),
375
+ });
376
+ const goals = graded.goals;
377
+ for (const id of lanes.all())
378
+ noteHarnessDisparity(id, graded.disparity);
379
+ const goalMet = goalOfDrive(drive.goalMet, goals, actedOnApp(run.toolCalls));
380
+ if (0 < goals.length)
381
+ for (const id of lanes.all())
382
+ noteHarnessGoal(id, goalMet);
383
+ // After the goals are graded: a journey that "passed" over goals that came back unmet is not.
384
+ // ponytail: one run-wide goalMet on every journey; per-journey once lanes grade their own goals.
385
+ if (planId !== undefined)
386
+ await reportPlanResults(platform, planId, goalMet === undefined ? results : results.map((r) => ({ ...r, goalMet })), runIds);
387
+ // ponytail: every lane is given the run's time; per-lane timing if lanes ever report their own.
388
+ for (const id of lanes.all())
389
+ noteHarnessSpan(id, deps.now() - runStarted);
229
390
  return {
230
- drive,
391
+ // The hunt's navigations too, after the goal was decided on what the plan itself drove.
392
+ drive: {
393
+ ...drive,
394
+ toolCalls: [...drive.toolCalls, ...graded.moved],
395
+ ...(goalMet === undefined ? {} : { goalMet }),
396
+ },
231
397
  plan,
232
398
  driverName,
233
399
  ...reconciled,
234
400
  unverifiedFlows,
235
- // The texts a named journey quoted must be on the page at the end, checked as the persona
236
- // drive always checked them.
237
- goals: await checkGoals((name, args) => ports.toolset(pinned(options).sessionId, focus).invoke(name, args), options.goals ?? goalsIn(focus)),
401
+ goals,
402
+ ...(0 === graded.disparity.length ? {} : { disparity: graded.disparity }),
238
403
  ...(0 === runIds.length ? {} : { runIds }),
404
+ ...(planId === undefined ? {} : { planId }),
405
+ journeys: results,
239
406
  planLines: [
240
407
  `Plan · ${String(script.journeys.length)} journeys in ${String(script.lanes.length)} lane(s)`,
241
408
  ...run.lines,
242
409
  ],
243
410
  };
244
411
  }
412
+ /**
413
+ * How the journeys were answered: replayed with no model, or driven by it and what that cost. Only
414
+ * what was measured; what a replay saved is not, since its journey was not also driven to compare.
415
+ */
416
+ function answeredBy(journeys) {
417
+ if (0 === journeys.length)
418
+ return '';
419
+ const driven = journeys.filter((j) => JourneyBy.MODEL === j.by);
420
+ const replayed = journeys.filter((j) => JourneyBy.REPLAY === j.by).length;
421
+ const tokens = driven.reduce((n, j) => n + j.tokens, 0);
422
+ return ` (${String(replayed)} replayed with no model, ${String(driven.length)} driven by the model${0 === driven.length ? '' : `, ${String(tokens)} tokens`})`;
423
+ }
424
+ /**
425
+ * Every text the plan writes down that a page could show back: journey titles, open goals, personas.
426
+ * The platform names the saved plan after them, so they are the Harness's words, never evidence.
427
+ */
428
+ function scriptTexts(script) {
429
+ return [
430
+ ...script.journeys.flatMap((j) => [
431
+ j.title,
432
+ ...j.steps.flatMap((s) => ('goal' in s && s.goal !== undefined ? [s.goal] : [])),
433
+ ]),
434
+ ...script.personas.map((p) => p.journey),
435
+ ];
436
+ }
245
437
  /** What the project still owes, in its own words: the user's recent request, then open intents. */
246
438
  async function memoryGoals(deps, sessionId) {
247
439
  const goals = [];
@@ -290,8 +482,14 @@ async function savePlan(deps, sessionId, plan, file) {
290
482
  return file;
291
483
  }
292
484
  }
293
- /** The run's goal verdict: false if any drive missed its goal, true if all judged ones reached it. */
294
- function goalOfRun(drives) {
485
+ /**
486
+ * The run's goal verdict: false if any drive missed its goal, true if all judged ones reached it.
487
+ * Every journey passed is the page's answer, already graded at each journey's end: a driver's own
488
+ * "not done" (a lane whose model call failed) read "but the goal was not reached" beside it.
489
+ */
490
+ export function goalOfRun(drives, journeys) {
491
+ if (0 < journeys.length && journeys.every((j) => ScriptStatus.PASSED === j.status))
492
+ return {};
295
493
  const judged = drives.flatMap((d) => (d.goalMet === undefined ? [] : [d.goalMet]));
296
494
  return 0 === judged.length ? {} : { goalMet: judged.every(Boolean) };
297
495
  }
@@ -316,6 +514,26 @@ async function crawlApp(deps, options, harness, driver) {
316
514
  return undefined;
317
515
  }
318
516
  }
517
+ /** The platform plan the newest saved run as `focus` ran, or undefined when none did. */
518
+ async function planMadeFor(deps, sessionId, focus) {
519
+ try {
520
+ const dir = reticleDirPaths(sessionRoot(deps, sessionId)).plans;
521
+ const files = (await deps.fs.readdir(dir))
522
+ .filter((f) => f.endsWith('.json'))
523
+ .sort()
524
+ .reverse();
525
+ for (const file of files) {
526
+ const saved = asRecord(JSON.parse(await deps.fs.readFile(join(dir, file))));
527
+ const planId = saved['planId'];
528
+ if (focus === saved['focus'] && 'string' === typeof planId)
529
+ return planId;
530
+ }
531
+ }
532
+ catch {
533
+ /* no plans yet: this persona is planned afresh */
534
+ }
535
+ return undefined;
536
+ }
319
537
  /**
320
538
  * The controls the last crawl saw, from the newest saved plan that kept them. The planner reads the
321
539
  * start page only; without these it never learned the refund buttons on another page existed, and
@@ -0,0 +1,5 @@
1
+ import type { ToolDeps } from './tool-kit.js';
2
+ /** Said when the agent acts in a tab the Harness is driving. */
3
+ export declare const msgHarnessHasTheTab: (runId: string) => string;
4
+ /** The Harness run driving the tab this agent call would act on, unless the call is the Harness's. */
5
+ export declare function harnessDriving<Ext>(deps: ToolDeps<Ext>, args: Record<string, unknown>): string | undefined;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * One driver per tab. The Harness clicking through a page while the agent clicks too is two hands on
3
+ * one mouse: neither result means anything. While a Harness run drives a tab, the agent's own
4
+ * actions in it are refused with how to wait for the run or stop it; its reads still run.
5
+ */
6
+ import { ReticleTool } from '@reticlehq/core';
7
+ import { runningDrive, runningDrives } from '../../features/harness/drive-runs.js';
8
+ import { currentDrivenBy } from '../../hooks/driven-by.js';
9
+ import { sessionIdFromArgs } from './tools-helpers.js';
10
+ /** Said when the agent acts in a tab the Harness is driving. */
11
+ export const msgHarnessHasTheTab = (runId) => `Reticle Harness is driving this tab now (run ${runId}), so this action did not run. Wait for ` +
12
+ `its result with ${ReticleTool.VERIFY} { action: "explore", runId: "${runId}" }, or stop it ` +
13
+ `with the same call and stop: true, then act.`;
14
+ /** The Harness run driving the tab this agent call would act on, unless the call is the Harness's. */
15
+ export function harnessDriving(deps, args) {
16
+ // No drive anywhere is the usual case, and it touches nothing: not even which tab this call is.
17
+ if (currentDrivenBy() !== undefined || 0 === runningDrives().length)
18
+ return undefined;
19
+ let sessionId;
20
+ try {
21
+ sessionId = deps.sessions.resolve(sessionIdFromArgs(args)).id;
22
+ }
23
+ catch {
24
+ return undefined; // no tab: the action fails on its own, with the no-session answer
25
+ }
26
+ return runningDrive(sessionId)?.harnessRun;
27
+ }
@@ -17,6 +17,8 @@ export interface ReticleToolsetOptions {
17
17
  only?: readonly string[];
18
18
  /** Stamped on every action this drive journals, so its verdicts fold into a run of their own. */
19
19
  drivenBy?: DrivenBy;
20
+ /** The person's own request: the only text that lets the drive press an outward control. */
21
+ asked?: string;
20
22
  /** The pinned session wins over any a call names: a remote caller never reaches another tab. */
21
23
  locked?: boolean;
22
24
  }
@@ -28,6 +30,12 @@ export interface ReticleToolsetOptions {
28
30
  * a harness run a measurement of the product rather than of a test harness.
29
31
  */
30
32
  export declare function reticleToolset(deps: ToolDeps, options?: ReticleToolsetOptions): HarnessToolset;
33
+ /**
34
+ * A request the Harness declares must succeed (`ok: true`) unless its claim names a status. A net
35
+ * claim with no status is met by any answer, so a sign-in whose `POST /api/login` came back 401 was
36
+ * counted as a check that held. Applied to the top-level claim of a wait or an assert.
37
+ */
38
+ export declare function requestMustSucceed(args: Record<string, unknown>): Record<string, unknown>;
31
39
  /**
32
40
  * Stamp the drive's own session onto a call.
33
41
  *
@@ -9,12 +9,13 @@
9
9
  */
10
10
  import { z } from 'zod';
11
11
  import { zodToJsonSchema } from 'zod-to-json-schema';
12
- import { AppRuntime, ConsequenceKind, NetInitiator, ReticleTool, } from '@reticlehq/core';
12
+ import { AppRuntime, ConsequenceKind, NetInitiator, PredicateKind, ReticleTool, } from '@reticlehq/core';
13
13
  import { TOOLS } from './tools.js';
14
14
  import { runTool } from './invoke-tool.js';
15
15
  import { TOOL_SURFACE, filterTools } from './tool-surface.js';
16
16
  import { withTimeout } from '../../features/harness/with-timeout.js';
17
17
  import { runDrivenBy } from '../../hooks/driven-by.js';
18
+ import { noteDriveStep } from '../../features/harness/drive-runs.js';
18
19
  /**
19
20
  * The two tools the harness is given beyond the advertised surface.
20
21
  *
@@ -25,7 +26,7 @@ import { runDrivenBy } from '../../hooks/driven-by.js';
25
26
  * sometimes skip, which silently turns the cheap path off.
26
27
  */
27
28
  /**
28
- * Beyond the default surface, the three tools a drive cannot do its job without.
29
+ * Beyond the default surface, the tools a drive cannot do its job without.
29
30
  *
30
31
  * RECORD and FLOW_SAVE are how a drive keeps what it drove. FLOW_REPLAY is how it avoids driving
31
32
  * the same thing twice — it was absent, so a driver handed a plan full of already-recorded journeys
@@ -35,6 +36,9 @@ const HARNESS_EXTRA_TOOLS = [
35
36
  ReticleTool.RECORD,
36
37
  ReticleTool.FLOW_SAVE,
37
38
  ReticleTool.FLOW_REPLAY,
39
+ // A goal below the fold stayed `unknown` on a drive told to scroll to it: nothing it was offered
40
+ // could scroll. This one brings an element into view by the same query a find uses.
41
+ ReticleTool.SCROLL_TO,
38
42
  ];
39
43
  /**
40
44
  * The one deliberate subtraction.
@@ -144,17 +148,36 @@ export function reticleToolset(deps, options = {}) {
144
148
  // list, and this is the same recovery the MCP surface gives an agent that does the same.
145
149
  return { error: `unknown tool ${target ?? name}`, available: [...byName.keys()] };
146
150
  }
147
- const pinned = pinSession(targetArgs, options.sessionId, true === options.locked);
151
+ const pinned = pinSession(options.drivenBy === undefined ? targetArgs : requestMustSucceed(targetArgs), options.sessionId, true === options.locked);
148
152
  const scoped = isDesktopSession(deps, pinned['sessionId'])
149
153
  ? desktopBackendClaims(pinned)
150
154
  : pinned;
151
155
  const drivenBy = options.drivenBy;
156
+ if (drivenBy !== undefined)
157
+ noteDriveStep(drivenBy.harness, tool.name);
152
158
  return withTimeout(drivenBy === undefined
153
159
  ? runTool(tool, deps, scoped)
154
- : runDrivenBy(drivenBy, () => runTool(tool, deps, scoped)), TOOL_TIMEOUT_MS, `${tool.name} never returned`);
160
+ : runDrivenBy(drivenBy, () => runTool(tool, deps, scoped), options.asked), TOOL_TIMEOUT_MS, `${tool.name} never returned`);
155
161
  },
156
162
  };
157
163
  }
164
+ /**
165
+ * A request the Harness declares must succeed (`ok: true`) unless its claim names a status. A net
166
+ * claim with no status is met by any answer, so a sign-in whose `POST /api/login` came back 401 was
167
+ * counted as a check that held. Applied to the top-level claim of a wait or an assert.
168
+ */
169
+ export function requestMustSucceed(args) {
170
+ const out = { ...args };
171
+ for (const key of ['until', 'predicate']) {
172
+ const claim = args[key];
173
+ if ('object' !== typeof claim || null === claim)
174
+ continue;
175
+ const p = claim;
176
+ if (PredicateKind.NET === p['kind'] && undefined === p['status'] && undefined === p['ok'])
177
+ out[key] = { ...p, ok: true };
178
+ }
179
+ return out;
180
+ }
158
181
  /**
159
182
  * Stamp the drive's own session onto a call.
160
183
  *
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The notes a person sent from the HUD, handed to the agent on whatever Reticle call it makes next.
3
+ *
4
+ * Act tools already splice them (`withControl`); every other tool did not, so a note waited until
5
+ * the agent happened to drive the page or poll `messages`. Taken here, once, from the tab the call
6
+ * is about; a call that names no tab and cannot resolve one takes every tab's, since a note held
7
+ * back is a note the person believes was read.
8
+ */
9
+ import type { Session } from '../../portal/session/session.js';
10
+ import type { SessionManager } from '../../portal/session/session-manager.js';
11
+ import type { SessionState } from '@reticlehq/core';
12
+ export interface HumanNotes {
13
+ state: SessionState;
14
+ guidance: string[];
15
+ }
16
+ export declare function takeHumanNotes(sessions: SessionManager, sessionId: string | undefined, session: Session | undefined): HumanNotes | undefined;
@@ -0,0 +1,27 @@
1
+ export function takeHumanNotes(sessions, sessionId, session) {
2
+ let target = session;
3
+ if (target === undefined) {
4
+ try {
5
+ target = sessions.resolve(sessionId);
6
+ }
7
+ catch {
8
+ target = undefined;
9
+ }
10
+ }
11
+ // ponytail: an unresolvable call takes every tab's notes; per-agent routing is the upgrade if two
12
+ // agents ever share one daemon on different apps and a note lands with the wrong one.
13
+ try {
14
+ const holding = (target === undefined ? (sessions.all?.() ?? []) : [target]).filter((tab) => 0 < tab.inboxSize());
15
+ const first = holding[0];
16
+ if (first === undefined)
17
+ return undefined;
18
+ return {
19
+ state: first.getState(),
20
+ guidance: holding.flatMap((tab) => tab.drainInbox().map((message) => message.text)),
21
+ };
22
+ }
23
+ catch {
24
+ // A courtesy on every call is never the reason a call fails; the notes stay queued.
25
+ return undefined;
26
+ }
27
+ }
@@ -1,4 +1,5 @@
1
- import type { ToolDef, ToolDeps } from './tool-kit.js';
1
+ import { type NoticeFold } from './agent/notices.js';
2
+ import type { ToolCall, ToolDef, ToolDeps } from './tool-kit.js';
2
3
  export declare const SESSION_BOUND_TOOLS: ReadonlySet<string>;
3
4
  /**
4
5
  * Tools that carry a `sessionId` arg but are NOT live-session-health tools — they read/write
@@ -7,4 +8,6 @@ export declare const SESSION_BOUND_TOOLS: ReadonlySet<string>;
7
8
  * `sessionId`-bearing tool to be classified into exactly one set (bound XOR exempt).
8
9
  */
9
10
  export declare const SESSION_EXEMPT_TOOLS: ReadonlySet<string>;
10
- export declare function runTool<Ext>(tool: ToolDef<Ext>, deps: ToolDeps<Ext>, args: Record<string, unknown>): Promise<unknown>;
11
+ export declare function runTool<Ext>(tool: ToolDef<Ext>, deps: ToolDeps<Ext>, given: Record<string, unknown>, call?: ToolCall): Promise<unknown>;
12
+ /** Advisories that become once-per-session notice lines. See agent/notices.ts. */
13
+ export declare const NOTICE_FOLD: NoticeFold;