@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
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Search before grading: a goal the drive did not end on is hunted for, the way a person would,
3
+ * before anything is said about it.
4
+ *
5
+ * Every Harness miss in the persona drives had one shape: it graded where it stood. It judged an
6
+ * Impact text on /runs, stopped one click short of "Team", read an empty search result as the
7
+ * answer, called an opened menu a wrong guess, and walked past a goal it had reached. This hunt is
8
+ * deterministic (no model) and bounded: from the page the drive ended on it tries the toggles and
9
+ * tabs, then the controls the journey names (a menu that opens is followed into its items), then the
10
+ * same page without its query, then the pages the map says show the goal, then the pages the drive
11
+ * reached. It never fills a field
12
+ * and never presses a name on the never-pressed list. Each place it looks is kept, so "not found"
13
+ * says where it searched, and a goal it did not find is undecided, never a failure.
14
+ */
15
+ import { ReticleTool } from '@reticlehq/core';
16
+ import { lookFor } from '../goals.js';
17
+ import { journeyNames, namedControls, navLinks, overlayOpen, parseTree, readPage, toggles, withoutQuery, } from './page-tree.js';
18
+ /** Presses the hunt may spend: enough for a menu, its item and a tab, or a few toggles. */
19
+ export const SEARCH_MOVES = 10;
20
+ /** Shortest heading matched against the journey; shorter ones match by accident. */
21
+ const MIN_HEADING = 4;
22
+ /** How deep a chain of presses goes from one page: menu, item, tab. */
23
+ const MAX_DEPTH = 3;
24
+ const label = (line) => `${line.role} "${line.name}"`;
25
+ /** Hunt for `goal`, leaving the tab where it was found. */
26
+ export async function searchForGoal(invoke, options) {
27
+ const { goal } = options;
28
+ const journey = options.journey ?? '';
29
+ const searched = [];
30
+ const looked = new Set();
31
+ const pressed = new Set();
32
+ let left = options.moves ?? SEARCH_MOVES;
33
+ let at;
34
+ let reopened = false;
35
+ /** Look here, then press what a person would press here, deeper while presses are left. */
36
+ const explore = async (depth) => {
37
+ const page = await readPage(invoke);
38
+ if (page === undefined)
39
+ return false;
40
+ searched.push(page.route);
41
+ looked.add(page.route);
42
+ if (await lookFor(invoke, goal, options.own)) {
43
+ at = page.route;
44
+ return true;
45
+ }
46
+ if (MAX_DEPTH <= depth)
47
+ return false;
48
+ // Read again, settled by the look: a page read as it loaded offered none of its controls.
49
+ const lines = parseTree((await readPage(invoke))?.tree ?? page.tree);
50
+ // A menu or dialog the drive left open hides the page behind it: the live drive's hunt read the
51
+ // workspace switcher and nothing else. Close it by reloading the page, once, and look again.
52
+ if (0 === depth && !reopened && overlayOpen(lines)) {
53
+ reopened = true;
54
+ return (await go(page.route)) && explore(0);
55
+ }
56
+ // What the journey names on this page first ("press Run plan"), then the toggles, then the
57
+ // named links that leave it: a switcher pressed as a toggle opened its menu over the plan page,
58
+ // and the button the journey named was never pressed.
59
+ const named = namedControls(lines, journey);
60
+ const leaving = new Set(navLinks(lines));
61
+ const tries = [
62
+ ...new Set([
63
+ ...named.filter((l) => !leaving.has(l)),
64
+ ...toggles(lines),
65
+ ...named.filter((l) => leaving.has(l)),
66
+ ].map(label)),
67
+ ];
68
+ const overlaid = overlayOpen(lines);
69
+ for (const name of tries) {
70
+ const key = `${page.route}: ${name}`;
71
+ if (pressed.has(key))
72
+ continue;
73
+ if (left <= 0)
74
+ return false;
75
+ // Found again on a fresh read: a ref does not survive the page coming back.
76
+ const now = await readPage(invoke);
77
+ const line = parseTree(now?.tree ?? '').find((l) => l.ref !== undefined && label(l) === name);
78
+ if (line?.ref === undefined)
79
+ continue;
80
+ pressed.add(key);
81
+ left -= 1;
82
+ searched.push(key);
83
+ try {
84
+ await invoke(ReticleTool.ACT, { ref: line.ref, action: 'click' });
85
+ }
86
+ catch {
87
+ continue;
88
+ }
89
+ if (await explore(depth + 1))
90
+ return true;
91
+ // Back where it pressed from, with nothing it opened left over the page to hide the rest.
92
+ const back = await readPage(invoke);
93
+ const leftOpen = !overlaid && overlayOpen(parseTree(back?.tree ?? ''));
94
+ if (back !== undefined && (back.route !== page.route || leftOpen))
95
+ await go(page.route);
96
+ }
97
+ return false;
98
+ };
99
+ const go = async (route) => {
100
+ try {
101
+ await invoke(ReticleTool.NAVIGATE, { url: route });
102
+ return true;
103
+ }
104
+ catch {
105
+ return false;
106
+ }
107
+ };
108
+ const start = await readPage(invoke);
109
+ if (await explore(0))
110
+ return { found: true, ...(at === undefined ? {} : { at }), searched };
111
+ // A search or a filter that emptied the list, undone.
112
+ const elsewhere = [
113
+ ...(start === undefined || withoutQuery(start.route) === start.route
114
+ ? []
115
+ : [withoutQuery(start.route)]),
116
+ ...mappedPagesFor(options.map, goal, journey),
117
+ // Newest first: the drive's last page before it moved on is where a saved thing shows.
118
+ ...[...(options.reached ?? [])].reverse(),
119
+ ];
120
+ for (const route of elsewhere) {
121
+ if (looked.has(route) || left <= 0)
122
+ continue;
123
+ if (!(await go(route)))
124
+ continue;
125
+ if (await explore(1))
126
+ return { found: true, ...(at === undefined ? {} : { at }), searched };
127
+ }
128
+ const gaveUpAt = searched.at(-1);
129
+ return { found: false, searched, ...(gaveUpAt === undefined ? {} : { gaveUpAt }) };
130
+ }
131
+ /** The mapped pages that show the goal, then the ones the journey names by heading. */
132
+ export function mappedPagesFor(map, goal, journey) {
133
+ if (map === undefined)
134
+ return [];
135
+ const wanted = goal.toLowerCase();
136
+ const said = journey.toLowerCase();
137
+ const showing = map.pages.filter((p) => p.texts.some((t) => t.toLowerCase().includes(wanted)));
138
+ // A page whose controls name what the journey asks for: Memory is a link on Flows.
139
+ const leading = map.pages.filter((p) => p.controls.some((c) => journeyNames(said, /"([^"]*)"/.exec(c)?.[1] ?? '')));
140
+ const named = map.pages.filter((p) => p.heading !== undefined &&
141
+ MIN_HEADING <= p.heading.length &&
142
+ said.includes(p.heading.toLowerCase()));
143
+ return [...new Set([...showing, ...leading, ...named].map((p) => p.route))];
144
+ }
@@ -0,0 +1,49 @@
1
+ export type Invoke = (name: string, args: Record<string, unknown>) => Promise<unknown>;
2
+ /** One element line: ` - button "Team" (ref=e252) [pressed]`. */
3
+ export interface TreeLine {
4
+ depth: number;
5
+ role: string;
6
+ name: string;
7
+ ref?: string;
8
+ states: string[];
9
+ /** The element's own text, `[text="…"]`, when it has no name to carry it. */
10
+ text?: string;
11
+ /** The roles of the lines it sits inside, nearest last. */
12
+ within: string[];
13
+ }
14
+ export interface PageRead {
15
+ route: string;
16
+ tree: string;
17
+ }
18
+ export declare function parseTree(tree: string): TreeLine[];
19
+ /** The page's own address: path, query and hash, without the parameters Reticle adds. */
20
+ export declare function routeOf(route: string): string;
21
+ /** The same page with no query: a search or a filter undone. */
22
+ export declare function withoutQuery(route: string): string;
23
+ /** Read the page in full. Undefined when it cannot be read. */
24
+ export declare function readPage(invoke: Invoke): Promise<PageRead | undefined>;
25
+ /** Whether a menu or dialog is open, so the read shows it and little else. */
26
+ export declare function overlayOpen(lines: readonly TreeLine[]): boolean;
27
+ /** Links in the app's navigation: where a person goes to look around. */
28
+ export declare function navLinks(lines: readonly TreeLine[]): (TreeLine & {
29
+ ref: string;
30
+ })[];
31
+ /**
32
+ * Toggles and tabs not already on: a button beside a pressed sibling (Mine | Team), and tabs, radios
33
+ * and switches. Pressing one changes what the page shows without leaving it.
34
+ */
35
+ export declare function toggles(lines: readonly TreeLine[]): (TreeLine & {
36
+ ref: string;
37
+ })[];
38
+ /**
39
+ * Controls the journey names ("open Account, choose Settings, then Members and access"): the plan
40
+ * is a hint, and these are where it points. A name like `Account: Leo Martin · Pro` matches on the
41
+ * part before its colon.
42
+ */
43
+ export declare function namedControls(lines: readonly TreeLine[], journey: string): (TreeLine & {
44
+ ref: string;
45
+ })[];
46
+ /** Whether the journey names a control: its name, or the part before its colon, as whole words. */
47
+ export declare function journeyNames(journey: string, name: string): boolean;
48
+ /** The words a page shows, as a reader would list them: headings, text and labels, not controls. */
49
+ export declare function textsOf(lines: readonly TreeLine[], max: number): string[];
@@ -0,0 +1,148 @@
1
+ /**
2
+ * A page as the exploratory Harness reads it: one full snapshot, and the controls on it that a
3
+ * person hunting for something would try — nav links, toggles and tabs, and whatever the journey
4
+ * names. Pure over the snapshot's line format (core's `snapshot-tree.ts`); no browser here.
5
+ */
6
+ import { RETICLE_URL_PARAM, ReticleTool, asRecord } from '@reticlehq/core';
7
+ const LINE = /^(\s*)-\s+([a-z]+)(?:\s+"((?:[^"\\]|\\.)*)")?(.*)$/;
8
+ const REF = /\(ref=(e\d+)\)/;
9
+ const STATES = /\[([a-z,]+)\]\s*$/;
10
+ const OWN_TEXT = /\[text="((?:[^"\\]|\\.)*)"\]/;
11
+ export function parseTree(tree) {
12
+ const out = [];
13
+ const stack = [];
14
+ for (const raw of tree.split('\n')) {
15
+ const m = LINE.exec(raw);
16
+ if (null === m)
17
+ continue;
18
+ const depth = (m[1] ?? '').length;
19
+ while (0 < stack.length && (stack.at(-1)?.depth ?? 0) >= depth)
20
+ stack.pop();
21
+ const rest = m[4] ?? '';
22
+ const ref = REF.exec(rest)?.[1];
23
+ const text = OWN_TEXT.exec(rest)?.[1];
24
+ out.push({
25
+ depth,
26
+ role: m[2] ?? '',
27
+ name: m[3] ?? '',
28
+ ...(ref === undefined ? {} : { ref }),
29
+ ...(text === undefined ? {} : { text }),
30
+ states: (STATES.exec(rest)?.[1] ?? '').split(',').filter((s) => 0 < s.length),
31
+ within: stack.map((s) => s.role),
32
+ });
33
+ stack.push({ depth, role: m[2] ?? '' });
34
+ }
35
+ return out;
36
+ }
37
+ /** The page's own address: path, query and hash, without the parameters Reticle adds. */
38
+ export function routeOf(route) {
39
+ const [pathAndQuery = '', ...hash] = route.split('#');
40
+ const [path = '', query] = pathAndQuery.split('?');
41
+ const ours = Object.values(RETICLE_URL_PARAM);
42
+ const kept = (query ?? '')
43
+ .split('&')
44
+ .filter((pair) => 0 < pair.length && !ours.some((p) => pair.startsWith(`${p}=`)))
45
+ .join('&');
46
+ return `${path || '/'}${0 === kept.length ? '' : `?${kept}`}${0 === hash.length ? '' : `#${hash.join('#')}`}`;
47
+ }
48
+ /** The same page with no query: a search or a filter undone. */
49
+ export function withoutQuery(route) {
50
+ const [pathAndQuery = '', ...hash] = route.split('#');
51
+ const path = pathAndQuery.split('?')[0] ?? '';
52
+ return `${0 === path.length ? '/' : path}${0 === hash.length ? '' : `#${hash.join('#')}`}`;
53
+ }
54
+ /** Read the page in full. Undefined when it cannot be read. */
55
+ export async function readPage(invoke) {
56
+ try {
57
+ const result = asRecord(await invoke(ReticleTool.SNAPSHOT, { mode: 'full' }));
58
+ const tree = result['tree'];
59
+ const route = asRecord(result['status'])['route'];
60
+ return 'string' === typeof tree
61
+ ? { tree, route: routeOf('string' === typeof route ? route : '/') }
62
+ : undefined;
63
+ }
64
+ catch {
65
+ return undefined;
66
+ }
67
+ }
68
+ /**
69
+ * Names the hunt never presses: each is a write, or leaves the session. The action tool's own
70
+ * destructive-action gate still applies; this keeps the search from even asking.
71
+ */
72
+ const NEVER_PRESSED = /\b(?:sign ?out|log ?out|delete|remove|leave|revoke|join|cancel|archive|reset|disconnect|accept|decline|mark as|resolve|ignore|invite|pay|buy|upgrade|save|submit|send|create|new)\b/i;
73
+ const pressable = (line) => line.ref !== undefined && 0 < line.name.length && !NEVER_PRESSED.test(line.name);
74
+ const NAV_LANDMARKS = new Set(['navigation', 'complementary', 'banner']);
75
+ const TOGGLE_ROLES = new Set(['tab', 'radio', 'switch']);
76
+ const TOGGLE_GROUPS = new Set(['group', 'toolbar', 'radiogroup', 'tablist']);
77
+ /** Roles that, open, make the rest of the page inert to a reader. */
78
+ const OVERLAYS = new Set(['menu', 'dialog', 'alertdialog', 'listbox']);
79
+ /** Whether a menu or dialog is open, so the read shows it and little else. */
80
+ export function overlayOpen(lines) {
81
+ return lines.some((l) => OVERLAYS.has(l.role));
82
+ }
83
+ const PRESSED = 'pressed';
84
+ const CHECKED = 'checked';
85
+ /** Links in the app's navigation: where a person goes to look around. */
86
+ export function navLinks(lines) {
87
+ return lines.filter((l) => 'link' === l.role && l.within.some((r) => NAV_LANDMARKS.has(r)) && pressable(l));
88
+ }
89
+ /**
90
+ * Toggles and tabs not already on: a button beside a pressed sibling (Mine | Team), and tabs, radios
91
+ * and switches. Pressing one changes what the page shows without leaving it.
92
+ */
93
+ export function toggles(lines) {
94
+ return lines.filter((l, i) => {
95
+ if (!pressable(l) || l.states.includes(PRESSED) || l.states.includes(CHECKED))
96
+ return false;
97
+ if (TOGGLE_ROLES.has(l.role))
98
+ return true;
99
+ // Only inside a group of its kind (Mine | Team, Map | List). A banner's "Hide sidebar" is
100
+ // pressed too, and the workspace switcher beside it was pressed as a toggle on a live drive.
101
+ if ('button' !== l.role || !TOGGLE_GROUPS.has(l.within.at(-1) ?? ''))
102
+ return false;
103
+ const siblings = [lines[i - 1], lines[i + 1]].filter((s) => s !== undefined && s.depth === l.depth && 'button' === s.role);
104
+ return siblings.some((s) => s.states.includes(PRESSED));
105
+ });
106
+ }
107
+ /** Shortest name matched against the journey's words; shorter ones match by accident. */
108
+ const MIN_NAMED = 4;
109
+ const ROLES_FOLLOWED = new Set(['link', 'button', 'menuitem', 'tab']);
110
+ /**
111
+ * Controls the journey names ("open Account, choose Settings, then Members and access"): the plan
112
+ * is a hint, and these are where it points. A name like `Account: Leo Martin · Pro` matches on the
113
+ * part before its colon.
114
+ */
115
+ export function namedControls(lines, journey) {
116
+ const said = journey.toLowerCase();
117
+ return lines.filter((l) => ROLES_FOLLOWED.has(l.role) && pressable(l) && journeyNames(said, l.name));
118
+ }
119
+ /** Whether the journey names a control: its name, or the part before its colon, as whole words. */
120
+ export function journeyNames(journey, name) {
121
+ const head = (name.split(':')[0] ?? '').trim().toLowerCase();
122
+ return (MIN_NAMED <= head.length && new RegExp(`\\b${escape(head)}\\b`).test(journey.toLowerCase()));
123
+ }
124
+ const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
125
+ /** Roles a person acts on rather than reads. */
126
+ const INTERACTIVE = new Set([
127
+ 'link',
128
+ 'button',
129
+ 'textbox',
130
+ 'searchbox',
131
+ 'checkbox',
132
+ 'radio',
133
+ 'switch',
134
+ 'combobox',
135
+ 'option',
136
+ 'menuitem',
137
+ 'tab',
138
+ 'slider',
139
+ 'spinbutton',
140
+ ]);
141
+ /** The words a page shows, as a reader would list them: headings, text and labels, not controls. */
142
+ export function textsOf(lines, max) {
143
+ const words = lines.flatMap((l) => [
144
+ ...(INTERACTIVE.has(l.role) || 0 === l.name.length ? [] : [l.name]),
145
+ ...(l.text === undefined ? [] : [l.text]),
146
+ ]);
147
+ return [...new Set(words)].slice(0, max);
148
+ }
@@ -0,0 +1,34 @@
1
+ import { type HarnessMap, type HarnessMapPage } from '@reticlehq/core/artifacts';
2
+ import type { ToolOutcome } from '../harness.js';
3
+ import { type Invoke, type PageRead } from './page-tree.js';
4
+ /** Presses the survey may spend: a dashboard's navigation and its toggles, not its rows. */
5
+ export declare const SURVEY_PRESSES = 12;
6
+ /** A map older than this is surveyed again; a younger one is reused and refreshed from drives. */
7
+ export declare const MAP_FRESH_MS: number;
8
+ /**
9
+ * Whether the app was surveyed for the run that started at `since` (or there is no map at all): a
10
+ * run that reused a fresh map does not sweep the whole app again.
11
+ */
12
+ export declare function surveyedSince(map: HarnessMap | undefined, since: number): boolean;
13
+ /** One page read, as the map keeps it. */
14
+ export declare function pageFrom(read: PageRead, at: number, reachedBy?: string): HarnessMapPage;
15
+ /** Pages merged by route, the newest read winning, newest first, within the map's bound. */
16
+ export declare function mergePages(map: HarnessMap, pages: readonly HarnessMapPage[], surveyedAt?: number): HarnessMap;
17
+ /** The pages a drive read in full, for refreshing the map from what it saw. */
18
+ export declare function pagesReadIn(calls: readonly ToolOutcome[], at: number): HarnessMapPage[];
19
+ /**
20
+ * Survey the app from where the tab stands, and leave the tab where it started. Every press is
21
+ * found again by its name on a fresh read of the start page, since a ref does not survive a reload.
22
+ */
23
+ export declare function surveyApp(invoke: Invoke, now: () => number, presses?: number): Promise<HarnessMap | undefined>;
24
+ /** The map from its file's text, or undefined when there is none or it does not parse. */
25
+ export declare function parseMap(text: string | undefined): HarnessMap | undefined;
26
+ /** The map as the platform takes it: pages only, the fields its engine reads. */
27
+ export declare function mapForPlatform(map: HarnessMap): {
28
+ pages: {
29
+ route: string;
30
+ heading?: string;
31
+ texts: string[];
32
+ controls: string[];
33
+ }[];
34
+ };
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Map first: before the Harness pursues a goal, it surveys the app, cheaply and with no model.
3
+ *
4
+ * Persona drives missed goals that sat one page away: the drive committed to a route, a prediction
5
+ * missed, and it graded where it stood. A person new to an app looks around first. The survey reads
6
+ * the start page, presses each nav link and each toggle once (never a field, never a name on the
7
+ * never-pressed list), reads where that leads, and goes back. The map is kept per app and refreshed
8
+ * by every drive's own reads, so the survey runs again only when the map is old.
9
+ */
10
+ import { PredicateKind, ReticleTool, SnapshotMode, asRecord } from '@reticlehq/core';
11
+ import { HarnessMapLimit, HarnessMapSchema, } from '@reticlehq/core/artifacts';
12
+ import { navLinks, overlayOpen, parseTree, readPage, routeOf, textsOf, toggles, } from './page-tree.js';
13
+ /** Presses the survey may spend: a dashboard's navigation and its toggles, not its rows. */
14
+ export const SURVEY_PRESSES = 12;
15
+ /** A map older than this is surveyed again; a younger one is reused and refreshed from drives. */
16
+ export const MAP_FRESH_MS = 24 * 60 * 60 * 1000;
17
+ /** How long a page gets to settle after a press before it is read. */
18
+ const SETTLE_MS = 3000;
19
+ /**
20
+ * Whether the app was surveyed for the run that started at `since` (or there is no map at all): a
21
+ * run that reused a fresh map does not sweep the whole app again.
22
+ */
23
+ export function surveyedSince(map, since) {
24
+ return map === undefined || since <= map.surveyedAt;
25
+ }
26
+ /** One page read, as the map keeps it. */
27
+ export function pageFrom(read, at, reachedBy) {
28
+ const lines = parseTree(read.tree);
29
+ const heading = lines.find((l) => 'heading' === l.role && 0 < l.name.length)?.name;
30
+ const clip = (t) => t.slice(0, HarnessMapLimit.TEXT);
31
+ return {
32
+ route: clip(read.route),
33
+ ...(heading === undefined ? {} : { heading: clip(heading) }),
34
+ texts: textsOf(lines, HarnessMapLimit.TEXTS).map(clip),
35
+ controls: lines
36
+ .filter((l) => l.ref !== undefined && 0 < l.name.length)
37
+ .slice(0, HarnessMapLimit.CONTROLS)
38
+ .map((l) => clip(`${l.role} "${l.name}"`)),
39
+ ...(reachedBy === undefined ? {} : { reachedBy: clip(reachedBy) }),
40
+ at,
41
+ };
42
+ }
43
+ /** Pages merged by route, the newest read winning, newest first, within the map's bound. */
44
+ export function mergePages(map, pages, surveyedAt = map.surveyedAt) {
45
+ const byRoute = new Map(map.pages.map((p) => [p.route, p]));
46
+ for (const page of pages) {
47
+ const was = byRoute.get(page.route);
48
+ if (was === undefined || was.at <= page.at) {
49
+ const reachedBy = page.reachedBy ?? was?.reachedBy;
50
+ byRoute.set(page.route, { ...page, ...(reachedBy === undefined ? {} : { reachedBy }) });
51
+ }
52
+ }
53
+ const pagesOut = [...byRoute.values()]
54
+ .sort((a, b) => b.at - a.at)
55
+ .slice(0, HarnessMapLimit.PAGES);
56
+ return { surveyedAt, pages: pagesOut };
57
+ }
58
+ /** The pages a drive read in full, for refreshing the map from what it saw. */
59
+ export function pagesReadIn(calls, at) {
60
+ return calls.flatMap((call) => {
61
+ // Only a full read of an unobstructed page: a quick read has no text, and a page behind an open
62
+ // menu reads as the menu. Either one once replaced the survey's page and emptied the map.
63
+ if (ReticleTool.SNAPSHOT !== call.name || call.isError)
64
+ return [];
65
+ if (SnapshotMode.FULL !== asRecord(call.args)['mode'])
66
+ return [];
67
+ const result = asRecord(call.result);
68
+ const tree = result['tree'];
69
+ const route = asRecord(result['status'])['route'];
70
+ if ('string' !== typeof tree || 'string' !== typeof route)
71
+ return [];
72
+ if (overlayOpen(parseTree(tree)))
73
+ return [];
74
+ return [pageFrom({ tree, route: routeOf(route) }, at)];
75
+ });
76
+ }
77
+ const label = (line) => `${line.role} "${line.name}"`;
78
+ async function settle(invoke) {
79
+ try {
80
+ await invoke(ReticleTool.WAIT_FOR, {
81
+ predicate: { kind: PredicateKind.SETTLED },
82
+ timeout_ms: SETTLE_MS,
83
+ });
84
+ }
85
+ catch {
86
+ /* a page that never settles is read as it stands */
87
+ }
88
+ }
89
+ /**
90
+ * Survey the app from where the tab stands, and leave the tab where it started. Every press is
91
+ * found again by its name on a fresh read of the start page, since a ref does not survive a reload.
92
+ */
93
+ export async function surveyApp(invoke, now, presses = SURVEY_PRESSES) {
94
+ let start = await readPage(invoke);
95
+ if (start === undefined)
96
+ return undefined;
97
+ // A menu left open hides the page behind it: reload it once before reading what it offers.
98
+ if (overlayOpen(parseTree(start.tree))) {
99
+ await invoke(ReticleTool.NAVIGATE, { url: start.route }).catch(() => undefined);
100
+ start = (await readPage(invoke)) ?? start;
101
+ }
102
+ const pages = [pageFrom(start, now())];
103
+ const startLines = parseTree(start.tree);
104
+ const targets = [...navLinks(startLines), ...toggles(startLines)]
105
+ .map(label)
106
+ .filter((name, i, all) => all.indexOf(name) === i)
107
+ .slice(0, presses);
108
+ for (const target of targets) {
109
+ try {
110
+ const here = await readPage(invoke);
111
+ const line = parseTree(here?.tree ?? '').find((l) => l.ref !== undefined && label(l) === target);
112
+ if (line?.ref === undefined)
113
+ continue;
114
+ await invoke(ReticleTool.ACT, { ref: line.ref, action: 'click' });
115
+ await settle(invoke);
116
+ const read = await readPage(invoke);
117
+ if (read !== undefined)
118
+ pages.push(pageFrom(read, now(), target));
119
+ if (read !== undefined && read.route !== start.route)
120
+ await invoke(ReticleTool.NAVIGATE, { url: start.route });
121
+ }
122
+ catch {
123
+ /* a press that fails is a page the map does not have */
124
+ }
125
+ }
126
+ return mergePages({ surveyedAt: now(), pages: [] }, pages, now());
127
+ }
128
+ /** The map from its file's text, or undefined when there is none or it does not parse. */
129
+ export function parseMap(text) {
130
+ if (text === undefined)
131
+ return undefined;
132
+ try {
133
+ const parsed = HarnessMapSchema.safeParse(JSON.parse(text));
134
+ return parsed.success ? parsed.data : undefined;
135
+ }
136
+ catch {
137
+ return undefined;
138
+ }
139
+ }
140
+ /** The map as the platform takes it: pages only, the fields its engine reads. */
141
+ export function mapForPlatform(map) {
142
+ return {
143
+ pages: map.pages.map((p) => ({
144
+ route: p.route,
145
+ ...(p.heading === undefined ? {} : { heading: p.heading }),
146
+ texts: p.texts,
147
+ controls: p.controls,
148
+ })),
149
+ };
150
+ }
@@ -1,21 +1,82 @@
1
+ /** One goal: text the page must show, or — when the persona negated it — must not. */
2
+ export interface Goal {
3
+ text: string;
4
+ /** The persona said the page must NOT show it: an absence goal, graded by asserting it is not there. */
5
+ absent?: true;
6
+ }
1
7
  export interface GoalCheck {
2
- /** The text that had to be on the page. */
8
+ /** The text that had to be on the page (or, for an absence goal, not on it). */
3
9
  text: string;
10
+ /** Set for an absence goal. */
11
+ absent?: true;
4
12
  /** The engine's verdict on it: only `yes` is proved. */
5
13
  verified: string;
14
+ /** Why it was not checked, when it was not. */
15
+ reason?: string;
6
16
  }
7
- /** The observable goals in a persona: whatever it quoted. */
17
+ /**
18
+ * Whether `shown` — one element's text, maybe cut short with "…" — is text the Harness wrote itself
19
+ * rather than the app: one of `own` (its journey, the names of the plan and the flows it saved), in
20
+ * full or cut short, holding `goal`. A Harness asked to rename a plan stopped on the /plans list and
21
+ * was graded PROVED on every quote: the plan it had just saved was named after the journey, and the
22
+ * journey quoted them all. An element showing exactly the goal is the app's, whoever else wrote it.
23
+ */
24
+ export declare function writtenByHarness(shown: string, goal: string, own: readonly string[]): boolean;
25
+ /** The end state a goal quotes: its last quoted text that it does not negate. */
26
+ export declare function endOf(goal: string): string | undefined;
27
+ /** The observable goals in a persona: whatever it quoted, each marked absent when it was negated. */
28
+ export declare function parseGoals(persona: string | undefined): Goal[];
29
+ /** The texts a persona says must be on the page: the quoted goals it did not negate. */
8
30
  export declare function goalsIn(persona: string | undefined): string[];
9
31
  /**
10
32
  * Check each goal on the page the drive ended on, recording ONE assert for the drive.
11
33
  *
12
34
  * Each quote used to be its own assert, and every assert is a check in the drive's run, so a goal
13
35
  * that quotes where it starts ("from "Count is 0" to "Count is 1"") recorded a "no" for the start
14
- * text a working app had rightly replaced, and the run synced as a failing flow. The page is read
15
- * once to answer each quote; the one recorded assert covers the quotes shown, or all of them when
16
- * none is, so a goal the page never reached still leaves a failed check behind. A check that cannot
17
- * run is `unknown`, never skipped.
36
+ * text a working app had rightly replaced, and the run synced as a failing flow. The page is let
37
+ * settle, read once, and each goal is scrolled to by its text — one below the fold read `unknown`
38
+ * on a drive that never scrolled. The one recorded assert covers the goals found. A goal not found
39
+ * is undecided, not failed: nothing here knows the drive reached the page that would show it. A
40
+ * check that cannot run is `unknown`, never skipped.
18
41
  */
19
- export declare function checkGoals(invoke: (name: string, args: Record<string, unknown>) => Promise<unknown>, goals: readonly string[]): Promise<GoalCheck[]>;
42
+ export declare function checkGoals(invoke: (name: string, args: Record<string, unknown>) => Promise<unknown>, goals: readonly (string | Goal)[],
43
+ /** The page as it read before the drive: a goal it already showed proves nothing at the end. */
44
+ opening?: string,
45
+ /** Text the Harness wrote itself (its journey, its plan's and flows' names): never evidence. */
46
+ own?: readonly string[]): Promise<GoalCheck[]>;
47
+ /**
48
+ * Whether the page shows `text` once it has settled, scrolled to if need be — how a person looks
49
+ * for something before saying it is not there. Records no check.
50
+ */
51
+ export declare function lookFor(invoke: (name: string, args: Record<string, unknown>) => Promise<unknown>, text: string,
52
+ /** Text the Harness wrote itself: a match inside it is not the page showing the goal. */
53
+ own?: readonly string[]): Promise<boolean>;
54
+ /** The page as it reads now, or undefined when it cannot be read. Taken before a drive starts. */
55
+ export declare function readOpening(invoke: (name: string, args: Record<string, unknown>) => Promise<unknown>): Promise<string | undefined>;
56
+ /**
57
+ * The end state the caller declared, checked like any assert.
58
+ *
59
+ * Quoted text only proves some words are on the last page, which is how a drive that never used the
60
+ * app could pass: from the field, "it only checks that I have certain titles on my page". An `expect`
61
+ * names an OUTCOME — a route reached, a request made, state changed — in the same predicate grammar
62
+ * as reticle_assert, and is graded the same way. A check that cannot run is `unknown`.
63
+ */
64
+ export declare function checkExpect(invoke: (name: string, args: Record<string, unknown>) => Promise<unknown>, predicate: Record<string, unknown>): Promise<GoalCheck>;
65
+ /** Whether the drive met the goals it was given: undefined when it was given none. */
66
+ export declare function goalsMet(checks: readonly GoalCheck[]): boolean | undefined;
67
+ /**
68
+ * Whether the drive met its goal, as the answer and the run report it. The driver's own `goalMet`
69
+ * is its word, never evidence: a run answered `goalMet: true` after zero actions on a tab that
70
+ * already showed the end state, and another with both its goals `unknown`. With goals, met exactly
71
+ * when every one was proved; with none, the driver's word stands, and only after an action ran.
72
+ * Undefined when nothing judged it.
73
+ */
74
+ export declare function goalOfDrive(claimed: boolean | undefined, checks: readonly GoalCheck[], acted: boolean): boolean | undefined;
20
75
  /** One line naming the goals the drive did not prove, or undefined when it proved them all. */
21
76
  export declare function unprovedGoals(checks: readonly GoalCheck[]): string | undefined;
77
+ /**
78
+ * The goals a drive is graded on: every quote, less a value the drive typed — an input, never
79
+ * evidence — except the journey's end (its last text to show), which stays even when typed: saving
80
+ * "Order 7" and then seeing it listed is the journey. Absence goals always stay.
81
+ */
82
+ export declare function endGoalsOf(goals: readonly Goal[], typed: readonly string[]): Goal[];