@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
@@ -1,678 +0,0 @@
1
- /**
2
- * A harness driver with no text generator in it.
3
- *
4
- * `driver.ts` binds the harness to a frontier model, and the comment at the top of it has always
5
- * claimed the tier is "a standing test of the design": the driver is not reasoning about business
6
- * logic, it is choosing what to touch next and saying what it expects, and if that needed a large
7
- * model then the engine would not be doing its job. Nothing tested the claim, because the only
8
- * driver in the repo was a large model.
9
- *
10
- * This is the test. Jev is a System One model — it evaluates typed questions against a state and
11
- * answers with probabilities, in one parallel pass, and it does not emit prose. It therefore cannot
12
- * invent a tool call. So every call this driver makes is built HERE, deterministically, out of what
13
- * the page actually offers, and the model's only contribution is picking one of them. That is a
14
- * strictly smaller surface than a generating driver has, and it is the whole reason this is worth
15
- * having: a driver that cannot name an element that is not on the page cannot hallucinate one.
16
- *
17
- * What did NOT move: the verdict. `decideVerified` still decides, on evidence, with no model in it.
18
- * A System One model cannot hallucinate a type, but it still returns a PROBABILITY, and a
19
- * probability is not proof. Anyone reading this file as an invitation to let Jev answer
20
- * "did it work?" should read `engine/src/evidence/verified.ts` first — the seventeen clauses there
21
- * exist because this product is the verdict, and a verdict sourced from a model's confidence is the
22
- * thing Reticle sells the absence of.
23
- */
24
- import { RETICLE_URL_PARAM, ReticleEnv, ReticleTool, platformCredentialFrom, asRecord, parseInteractive, } from '@reticlehq/core';
25
- import { FINISH_TOOL } from './harness.js';
26
- import { heuristicFillValue } from './fill-values.js';
27
- export const DEFAULT_JEV_MODEL = 'jev-latest';
28
- export const DEFAULT_JEV_BASE_URL = 'https://api.typesafe.ai';
29
- /**
30
- * TypeSafe's own path, and the platform's.
31
- *
32
- * They differ, and forgetting that broke the one claim this whole feature exists to make. A daemon
33
- * holding only a platform key correctly chose the `jev` driver, and then posted to the upstream's
34
- * path on the platform's host: `jev 404: Route POST:/v1/systemone not found`. Nothing was driven.
35
- *
36
- * It was not caught earlier because the daemon under test also had a direct `JEV_API_KEY` exported,
37
- * so it took the direct branch and never went near the platform — the "only a platform key" run was
38
- * not, in fact, only a platform key. The sibling OpenAI driver already routed on this exact
39
- * distinction; this one did not.
40
- */
41
- const SYSTEMONE_PATH = '/v1/systemone';
42
- const PLATFORM_PATH = '/v1/model/systemone';
43
- /**
44
- * Tool names this driver emits.
45
- *
46
- * Taken from core rather than spelled again here: these cross a wire, and a second spelling of a
47
- * wire string is a rename waiting to half-land. `finish` is the exception — it is the harness's own
48
- * synthetic tool and has no wire identity, so it comes from the loop that defines it.
49
- */
50
- const Tool = {
51
- SNAPSHOT: ReticleTool.SNAPSHOT,
52
- ACT_AND_WAIT: ReticleTool.ACT_AND_WAIT,
53
- OBSERVE: ReticleTool.OBSERVE,
54
- STATE: ReticleTool.STATE,
55
- RECORD: ReticleTool.RECORD,
56
- FLOW_SAVE: ReticleTool.FLOW_SAVE,
57
- FLOW_REPLAY: ReticleTool.FLOW_REPLAY,
58
- NAVIGATE: ReticleTool.NAVIGATE,
59
- FINISH: FINISH_TOOL.name,
60
- };
61
- /** The synthetic option meaning "stop driving". Not a tool arg — a key in the choice set. */
62
- const FINISH_OPTION = 'finish';
63
- /** The synthetic option meaning "I cannot tell from this page; look again". */
64
- const RELOOK_OPTION = 'look_again';
65
- /** Back to the page before this one — a dead end used to end the whole drive where it stood. */
66
- const BACK_OPTION = 'go_back';
67
- /**
68
- * Tools the model may route to, beyond acting on a control.
69
- *
70
- * This driver used to hard-code every tool and ask only WHICH ELEMENT — so a drive could never
71
- * decide to go and look at what the app actually did, only to click something else. Reading a
72
- * channel is a real choice with a real cost, and it is the choice that turns "the page looks fine"
73
- * into evidence, so it belongs to the model rather than to a branch in this file.
74
- *
75
- * The candidates are still ENUMERATED here. Jev picks a key from a set we built, which is what
76
- * makes a driver that cannot name a tool it does not have.
77
- */
78
- const OBSERVE_OPTION = 'observe_what_the_app_did';
79
- const STATE_OPTION = 'read_app_state';
80
- /** The permission gate on a destructive control, as the refusal names it. */
81
- const DANGEROUS_ARG = 'confirmDangerous';
82
- /**
83
- * How many interactive elements may go into one choice set.
84
- *
85
- * Not a token budget — Jev prices the state, and 44 candidates measured at 1,421 input tokens, which
86
- * is noise. It is a QUALITY bound: a list of two hundred near-identical row links is a page where the
87
- * useful next action is a control, not a row, and offering all of them mostly buys ties. Document
88
- * order is kept, so the controls a page puts first stay in.
89
- */
90
- const MAX_CANDIDATES = 40;
91
- /** Above this, `journey_complete` is taken as a yes. Deliberately high — finishing early loses coverage. */
92
- const COMPLETE_THRESHOLD = 0.7;
93
- /**
94
- * Turns held back at the end of the budget to stop recording, save the flow and finish.
95
- *
96
- * Without this the driver spends every step exploring and the run ends on BUDGET with `savedFlows`
97
- * empty — which is not a cheap drive, it is a drive that produced nothing. Measured before the
98
- * reserve existed: 24 steps, a real journey driven through a real app, and no flow at the end of it,
99
- * because the teardown never got a turn. A saved flow is the entire product of an explore, so the
100
- * last three turns are not negotiable and the exploring gets what is left.
101
- */
102
- const TEARDOWN_TURNS = 3;
103
- /**
104
- * The app's own route, with Reticle's fingerprints wiped off it.
105
- *
106
- * A pooled launcher appends `__reticle_opened=1` to the URL it opens, and that parameter ended up
107
- * inside a declared consequence: "this click leaves a route containing /?__reticle_opened=1". On a
108
- * hash-routed app that claim can never hold, because the query string never changes -- only the
109
- * fragment does -- so every navigation link was a guaranteed red, and the red was about OUR query
110
- * parameter rather than about the application. Found by making a failed action say what it claimed;
111
- * before that it read as an ordinary "the declared consequence did not hold".
112
- *
113
- * The fragment is kept, and is the point: on a hash-routed app it is the only part that moves.
114
- */
115
- export function appRoute(route) {
116
- const [pathAndQuery = '', ...hash] = route.split('#');
117
- const [path = '', query] = pathAndQuery.split('?');
118
- const kept = query === undefined
119
- ? ''
120
- : query
121
- .split('&')
122
- .filter((pair) => !Object.values(RETICLE_URL_PARAM).some((p) => pair.startsWith(`${p}=`)))
123
- .join('&');
124
- const fragment = 0 === hash.length ? '' : `#${hash.join('#')}`;
125
- return `${path}${0 === kept.length ? '' : `?${kept}`}${fragment}`;
126
- }
127
- /**
128
- * How many of the app's declared signals are offered as consequences.
129
- *
130
- * Every one is a line in a prompt and a branch for the model to weigh, and a contract can declare
131
- * dozens. The plan hands them over untested-first, so a cap takes the ones a drive most needs to
132
- * claim rather than whichever the contract happened to list first.
133
- */
134
- const MAX_SIGNAL_CONSEQUENCES = 6;
135
- /**
136
- * The consequences on offer, given where the app currently is and what it says it can do.
137
- *
138
- * Two things shape this list, and the second one was missing for a whole release.
139
- *
140
- * It is a function of the CURRENT ROUTE, because "this takes us off the page we are on" is only
141
- * falsifiable against a route actually read.
142
- *
143
- * It is also a function of the app's OWN VOCABULARY, because an unbound claim cannot be saved. A
144
- * drive that declares "some signal fires" proves something real at the time and writes a flow that
145
- * asserts nothing, so every later replay passes as long as the clicks still land. Offering the
146
- * declared signal NAMES turns the same choice into one a flow can keep, and costs nothing extra:
147
- * the names are already read out of `.reticle` to build the plan.
148
- */
149
- export function consequencesFor(route, vocabulary = []) {
150
- const base = {};
151
- // The app's own words first. A signal is the strongest evidence there is -- the application
152
- // itself saying what it did -- and a named one is the only form of that a flow can carry.
153
- for (const name of vocabulary.slice(0, MAX_SIGNAL_CONSEQUENCES)) {
154
- base[`signal ${name}`] = {
155
- predicate: { kind: 'signal', name },
156
- describes: `The app fires its own "${name}" signal.`,
157
- recordable: true,
158
- };
159
- }
160
- base['saves'] = {
161
- predicate: { kind: 'net', method: 'POST' },
162
- describes: 'The app POSTs to its backend — expect this for anything that creates or submits.',
163
- recordable: true,
164
- };
165
- base['updates'] = {
166
- predicate: { kind: 'net', method: 'PATCH' },
167
- describes: 'The app PATCHes its backend — expect this for a setting or an edit being saved.',
168
- recordable: true,
169
- };
170
- /*
171
- * There is deliberately no GET offer.
172
- *
173
- * It was there for one run and cost 7 of 9 actions: a dashboard polls, so a GET is in flight
174
- * before most clicks, and the engine correctly answers `no-fault` -- the consequence was already
175
- * true, so the action proved nothing about it. A claim that background traffic satisfies is not a
176
- * claim. Mutations are the opposite: a POST or a PATCH inside the action's own window is almost
177
- * always the action's own doing, which is why those two survive and reading does not.
178
- *
179
- * A filter or a search therefore has nothing specific to claim here, and should claim `nothing`
180
- * rather than something that cannot fail.
181
- */
182
- base['any'] = {
183
- predicate: { kind: 'anyOf', predicates: [{ kind: 'signal' }, { kind: 'net' }] },
184
- describes: 'The app sends a request OR fires a signal, but which one is not predictable. Proves the ' +
185
- 'action did something; too vague to save as a regression test.',
186
- recordable: false,
187
- };
188
- /**
189
- * "This takes us off the page we are on."
190
- *
191
- * A bare `{ kind: 'route' }` is unconditionally true — there is always a current route — so it
192
- * cannot be declared. Negating a route we have actually READ is a different thing entirely, and
193
- * it is properly falsifiable: before the click we are on that route, so the pre-check is false
194
- * and nothing is `already_true`; after a real navigation we are not, so it holds; and if the
195
- * control is dead the route never changes and the verdict is a CORRECT red.
196
- *
197
- * Its absence was a defect with teeth. Driving a real dashboard, the only consequences on offer
198
- * were `signal` and `net` — so every click on a nav link, which changes the route client-side and
199
- * touches neither, was handed a declaration it could not satisfy. 21 of 42 actions came back
200
- * `no`, and not one of them was a bug in the application. A false red is exactly as dishonest as
201
- * a false green, and it is worse here than saying nothing would have been.
202
- *
203
- * Skipped at the root (`/`), where `contains` would match every route and the negation could
204
- * never hold.
205
- */
206
- if (route !== undefined && 1 < route.length) {
207
- base['navigates'] = {
208
- predicate: { kind: 'not', predicate: { kind: 'route', contains: route } },
209
- describes: `The app leaves the current page (${route}) — expect this for a navigation link or anything that opens another screen.`,
210
- // A negation has no representation a replay can re-check, so this one proves the click and
211
- // saves nothing. Kept anyway: without it, every nav link on a client-routed app was handed a
212
- // declaration it could not satisfy, and 21 of 42 actions came back a false red. A drive that
213
- // is honest now beats a flow that would have been stronger later.
214
- recordable: false,
215
- };
216
- }
217
- return base;
218
- }
219
- /**
220
- * Declaring nothing, named so it can be CHOSEN rather than defaulted to.
221
- *
222
- * A control that genuinely changes nothing observable — opening a menu, focusing a field — should
223
- * be recorded as such, not given an expectation it will fail. The verdict then comes back
224
- * `no-fault`, which is honest: nothing was claimed, so nothing was proved.
225
- */
226
- const NO_CONSEQUENCE = 'nothing';
227
- /** Roles that want text typed into them rather than clicked. */
228
- const TEXT_ROLES = new Set(['textbox', 'searchbox', 'spinbutton']);
229
- /** Roles that toggle. */
230
- const TOGGLE_ROLES = new Set(['checkbox', 'radio', 'switch']);
231
- /** The plan kinds, as the caller spells them. */
232
- const PLAN_REPLAY = 'replay';
233
- /**
234
- * Read this driver's configuration out of the environment.
235
- *
236
- * A direct Jev key wins over the platform key, so that someone debugging the upstream is never
237
- * quietly talking to the proxy they were trying to bypass. Returns `undefined` when neither is set,
238
- * which is a routine answer and not a failure — the caller falls back to the Anthropic driver.
239
- */
240
- export function jevOptionsFromEnv(env) {
241
- const direct = env[ReticleEnv.HARNESS_JEV_KEY];
242
- if (direct !== undefined && 0 < direct.length) {
243
- const baseUrl = env[ReticleEnv.HARNESS_JEV_URL];
244
- return {
245
- apiKey: direct,
246
- ...(baseUrl === undefined || 0 === baseUrl.length ? {} : { baseUrl }),
247
- };
248
- }
249
- // The ordinary path: the key the user minted on the platform, against the platform's own proxy.
250
- // Reticle never ships a Jev key; the URL is the configured platform, else the hosted service.
251
- const cloud = platformCredentialFrom(env);
252
- if (cloud === undefined)
253
- return undefined;
254
- return { apiKey: cloud.apiKey, baseUrl: cloud.url };
255
- }
256
- /** Strip the snapshot's list marker, so a description reads as a phrase rather than a bullet. */
257
- function cleanDesc(desc) {
258
- return desc.replace(/^-\s*/, '').trim();
259
- }
260
- /** The role is the first word of a snapshot line: `- textbox "Card number"`. */
261
- function roleOf(desc) {
262
- return cleanDesc(desc).split(/\s+/)[0]?.toLowerCase() ?? '';
263
- }
264
- /** The accessible name, which the snapshot quotes. */
265
- function nameOf(desc) {
266
- return /"([^"]*)"/.exec(desc)?.[1] ?? '';
267
- }
268
- /** The action verb a role wants. */
269
- function actionFor(role) {
270
- if (TEXT_ROLES.has(role))
271
- return 'fill';
272
- if (TOGGLE_ROLES.has(role))
273
- return 'check';
274
- return 'click';
275
- }
276
- /**
277
- * Derive the drive's state from the history the loop hands us.
278
- *
279
- * Deliberately derived rather than held in a closure. The loop owns what gets remembered — it does
280
- * the truncation and the budget — so a driver that kept its own parallel copy would have two
281
- * versions of the same fact and no rule for which one is right when a turn is retried or dropped.
282
- */
283
- function readState(history) {
284
- const state = {
285
- open: undefined,
286
- unsaved: [],
287
- saved: [],
288
- tree: undefined,
289
- route: undefined,
290
- pages: [],
291
- proved: [],
292
- replayed: [],
293
- acted: [],
294
- blocked: [],
295
- turns: 0,
296
- };
297
- for (const entry of history) {
298
- if ('tool' !== entry.role)
299
- continue;
300
- state.turns += 1;
301
- for (const outcome of entry.outcomes) {
302
- if (Tool.RECORD === outcome.name) {
303
- const args = asRecord(outcome.args);
304
- const named = args['recordingName'];
305
- if ('string' === typeof named) {
306
- if ('start' === args['action'] && !outcome.isError) {
307
- state.open = { name: named, slug: slugAfter(named) };
308
- }
309
- if ('stop' === args['action']) {
310
- state.open = undefined;
311
- // A stop that ERRORED still closes our side of it: re-stopping a recording that is not
312
- // running loops forever, and the save below is refused either way, which is visible.
313
- state.unsaved.push(named);
314
- }
315
- }
316
- }
317
- if (Tool.FLOW_REPLAY === outcome.name) {
318
- // Recorded whether it passed or failed: a replay that went red is a FINDING, and re-running
319
- // it would bury the finding under a loop instead of moving on to the next plan step.
320
- const flowName = asRecord(outcome.args)['flowName'];
321
- if ('string' === typeof flowName)
322
- state.replayed.push(flowName);
323
- }
324
- if (Tool.FLOW_SAVE === outcome.name) {
325
- const flowName = asRecord(outcome.args)['flowName'];
326
- if ('string' === typeof flowName) {
327
- state.unsaved = state.unsaved.filter((n) => n !== flowName);
328
- if (!outcome.isError)
329
- state.saved.push(flowName);
330
- }
331
- }
332
- if (Tool.SNAPSHOT === outcome.name && !outcome.isError) {
333
- const result = asRecord(outcome.result);
334
- const tree = result['tree'];
335
- if ('string' === typeof tree)
336
- state.tree = tree;
337
- const route = asRecord(result['status'])['route'];
338
- if ('string' === typeof route) {
339
- state.route = appRoute(route);
340
- if (state.pages.at(-1) !== route)
341
- state.pages.push(route);
342
- }
343
- }
344
- if (Tool.NAVIGATE === outcome.name)
345
- state.tree = undefined;
346
- if (Tool.ACT_AND_WAIT === outcome.name) {
347
- const ref = asRecord(outcome.args)['ref'];
348
- const failure = asRecord(outcome.result)['error'];
349
- const refused = outcome.isError && 'string' === typeof failure && failure.includes(DANGEROUS_ARG);
350
- const until = asRecord(asRecord(outcome.args)['until']);
351
- const signal = until['name'];
352
- if ('yes' === asRecord(outcome.result)['verified'] && 'string' === typeof signal)
353
- state.proved.push(signal);
354
- if ('string' === typeof ref) {
355
- // A refused act never happened, so it is not something this drive has driven. Recording
356
- // it as driven would retire the control after an attempt that never reached the app.
357
- if (refused)
358
- state.blocked.push(ref);
359
- else
360
- state.acted.push(ref);
361
- }
362
- // The page has almost certainly moved; the tree we hold describes a page that is gone.
363
- state.tree = undefined;
364
- }
365
- }
366
- }
367
- return state;
368
- }
369
- /** Build the choice set: every interactive element on the page, plus the two synthetic options. */
370
- function candidatesFrom(tree) {
371
- return parseInteractive(tree)
372
- .filter((item) => 0 < item.ref.length)
373
- .slice(0, MAX_CANDIDATES)
374
- .map((item) => ({ ref: item.ref, desc: cleanDesc(item.desc), role: roleOf(item.desc) }));
375
- }
376
- /**
377
- * The state Jev reads.
378
- *
379
- * It is the standing instruction, what has been driven, and the page — in that order, because the
380
- * question is always "what next, given where we are". Kept as plain lines rather than JSON: the
381
- * snapshot is already a line-per-element format a reader can follow, and wrapping it in braces costs
382
- * tokens to say nothing.
383
- */
384
- function buildState(system, history, drive, objective) {
385
- const goal = history.find((entry) => 'user' === entry.role)?.text ?? '';
386
- const driven = 0 === drive.acted.length
387
- ? ' (nothing yet)'
388
- : `\n${drive.acted.map((r, i) => ` ${i + 1}. acted on ${r}`).join('\n')}`;
389
- return [
390
- system,
391
- '',
392
- `OPENING INSTRUCTION: ${goal}`,
393
- // The one plan step this drive is currently FOR, said again next to the page rather than left
394
- // in a standing instruction twenty turns back. A model choosing a control should be reading
395
- // what it is trying to prove, not remembering it.
396
- ...(objective === undefined
397
- ? []
398
- : [`CURRENTLY TRYING TO PROVE: ${objective.target} — ${objective.why}`]),
399
- `ACTIONS DRIVEN SO FAR:${driven}`,
400
- '',
401
- 'CURRENT PAGE (interactive elements only):',
402
- drive.tree ?? '(not looked at yet)',
403
- ].join('\n');
404
- }
405
- /** One POST. Narrowed at the boundary rather than trusted, same as the Anthropic driver does. */
406
- async function callJev(options, state, questions) {
407
- const res = await options.doFetch(`${options.baseUrl}${options.path}`, {
408
- method: 'POST',
409
- headers: {
410
- authorization: `Bearer ${options.apiKey}`,
411
- 'content-type': 'application/json',
412
- },
413
- body: JSON.stringify({ state, model: options.model, questions }),
414
- });
415
- const text = await res.text();
416
- if (!res.ok)
417
- throw new Error(`jev ${res.status}: ${text.slice(0, 400)}`);
418
- return JSON.parse(text);
419
- }
420
- /**
421
- * The recording, and so the flow, this drive writes.
422
- *
423
- * A System One model cannot supply a name, so one is chosen here. It was briefly minted from a
424
- * module-level counter, which is wrong in the one place this code actually runs: a daemon is
425
- * long-lived and drives more than once, so the counter was shared between drives that know nothing
426
- * about each other, and the name a drive used depended on how many drives had happened before it in
427
- * that process. The name now comes from the drive's own history when there is one, and otherwise
428
- * from the caller — no globals, no clock, and the same history always yields the same name.
429
- */
430
- const DEFAULT_RECORDING_NAME = 'harness-drive';
431
- /**
432
- * A flow is opened per PAGE, not per drive, and the page names it.
433
- *
434
- * One recording for a whole drive is one enormous flow, and a saved flow is the entire product of
435
- * an explore — it is what replays deterministically forever with no model in the loop. Measured
436
- * against a real dashboard the frontier driver, which segments its recordings into named journeys,
437
- * left 12 flows behind; this driver left 1. Same coverage, a twelfth of the durable output.
438
- *
439
- * A System One model cannot name anything, so the name comes from the route — which is both
440
- * deterministic and the most honest label available, since the route is what actually scopes the
441
- * journey. Segmenting on route change means every page a drive visits becomes its own replayable
442
- * flow, and a flow that goes red names the page it belongs to.
443
- */
444
- function slugOf(route) {
445
- const path = (route ?? '').replace(/^.*#/, '').replace(/[?#].*$/, '');
446
- const slug = path
447
- .replace(/[^a-zA-Z0-9]+/g, '-')
448
- .replace(/^-+|-+$/g, '')
449
- .toLowerCase();
450
- return 0 === slug.length ? 'home' : slug;
451
- }
452
- /** The slug back out of a recording name, so a name and a route can be compared. */
453
- function slugAfter(name) {
454
- return name.startsWith(`${DEFAULT_RECORDING_NAME}-`)
455
- ? name.slice(DEFAULT_RECORDING_NAME.length + 1)
456
- : name;
457
- }
458
- /**
459
- * Build a driver backed by a System One model.
460
- *
461
- * Every turn emits exactly ONE call. The loop dispatches a turn's calls with `Promise.all`, so an
462
- * act and the snapshot that reads its result cannot be batched into one turn — they would race, and
463
- * the snapshot would describe a page mid-flight. One call per turn costs a step and buys a reading
464
- * that is actually of the page the action produced.
465
- */
466
- export function jevDriver(options) {
467
- const model = options.model ?? DEFAULT_JEV_MODEL;
468
- const baseUrl = options.baseUrl ?? DEFAULT_JEV_BASE_URL;
469
- const doFetch = options.fetch ?? ((url, init) => fetch(url, init));
470
- // A base URL that is not TypeSafe's is the platform's, which is the only other thing this talks
471
- // to — and it serves the same wire shape under its own path.
472
- const path = DEFAULT_JEV_BASE_URL === baseUrl ? SYSTEMONE_PATH : PLATFORM_PATH;
473
- const budget = options.maxSteps;
474
- const plan = options.plan ?? [];
475
- /**
476
- * The one fact the history cannot carry.
477
- *
478
- * Everything else this driver needs is DERIVED from the history the loop hands it, because the
479
- * loop owns what is remembered. "The model has said the app is covered" leaves no trace there —
480
- * the only thing it produces is a `record stop`, which is indistinguishable from the stop that
481
- * happens on every route change. Without it the drive closes the last journey, saves it, and
482
- * then cheerfully opens another one on the same page.
483
- *
484
- * Held rather than derived, and it only ever goes one way, for one drive.
485
- */
486
- let windingUp = false;
487
- // Tool-call ids only have to be unique within a turn, and this driver emits one call per turn.
488
- // A per-instance counter is therefore enough, and it keeps the clock out of pure logic.
489
- let callSeq = 0;
490
- const only = (call, text, usage) => ({
491
- text,
492
- calls: [call],
493
- ...(usage === undefined ? {} : { usage }),
494
- });
495
- const request = (tool, args) => {
496
- callSeq += 1;
497
- return { id: `jev-${String(callSeq)}-${tool}`, name: tool, args };
498
- };
499
- return {
500
- async turn(input) {
501
- const drive = readState(input.history);
502
- // ── deterministic scaffolding ────────────────────────────────────────────────────────────
503
- // Every step here has exactly one right answer, so asking a model would spend a call to be
504
- // told what the code already knows. The model is only consulted where there is a real choice.
505
- // Banking what has been driven always wins over driving more. A stopped recording that is
506
- // never saved is a journey nobody can replay, which is the whole point of the drive.
507
- const unsaved = drive.unsaved[0];
508
- if (unsaved !== undefined)
509
- return only(
510
- // No intent. A drive has no business rule of its own to state, and what it used to send
511
- // ("Autonomous coverage drive: N actions") was a count of what it did, filed in the ledger
512
- // as a rule and re-amended every time the count changed.
513
- request(Tool.FLOW_SAVE, { flowName: unsaved }), `save ${unsaved}`);
514
- /*
515
- * THE PLAN'S CHEAP HALF, and it runs before the model is asked anything.
516
- *
517
- * A journey already recorded replays deterministically for a few hundred tokens. Re-driving
518
- * it pays a frontier-priced loop to rediscover something sitting on disk, which is what every
519
- * run did before the plan existed. No Jev call is made here at all: there is no decision to
520
- * take, only work the caller already decided was worth doing.
521
- *
522
- * A replay that goes RED is a finding and the drive moves on — re-running it would bury the
523
- * finding in a loop. The verdict is on the tool result either way.
524
- */
525
- const nextReplay = plan.find((step) => PLAN_REPLAY === step.kind && !drive.replayed.includes(step.target));
526
- if (nextReplay !== undefined && !windingUp)
527
- return only(request(Tool.FLOW_REPLAY, { flowName: nextReplay.target }), `replay ${nextReplay.target} — ${nextReplay.why}`);
528
- if (drive.tree === undefined)
529
- return only(request(Tool.SNAPSHOT, { mode: 'interactive' }), 'look at the page');
530
- const slug = slugOf(drive.route);
531
- const outOfBudget = budget !== undefined && drive.turns >= budget - TEARDOWN_TURNS;
532
- // Out of budget, or told to wind up: close the open recording and stop opening new ones.
533
- if (outOfBudget || windingUp) {
534
- if (drive.open !== undefined)
535
- return only(request(Tool.RECORD, { action: 'stop', recordingName: drive.open.name }), 'wind up; stop recording so the journey can be saved');
536
- return only(request(Tool.FINISH, {
537
- summary: `Drove ${String(drive.acted.length)} actions and saved ${String(drive.saved.length)} flow(s): ${drive.saved.join(', ')}.`,
538
- }), 'done');
539
- }
540
- /**
541
- * A page reached for the FIRST time ends the journey before it and opens its own.
542
- *
543
- * "Any route change" was too aggressive and produced a loop with a receipt:
544
- * `harness-drive-home-2` through `-41`. This dashboard has destinations that render nothing
545
- * and bounce straight back, so the route oscillates, and segmenting on every change closed and
546
- * reopened a recording on each bounce — 40 junk flows and a spent budget.
547
- *
548
- * Bounding it by "has this page been recorded yet" gives exactly one flow per page, which was
549
- * the point, and makes oscillation free: returning to somewhere already recorded just keeps
550
- * driving under the open recording. Those actions land in the previous page's flow, which is
551
- * untidy and is a great deal better than the alternative.
552
- */
553
- const alreadyRecorded = (candidate) => [...drive.saved, ...drive.unsaved].some((n) => slugAfter(n) === candidate);
554
- if (drive.open !== undefined && drive.open.slug !== slug && !alreadyRecorded(slug))
555
- return only(request(Tool.RECORD, { action: 'stop', recordingName: drive.open.name }), `left ${drive.open.slug}; close that journey before starting the next`);
556
- if (drive.open === undefined)
557
- return only(request(Tool.RECORD, {
558
- action: 'start',
559
- recordingName: `${DEFAULT_RECORDING_NAME}-${slug}`,
560
- }), `start recording ${slug}`);
561
- // ── the one real decision ────────────────────────────────────────────────────────────────
562
- // What the drive is currently for: the first plan step that is not a replay. Replays are all
563
- // done by the time we reach here, so whatever is left is the intent nobody has proved.
564
- const objective = plan.find((step) => PLAN_REPLAY !== step.kind && !drive.proved.includes(step.target));
565
- const candidates = candidatesFrom(drive.tree);
566
- /**
567
- * A page with nothing to act on ends the DRIVE, not just the journey.
568
- *
569
- * Closing the journey here and returning was an infinite loop with a receipt: the scaffolding
570
- * above saves the stopped recording, sees no open one, and opens another for the same page —
571
- * which still has nothing on it. Measured against a real dashboard it produced
572
- * `harness-drive-settings-2` through `-49` and spent the entire 250-step budget on 28 actions.
573
- *
574
- * Winding up instead closes the open recording once, saves it, and finishes.
575
- */
576
- if (0 === candidates.length) {
577
- windingUp = true;
578
- return only(request(Tool.RECORD, { action: 'stop', recordingName: drive.open.name }), 'nothing interactive on this page; wind up');
579
- }
580
- const criteria = {
581
- [FINISH_OPTION]: 'Stop driving: every journey started here reached its end state, or nothing leads anywhere new.',
582
- [RELOOK_OPTION]: 'Look at the page again without acting, because this reading looks incomplete.',
583
- [OBSERVE_OPTION]: 'Read what the application DID since the last action — the requests it made and what it logged. Choose this when something was driven and it is not yet clear whether it worked.',
584
- [STATE_OPTION]: "Read the application's own state, which is the strongest evidence there is and the one thing a screen cannot fake.",
585
- };
586
- const previous = drive.pages.at(-2);
587
- if (previous !== undefined)
588
- criteria[BACK_OPTION] =
589
- `Go back to ${previous}: this page is a dead end, or a journey started there is not finished.`;
590
- for (const candidate of candidates) {
591
- const verb = actionFor(candidate.role);
592
- const already = drive.acted.includes(candidate.ref) ? ' (already driven once)' : '';
593
- criteria[candidate.ref] = `${verb} the ${candidate.desc}${already}`;
594
- }
595
- const response = await callJev({ apiKey: options.apiKey, model, baseUrl, path, doFetch }, buildState(input.system, input.history, drive, objective), {
596
- next_action: {
597
- type: 'choice',
598
- instructions: 'Which single action carries the current user journey forward toward its END state — a submitted form, a saved record, a confirmation? Finish the journey this page started before opening a new one; prefer something not already driven only once it is finished.',
599
- criteria,
600
- },
601
- journey_complete: {
602
- type: 'noul',
603
- instructions: 'Every journey started so far has been carried to its end state and checked there, and further driving would add nothing.',
604
- },
605
- });
606
- const usage = {
607
- input: response.usage?.input_tokens ?? 0,
608
- output: response.usage?.output_tokens ?? 0,
609
- cacheRead: 0,
610
- cacheWrite: 0,
611
- };
612
- const chosen = response.answers?.['next_action']?.choice ?? FINISH_OPTION;
613
- const complete = response.answers?.['journey_complete']?.noul ?? 0;
614
- if (FINISH_OPTION === chosen || COMPLETE_THRESHOLD < complete) {
615
- windingUp = true;
616
- return only(request(Tool.RECORD, { action: 'stop', recordingName: drive.open.name }), 'app covered; close the last journey and wind up', usage);
617
- }
618
- if (RELOOK_OPTION === chosen)
619
- return only(request(Tool.SNAPSHOT, { mode: 'interactive' }), 'look again', usage);
620
- if (BACK_OPTION === chosen && previous !== undefined)
621
- return only(request(Tool.NAVIGATE, { url: previous }), `back to ${previous}`, usage);
622
- // Routing to a READ rather than an action. Neither changes the app, so neither is recorded as
623
- // something driven — they are how the drive finds out whether what it drove worked.
624
- if (OBSERVE_OPTION === chosen)
625
- return only(request(Tool.OBSERVE, {}), 'read what the app did', usage);
626
- if (STATE_OPTION === chosen)
627
- return only(request(Tool.STATE, {}), 'read the app state', usage);
628
- const picked = candidates.find((candidate) => candidate.ref === chosen);
629
- if (picked === undefined)
630
- // Jev answers with one of the keys it was given, so this is unreachable by construction —
631
- // but a driver that trusted that and was wrong would emit a call naming an element that is
632
- // not on the page, which is precisely the failure this driver exists to make impossible.
633
- return only(request(Tool.SNAPSHOT, { mode: 'interactive' }), 'unrecognised choice; look again', usage);
634
- const action = actionFor(picked.role);
635
- // A SECOND call, deliberately. Jev answers every question in one pass and the answers are
636
- // independent, so "what should I expect from the element I am about to choose" cannot be
637
- // asked in the same breath as "which element". It costs another ~350ms and ~$0.00004, and it
638
- // costs nothing from the STEP budget, which is what is actually scarce here.
639
- const offered = consequencesFor(drive.route, options.vocabulary);
640
- const expectation = await callJev({ apiKey: options.apiKey, model, baseUrl, path, doFetch }, `${buildState(input.system, input.history, drive, objective)}\n\nABOUT TO: ${action} ${picked.desc}`, {
641
- expected_consequence: {
642
- type: 'choice',
643
- instructions: 'If this action works, what should the application itself be observed to do? Choose the consequence you are CONFIDENT of. A wrong guess is reported as a defect in the application, so when no listed consequence clearly follows from this control, choose `nothing` — claiming less is always better than claiming wrongly. Among consequences you are equally confident of, prefer the most SPECIFIC one: a named signal over a request, a request over anything vaguer, because only a specific claim survives into the saved test.',
644
- criteria: {
645
- ...Object.fromEntries(Object.entries(offered).map(([key, v]) => [key, v.describes])),
646
- [NO_CONSEQUENCE]: 'Nothing predictable happens, or you are not confident which of the above would. Nothing is claimed and nothing is proved.',
647
- },
648
- },
649
- });
650
- const expected = expectation.answers?.['expected_consequence']?.choice ?? NO_CONSEQUENCE;
651
- const consequence = offered[expected];
652
- // Granted only to a ref the gate has already refused — see `DriveState.blocked`.
653
- const wasRefused = drive.blocked.includes(picked.ref);
654
- const args = {
655
- ref: picked.ref,
656
- action,
657
- ...(wasRefused ? { args: { [DANGEROUS_ARG]: true } } : {}),
658
- // No `intent`: "click button \"Save\"" describes a step, not a rule, and the ledger refuses it.
659
- // The recorded step keeps the element's role and name, which is what reads back as a journey.
660
- ...(consequence === undefined ? {} : { until: consequence.predicate }),
661
- };
662
- if ('fill' === action) {
663
- const label = nameOf(picked.desc);
664
- args['args'] = {
665
- ...asRecord(args['args']),
666
- value: await (options.fillValue?.(label) ?? Promise.resolve(heuristicFillValue(label))),
667
- };
668
- }
669
- const spent = {
670
- input: usage.input + (expectation.usage?.input_tokens ?? 0),
671
- output: usage.output + (expectation.usage?.output_tokens ?? 0),
672
- cacheRead: 0,
673
- cacheWrite: 0,
674
- };
675
- return only(request(Tool.ACT_AND_WAIT, args), `${action} ${picked.desc}, expecting ${expected}`, spent);
676
- },
677
- };
678
- }