@reticlehq/server 3.2.0 → 3.4.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 (437) hide show
  1. package/LICENSE-ENTERPRISE +1 -1
  2. package/README.md +3 -3
  3. package/SKILL.md +23 -22
  4. package/dist/chromium-launch-options.d.ts +4 -3
  5. package/dist/chromium-launch-options.js +6 -2
  6. package/dist/command/cli/adhoc-suite.d.ts +41 -0
  7. package/dist/command/cli/adhoc-suite.js +159 -0
  8. package/dist/command/cli/adhoc-verdict.d.ts +58 -2
  9. package/dist/command/cli/adhoc-verdict.js +108 -13
  10. package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
  11. package/dist/command/cli/answers/gate-hook-message.js +6 -0
  12. package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
  13. package/dist/command/cli/auth/cloud-keystore.js +0 -3
  14. package/dist/command/cli/auth/cloud-session.d.ts +4 -0
  15. package/dist/command/cli/auth/cloud-session.js +2 -0
  16. package/dist/command/cli/cli-doctor.js +30 -8
  17. package/dist/command/cli/cli-flow-commands.d.ts +3 -6
  18. package/dist/command/cli/cli-flow-commands.js +67 -4
  19. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  20. package/dist/command/cli/cli-parse-grammar.js +7 -0
  21. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  22. package/dist/command/cli/cli-parse-verify.js +86 -13
  23. package/dist/command/cli/cli-parse.d.ts +14 -1
  24. package/dist/command/cli/cli-parse.js +54 -8
  25. package/dist/command/cli/cli-update-commands.js +8 -1
  26. package/dist/command/cli/cli-verify.d.ts +80 -0
  27. package/dist/command/cli/cli-verify.js +181 -26
  28. package/dist/command/cli/cloud-cli.js +5 -2
  29. package/dist/command/cli/cloud-kit.d.ts +0 -2
  30. package/dist/command/cli/cloud-kit.js +3 -5
  31. package/dist/command/cli/cloud-login.js +21 -3
  32. package/dist/command/cli/demo/demo-page.js +6 -3
  33. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
  34. package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
  35. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  36. package/dist/command/cli/launch/cli-launch.d.ts +9 -29
  37. package/dist/command/cli/launch/cli-launch.js +27 -49
  38. package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
  39. package/dist/command/cli/launch/sdk-version-match.js +206 -0
  40. package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
  41. package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
  42. package/dist/command/cli/ports/resolve/cli-port.js +169 -15
  43. package/dist/command/cli/report-command.d.ts +16 -0
  44. package/dist/command/cli/report-command.js +97 -0
  45. package/dist/command/cli/setup-mcp-cli.js +13 -13
  46. package/dist/command/cli/tutorial.d.ts +2 -2
  47. package/dist/command/cli/tutorial.js +21 -7
  48. package/dist/command/cli.js +67 -10
  49. package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
  50. package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
  51. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  52. package/dist/command/daemon/daemon-resolve.d.ts +9 -0
  53. package/dist/command/daemon/daemon-resolve.js +1 -1
  54. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  55. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
  56. package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
  57. package/dist/command/dev/stale-issue-guard.d.ts +3 -4
  58. package/dist/command/dev/stale-issue-guard.js +8 -8
  59. package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
  60. package/dist/command/setup/bringup/connect-lease.js +38 -0
  61. package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
  62. package/dist/command/setup/bringup/dev-server-files.js +131 -0
  63. package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
  64. package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
  65. package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
  66. package/dist/command/setup/bringup/ensure-daemon.js +135 -16
  67. package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
  68. package/dist/command/setup/bringup/static-page-server.js +151 -0
  69. package/dist/command/setup/desktop-shape.d.ts +4 -0
  70. package/dist/command/setup/desktop-shape.js +18 -2
  71. package/dist/command/setup/init/init-host.js +8 -0
  72. package/dist/command/setup/init/init-port.d.ts +15 -0
  73. package/dist/command/setup/init/init-port.js +44 -0
  74. package/dist/command/setup/init/init-runtime.d.ts +1 -1
  75. package/dist/command/setup/init/init-runtime.js +39 -2
  76. package/dist/command/setup/node-effects.d.ts +27 -14
  77. package/dist/command/setup/node-effects.js +80 -44
  78. package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
  79. package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
  80. package/dist/command/setup/probe/page-probe.d.ts +13 -2
  81. package/dist/command/setup/probe/page-probe.js +18 -3
  82. package/dist/command/setup/run-setup.d.ts +26 -1
  83. package/dist/command/setup/run-setup.js +96 -13
  84. package/dist/command/setup/session-pick.d.ts +13 -0
  85. package/dist/command/setup/session-pick.js +20 -0
  86. package/dist/command/setup/setup-command.d.ts +2 -14
  87. package/dist/command/setup/setup-command.js +105 -31
  88. package/dist/command/setup/setup-mcp.js +3 -3
  89. package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
  90. package/dist/command/setup/terminal/wait-progress.js +17 -0
  91. package/dist/features/crawl/crawl-empty.js +1 -1
  92. package/dist/features/crawl/crawl-tools.d.ts +6 -0
  93. package/dist/features/crawl/crawl-tools.js +57 -0
  94. package/dist/features/crawl/crawl.d.ts +2 -0
  95. package/dist/features/crawl/crawl.js +171 -156
  96. package/dist/features/exhaust/app-coverage.d.ts +33 -0
  97. package/dist/features/exhaust/app-coverage.js +31 -0
  98. package/dist/features/exhaust/code-coverage.d.ts +47 -0
  99. package/dist/features/exhaust/code-coverage.js +77 -0
  100. package/dist/features/exhaust/exhaust-run.d.ts +33 -0
  101. package/dist/features/exhaust/exhaust-run.js +82 -0
  102. package/dist/features/exhaust/explorer.d.ts +103 -0
  103. package/dist/features/exhaust/explorer.js +195 -0
  104. package/dist/features/exhaust/failure-branches.d.ts +33 -0
  105. package/dist/features/exhaust/failure-branches.js +92 -0
  106. package/dist/features/exhaust/ledger.d.ts +202 -0
  107. package/dist/features/exhaust/ledger.js +252 -0
  108. package/dist/features/exhaust/session-fold.d.ts +31 -0
  109. package/dist/features/exhaust/session-fold.js +79 -0
  110. package/dist/features/exhaust/session-port.d.ts +36 -0
  111. package/dist/features/exhaust/session-port.js +102 -0
  112. package/dist/features/harness/drive-report.d.ts +0 -9
  113. package/dist/features/harness/drive-report.js +18 -0
  114. package/dist/features/harness/driver.js +4 -7
  115. package/dist/features/harness/fill-values.d.ts +6 -0
  116. package/dist/features/harness/fill-values.js +3 -0
  117. package/dist/features/harness/jev-driver.js +36 -22
  118. package/dist/features/harness/openai-driver.js +4 -7
  119. package/dist/features/harness/platform-config.d.ts +10 -0
  120. package/dist/features/harness/platform-config.js +13 -6
  121. package/dist/index.d.ts +10 -1
  122. package/dist/index.js +78 -104
  123. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  124. package/dist/judgement/capsule/capsule-store.js +58 -6
  125. package/dist/judgement/capsule/capsule.js +5 -0
  126. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  127. package/dist/judgement/capsule/causal-summary.js +7 -0
  128. package/dist/judgement/domain/domain-model.js +40 -9
  129. package/dist/judgement/oracles/self-instrument.js +4 -2
  130. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  131. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  132. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  133. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  134. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  135. package/dist/judgement/runs/artifact/render-report.js +4 -1
  136. package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
  137. package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
  138. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  139. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  140. package/dist/judgement/runs/context-tools.js +21 -3
  141. package/dist/judgement/runs/drive-run.js +7 -2
  142. package/dist/judgement/runs/verification-sync.d.ts +3 -1
  143. package/dist/judgement/runs/verification-sync.js +1 -1
  144. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  145. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  146. package/dist/language/flows/change/affected.d.ts +9 -0
  147. package/dist/language/flows/change/affected.js +35 -0
  148. package/dist/language/flows/change/gate.d.ts +20 -0
  149. package/dist/language/flows/change/gate.js +12 -1
  150. package/dist/language/flows/flow-anchor.d.ts +12 -0
  151. package/dist/language/flows/flow-anchor.js +20 -0
  152. package/dist/language/flows/flow-author.d.ts +7 -0
  153. package/dist/language/flows/flow-author.js +19 -0
  154. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  155. package/dist/language/flows/flow-expect-grammar.js +92 -11
  156. package/dist/language/flows/flow-intent.js +1 -1
  157. package/dist/language/flows/flow-journey.d.ts +54 -0
  158. package/dist/language/flows/flow-journey.js +119 -0
  159. package/dist/language/flows/flow-learning.d.ts +3 -0
  160. package/dist/language/flows/flow-learning.js +39 -8
  161. package/dist/language/flows/flow-replay-run.d.ts +33 -12
  162. package/dist/language/flows/flow-replay-run.js +131 -52
  163. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  164. package/dist/language/flows/flow-replay.d.ts +27 -12
  165. package/dist/language/flows/flow-replay.js +127 -111
  166. package/dist/language/flows/flow-result.d.ts +2 -0
  167. package/dist/language/flows/flow-result.js +25 -0
  168. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  169. package/dist/language/flows/flow-step-runners.js +20 -4
  170. package/dist/language/flows/flow-success.d.ts +21 -6
  171. package/dist/language/flows/flow-success.js +50 -138
  172. package/dist/language/flows/flow-tools.js +17 -5
  173. package/dist/language/flows/flows.d.ts +18 -5
  174. package/dist/language/flows/flows.js +101 -16
  175. package/dist/language/flows/heal.d.ts +9 -1
  176. package/dist/language/flows/heal.js +24 -2
  177. package/dist/language/flows/learned-sources.d.ts +21 -0
  178. package/dist/language/flows/learned-sources.js +84 -0
  179. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  180. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  181. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  182. package/dist/language/flows/recording/replay-halt.js +3 -1
  183. package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
  184. package/dist/language/flows/recording/tape/recordings.js +55 -1
  185. package/dist/language/flows/replay.d.ts +19 -0
  186. package/dist/language/flows/replay.js +53 -13
  187. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  188. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  189. package/dist/language/flows/stores/flake-store.js +2 -3
  190. package/dist/language/flows/suite/coverage.d.ts +1 -1
  191. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  192. package/dist/language/flows/verify-change-tools.js +19 -2
  193. package/dist/launch-chromium.d.ts +80 -0
  194. package/dist/launch-chromium.js +218 -0
  195. package/dist/memory/cloud/cloud-config.d.ts +11 -2
  196. package/dist/memory/cloud/cloud-config.js +47 -7
  197. package/dist/memory/cloud/cloud-sync.d.ts +4 -3
  198. package/dist/memory/cloud/cloud-sync.js +7 -10
  199. package/dist/memory/cloud/harness-config.d.ts +2 -0
  200. package/dist/memory/cloud/harness-offer.js +5 -6
  201. package/dist/memory/cloud/harness-switch.js +5 -6
  202. package/dist/memory/cloud/sync-cycle.d.ts +78 -1
  203. package/dist/memory/cloud/sync-cycle.js +321 -53
  204. package/dist/memory/cloud/sync-daemon.d.ts +13 -0
  205. package/dist/memory/cloud/sync-daemon.js +45 -20
  206. package/dist/memory/cloud/sync-disk.js +27 -8
  207. package/dist/memory/impact/impact-store.js +6 -0
  208. package/dist/memory/intent/inline-intent.js +8 -3
  209. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  210. package/dist/memory/intent/intent-shard-store.js +252 -140
  211. package/dist/memory/intent/intent-shard.d.ts +0 -23
  212. package/dist/memory/intent/intent-shard.js +1 -11
  213. package/dist/memory/intent/intent-store.d.ts +13 -8
  214. package/dist/memory/intent/intent-store.js +46 -90
  215. package/dist/memory/intent/intent-tools.js +34 -23
  216. package/dist/memory/journal/ambient-store.js +2 -3
  217. package/dist/memory/journal/deviation-report.js +4 -1
  218. package/dist/memory/journal/deviation-service.js +10 -2
  219. package/dist/memory/journal/drive-flow.d.ts +19 -14
  220. package/dist/memory/journal/drive-flow.js +65 -48
  221. package/dist/memory/journal/envelope-store.js +2 -3
  222. package/dist/memory/journal/journal-recorder.d.ts +21 -0
  223. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  224. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  225. package/dist/memory/journal/on-disk/retention.d.ts +14 -10
  226. package/dist/memory/journal/on-disk/retention.js +13 -12
  227. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  228. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  229. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
  230. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
  231. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  232. package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
  233. package/dist/memory/journal/route-template.d.ts +22 -0
  234. package/dist/memory/journal/route-template.js +44 -0
  235. package/dist/memory/journal/session-end.d.ts +13 -2
  236. package/dist/memory/journal/session-end.js +88 -18
  237. package/dist/memory/journal/session-journal.d.ts +8 -1
  238. package/dist/memory/journal/session-journal.js +10 -0
  239. package/dist/memory/project/baselines.d.ts +1 -1
  240. package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
  241. package/dist/memory/project/dir/reticle-dir.js +1 -0
  242. package/dist/memory/project/fs/fs-port.js +44 -5
  243. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  244. package/dist/memory/project/fs/write-atomic.js +48 -0
  245. package/dist/memory/project/project-tools.js +3 -1
  246. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  247. package/dist/memory/recall/prior/connection-memory.js +8 -0
  248. package/dist/memory/recall/registered-projects.d.ts +2 -1
  249. package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
  250. package/dist/portal/bridge/auth-failure-reason.js +9 -4
  251. package/dist/portal/bridge/bridge.d.ts +8 -0
  252. package/dist/portal/bridge/bridge.js +43 -2
  253. package/dist/portal/input/js-coverage.d.ts +25 -0
  254. package/dist/portal/input/js-coverage.js +30 -0
  255. package/dist/portal/input/real-input.d.ts +11 -0
  256. package/dist/portal/input/real-input.js +31 -5
  257. package/dist/portal/pool/browser-pool.d.ts +10 -0
  258. package/dist/portal/pool/browser-pool.js +10 -0
  259. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  260. package/dist/portal/pool/playwright-launcher.js +21 -13
  261. package/dist/portal/pool/pool-contract.d.ts +2 -0
  262. package/dist/portal/pool/storage-seed.d.ts +2 -1
  263. package/dist/portal/pool/zero-install.d.ts +27 -0
  264. package/dist/portal/pool/zero-install.js +54 -0
  265. package/dist/portal/realm/web-realm.js +6 -0
  266. package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
  267. package/dist/portal/session/dev-server/dev-command.js +30 -12
  268. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  269. package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
  270. package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
  271. package/dist/portal/session/dev-server/route-status-probe.js +57 -0
  272. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  273. package/dist/portal/session/dev-server/served-document.js +57 -0
  274. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  275. package/dist/portal/session/facts/background-traffic.js +25 -0
  276. package/dist/portal/session/facts/observed-state.d.ts +11 -0
  277. package/dist/portal/session/facts/observed-state.js +34 -0
  278. package/dist/portal/session/live-control-tools.js +48 -3
  279. package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
  280. package/dist/portal/session/no-session-diagnosis.js +62 -5
  281. package/dist/portal/session/no-session-next-action.d.ts +13 -0
  282. package/dist/portal/session/no-session-next-action.js +48 -9
  283. package/dist/portal/session/no-session-watch.d.ts +18 -0
  284. package/dist/portal/session/no-session-watch.js +88 -2
  285. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  286. package/dist/portal/session/session-health.d.ts +61 -0
  287. package/dist/portal/session/session-health.js +43 -3
  288. package/dist/portal/session/session-info.d.ts +6 -0
  289. package/dist/portal/session/session-manager.d.ts +29 -6
  290. package/dist/portal/session/session-manager.js +42 -5
  291. package/dist/portal/session/session-reaper.d.ts +28 -0
  292. package/dist/portal/session/session-reaper.js +49 -1
  293. package/dist/portal/session/session-successor.d.ts +11 -0
  294. package/dist/portal/session/session-successor.js +14 -1
  295. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  296. package/dist/portal/session/session-verdict-facts.js +15 -0
  297. package/dist/portal/session/session.d.ts +10 -0
  298. package/dist/portal/session/session.js +34 -26
  299. package/dist/surface/http-server.d.ts +2 -1
  300. package/dist/surface/http-server.js +4 -2
  301. package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
  302. package/dist/surface/mcp/mcp-proxy.js +5 -5
  303. package/dist/surface/mcp/mcp.js +4 -2
  304. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
  305. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
  306. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  307. package/dist/surface/mcp/server-instructions.js +21 -8
  308. package/dist/surface/tools/act/after-match.d.ts +17 -0
  309. package/dist/surface/tools/act/after-match.js +30 -0
  310. package/dist/surface/tools/act/already-true.d.ts +40 -0
  311. package/dist/surface/tools/act/already-true.js +36 -0
  312. package/dist/surface/tools/act/durable.d.ts +69 -0
  313. package/dist/surface/tools/act/durable.js +139 -0
  314. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
  315. package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
  316. package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
  317. package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
  318. package/dist/surface/tools/act/proved-controls.d.ts +9 -0
  319. package/dist/surface/tools/act/proved-controls.js +11 -0
  320. package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
  321. package/dist/surface/tools/act/sequence-grade.js +32 -1
  322. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  323. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  324. package/dist/surface/tools/act-capsule.d.ts +7 -0
  325. package/dist/surface/tools/act-capsule.js +68 -8
  326. package/dist/surface/tools/act-sequence-tool.js +25 -8
  327. package/dist/surface/tools/act-tools.js +51 -74
  328. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  329. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  330. package/dist/surface/tools/assert/assert-grade.js +26 -3
  331. package/dist/surface/tools/assert/assert-verdict.js +32 -6
  332. package/dist/surface/tools/browser-tools.js +17 -4
  333. package/dist/surface/tools/coverage-tools.js +27 -1
  334. package/dist/surface/tools/dynamic-tools.js +6 -0
  335. package/dist/surface/tools/error-recovery.js +4 -4
  336. package/dist/surface/tools/feedback-invite.js +6 -4
  337. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  338. package/dist/surface/tools/feedback-tools.js +1 -1
  339. package/dist/surface/tools/harness-explore.d.ts +3 -2
  340. package/dist/surface/tools/harness-explore.js +7 -6
  341. package/dist/surface/tools/invoke-tool.js +17 -4
  342. package/dist/surface/tools/lease-hint.d.ts +8 -0
  343. package/dist/surface/tools/lease-hint.js +10 -0
  344. package/dist/surface/tools/lease-tools.d.ts +16 -28
  345. package/dist/surface/tools/lease-tools.js +68 -11
  346. package/dist/surface/tools/lineage-tools.js +1 -1
  347. package/dist/surface/tools/live-call-text.js +4 -1
  348. package/dist/surface/tools/observe-tools.js +23 -7
  349. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  350. package/dist/surface/tools/real-input-attempt.js +1 -1
  351. package/dist/surface/tools/tool-kit.d.ts +5 -0
  352. package/dist/surface/tools/tool-kit.js +6 -1
  353. package/dist/surface/tools/tool-surface.js +17 -5
  354. package/dist/surface/tools/tools.js +68 -29
  355. package/dist/telemetry/argument-shape.d.ts +0 -2
  356. package/dist/telemetry/argument-shape.js +0 -4
  357. package/dist/telemetry/error-class.d.ts +2 -3
  358. package/dist/telemetry/error-class.js +2 -3
  359. package/dist/telemetry/feedback-local.d.ts +1 -0
  360. package/dist/telemetry/feedback-local.js +1 -3
  361. package/dist/telemetry/feedback.d.ts +1 -1
  362. package/dist/telemetry/harness-drive.d.ts +0 -2
  363. package/dist/telemetry/harness-drive.js +0 -4
  364. package/dist/telemetry/hud-metrics.d.ts +32 -0
  365. package/dist/telemetry/hud-metrics.js +95 -0
  366. package/dist/telemetry/session-metrics.d.ts +5 -0
  367. package/dist/telemetry/session-metrics.js +15 -1
  368. package/dist/wire-journal.d.ts +34 -0
  369. package/dist/wire-journal.js +104 -0
  370. package/dist/workspace-packages.d.ts +0 -2
  371. package/dist/workspace-packages.js +1 -9
  372. package/docs/README.md +5 -2
  373. package/docs/actions.mdx +3 -3
  374. package/docs/agent-cheatsheet.md +4 -4
  375. package/docs/architecture.md +6 -6
  376. package/docs/best-practices.mdx +1 -1
  377. package/docs/capabilities.mdx +32 -1
  378. package/docs/cli/cloud.mdx +21 -9
  379. package/docs/cli/doctor.mdx +4 -0
  380. package/docs/cli/feedback.mdx +2 -2
  381. package/docs/cli/gate.mdx +9 -4
  382. package/docs/cli/init.mdx +1 -0
  383. package/docs/cli/report.mdx +44 -0
  384. package/docs/cli/update.mdx +10 -0
  385. package/docs/cli.mdx +9 -0
  386. package/docs/desktop.mdx +14 -10
  387. package/docs/environment.mdx +87 -0
  388. package/docs/faq.mdx +18 -16
  389. package/docs/first-drive.md +5 -13
  390. package/docs/flows.md +32 -2
  391. package/docs/frameworks.mdx +140 -9
  392. package/docs/getting-started.md +3 -3
  393. package/docs/http-transport.md +6 -3
  394. package/docs/human-control.md +2 -2
  395. package/docs/index.mdx +16 -6
  396. package/docs/install-agentic.mdx +37 -1
  397. package/docs/install-manual.mdx +1 -1
  398. package/docs/integration-patterns.md +3 -3
  399. package/docs/multi-agent-testing.md +1 -1
  400. package/docs/packages/babel-plugin.mdx +1 -1
  401. package/docs/packages/browser.mdx +2 -2
  402. package/docs/packages/react.mdx +2 -2
  403. package/docs/packages/tauri.mdx +1 -1
  404. package/docs/packages/vite-plugin.mdx +2 -2
  405. package/docs/packages.mdx +9 -9
  406. package/docs/predicates.mdx +176 -7
  407. package/docs/quickstart.mdx +2 -2
  408. package/docs/recipes.mdx +2 -2
  409. package/docs/state-management.mdx +2 -2
  410. package/docs/system-map.md +1 -1
  411. package/docs/telemetry.md +1 -1
  412. package/docs/token-efficiency.md +3 -3
  413. package/docs/tools/act-and-wait.mdx +1 -0
  414. package/docs/tools/act-sequence.mdx +1 -1
  415. package/docs/tools/console.mdx +1 -1
  416. package/docs/tools/inspect.mdx +1 -1
  417. package/docs/tools/network.mdx +1 -1
  418. package/docs/tools/query.mdx +11 -11
  419. package/docs/tools/sessions.mdx +1 -1
  420. package/docs/tools/snapshot.mdx +1 -1
  421. package/docs/tools/state.mdx +1 -1
  422. package/docs/tools/wait-for.mdx +1 -1
  423. package/docs/usage.md +8 -7
  424. package/docs/use-cases.mdx +157 -0
  425. package/docs/vs-screenshots.mdx +3 -3
  426. package/docs/what-is-recorded.md +62 -0
  427. package/docs/what-is-reticle.mdx +17 -20
  428. package/docs/why-reticle.mdx +14 -21
  429. package/package.json +11 -10
  430. package/dist/judgement/capsule/minimize.d.ts +0 -12
  431. package/dist/judgement/capsule/minimize.js +0 -22
  432. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  433. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
  434. package/dist/judgement/phenomena/phenomena.d.ts +0 -26
  435. package/dist/judgement/phenomena/phenomena.js +0 -101
  436. package/dist/language/flows/flow-report.d.ts +0 -22
  437. package/dist/language/flows/flow-report.js +0 -106
@@ -0,0 +1,102 @@
1
+ /**
2
+ * A live session, as the explorer's port.
3
+ *
4
+ * The one hard part is that a full page load REPLACES the session: the SDK reconnects under the
5
+ * same id (sessionStorage keeps it) but as a new object, and a command in flight on the old one is
6
+ * rejected. So every call reads the CURRENT session, and anything that may have navigated waits for
7
+ * the successor before it answers — the same wait `navigate { reload }` does.
8
+ */
9
+ import { ActionType, ReticleCommand, ReticleTool, SnapshotMode, asRecord, asString, } from '@reticlehq/core';
10
+ import { RELOAD_RECONNECT_TIMEOUT_MS, waitForReconnect, } from '../../portal/session/session-reconnect.js';
11
+ import { isSessionReplacedError } from '../../portal/session/facts/session-replaced.js';
12
+ export function sessionPort(input) {
13
+ let current = input.start;
14
+ /** Wait for the document that replaced `before`. False when none arrived in time. */
15
+ const successor = async (before) => {
16
+ const back = await waitForReconnect({
17
+ current: () => input.sessions.get(before.id),
18
+ previous: before,
19
+ timeoutMs: RELOAD_RECONNECT_TIMEOUT_MS,
20
+ now: input.now,
21
+ sleep: input.sleep,
22
+ });
23
+ const next = input.sessions.get(before.id);
24
+ if (!back || next === undefined)
25
+ return false;
26
+ current = next;
27
+ return true;
28
+ };
29
+ const look = async () => {
30
+ for (let attempt = 0; attempt < 2; attempt += 1) {
31
+ try {
32
+ const res = await current.command(ReticleCommand.SNAPSHOT, {
33
+ mode: SnapshotMode.INTERACTIVE,
34
+ });
35
+ const body = asRecord(res.result);
36
+ const route = asString(asRecord(body['status'])['route']);
37
+ return { tree: asString(body['tree']) ?? '', ...(route === undefined ? {} : { route }) };
38
+ }
39
+ catch (error) {
40
+ // A click that followed a real link leaves the next read on a dead document.
41
+ if (!isSessionReplacedError(error) || !(await successor(current)))
42
+ break;
43
+ }
44
+ }
45
+ return { tree: '' };
46
+ };
47
+ return {
48
+ current: () => current,
49
+ look,
50
+ async reset() {
51
+ const before = current;
52
+ try {
53
+ const res = await before.command(ReticleCommand.NAVIGATE, { url: input.startUrl });
54
+ if (!res.ok)
55
+ return false;
56
+ }
57
+ catch (error) {
58
+ if (!isSessionReplacedError(error))
59
+ return false;
60
+ }
61
+ if (!(await successor(before)))
62
+ return false;
63
+ await input.sleep(input.settleMs);
64
+ return true;
65
+ },
66
+ async act(ref, action, value) {
67
+ const session = current;
68
+ const since = session.elapsed();
69
+ session.beginAction?.(ReticleTool.CRAWL, { ref, action });
70
+ let ok = false;
71
+ let replaced = false;
72
+ try {
73
+ const res = await session.command(ReticleCommand.ACT, {
74
+ ref,
75
+ action: 'fill' === action ? ActionType.FILL : ActionType.CLICK,
76
+ args: value === undefined ? {} : { value },
77
+ });
78
+ ok = res.ok && false !== asRecord(res.result)['dispatched'];
79
+ }
80
+ catch (error) {
81
+ // Following a real link replaces the document mid-command: the click WORKED.
82
+ if (!isSessionReplacedError(error))
83
+ throw error;
84
+ replaced = true;
85
+ ok = true;
86
+ }
87
+ finally {
88
+ session.finishAction?.();
89
+ }
90
+ await input.sleep(input.settleMs);
91
+ const events = session.eventsSince(since);
92
+ if (replaced && (await successor(session)))
93
+ return { ok, events: [...events, ...current.eventsSince(0)] };
94
+ return { ok, events };
95
+ },
96
+ ...(input.setMocks === undefined
97
+ ? {}
98
+ : {
99
+ mock: (rules) => input.setMocks?.(current.url, rules) ?? Promise.resolve(false),
100
+ }),
101
+ };
102
+ }
@@ -61,13 +61,4 @@ export declare function replayedFlows(toolCalls: readonly ToolOutcome[]): {
61
61
  }[];
62
62
  /** Reduce the raw call log to the actions that actually drove the app. */
63
63
  export declare function drivenSteps(toolCalls: readonly ToolOutcome[]): DrivenStep[];
64
- /**
65
- * The account, as lines.
66
- *
67
- * Proved and not-proved are counted separately and both are stated, because the failure mode this
68
- * whole product exists to prevent is a reader taking "we did twelve things" for "twelve things
69
- * work". `unknown` is deliberately grouped under NOT proved and labelled as undecided evidence
70
- * rather than as a failure — it calls for a better check, not a code change, and collapsing the two
71
- * would send an agent to rewrite working code.
72
- */
73
64
  export declare function describeDrive(toolCalls: readonly ToolOutcome[], savedFlows: readonly string[]): string;
@@ -134,6 +134,18 @@ export function drivenSteps(toolCalls) {
134
134
  * rather than as a failure — it calls for a better check, not a code change, and collapsing the two
135
135
  * would send an agent to rewrite working code.
136
136
  */
137
+ /** The pages the drive's own snapshots reported, in order, each distinct page once. */
138
+ function pagesReached(toolCalls) {
139
+ const pages = [];
140
+ for (const call of toolCalls) {
141
+ if (ReticleTool.SNAPSHOT !== call.name || call.isError)
142
+ continue;
143
+ const route = asString(asRecord(asRecord(call.result)['status'])['route']);
144
+ if (route !== undefined && !pages.includes(route))
145
+ pages.push(route);
146
+ }
147
+ return pages;
148
+ }
137
149
  export function describeDrive(toolCalls, savedFlows) {
138
150
  const steps = drivenSteps(toolCalls);
139
151
  const replays = replayedFlows(toolCalls);
@@ -166,10 +178,16 @@ export function describeDrive(toolCalls, savedFlows) {
166
178
  const proved = steps.filter((step) => Verified.YES === step.verified);
167
179
  const failed = steps.filter((step) => Verified.NO === step.verified);
168
180
  const undecided = steps.filter((step) => Verified.YES !== step.verified && Verified.NO !== step.verified);
181
+ const pages = pagesReached(toolCalls);
169
182
  const lines = [
170
183
  ...(replayLine === undefined ? [] : [replayLine]),
171
184
  `Drove ${String(steps.length)} action(s): ${String(proved.length)} proved, ` +
172
185
  `${String(failed.length)} failed, ${String(undecided.length)} not decided.`,
186
+ // How DEEP it got. An action count reads the same for a checkout walked to its receipt and for
187
+ // eleven clicks on the home page; the pages reached are what tell them apart.
188
+ ...(0 === pages.length
189
+ ? []
190
+ : [`Reached ${String(pages.length)} page(s): ${pages.join(' → ')}.`]),
173
191
  ];
174
192
  for (const step of steps.slice(0, MAX_LISTED)) {
175
193
  const verdict = step.verified ?? 'nothing declared';
@@ -11,7 +11,7 @@
11
11
  * purpose.
12
12
  */
13
13
  import { z } from 'zod';
14
- import { ReticleEnv, apiKeyFrom } from '@reticlehq/core';
14
+ import { ReticleEnv, platformCredentialFrom } from '@reticlehq/core';
15
15
  /**
16
16
  * The default driver model.
17
17
  *
@@ -91,13 +91,10 @@ export function harnessOptionsFromEnv(env) {
91
91
  *
92
92
  * An explicit `ANTHROPIC_API_KEY` still wins: someone who exported one meant it.
93
93
  */
94
- const cloudKey = apiKeyFrom(env);
95
- const cloudUrl = env[ReticleEnv.CLOUD_URL];
96
- if (cloudKey === undefined || 0 === cloudKey.length)
94
+ const cloud = platformCredentialFrom(env);
95
+ if (cloud === undefined)
97
96
  return undefined;
98
- if (cloudUrl === undefined || 0 === cloudUrl.length)
99
- return undefined;
100
- return withOptions(cloudKey, cloudUrl);
97
+ return withOptions(cloud.apiKey, cloud.url);
101
98
  }
102
99
  /** Build a driver backed by the Messages API. */
103
100
  export function harnessDriver(options) {
@@ -64,4 +64,10 @@ export declare function fillValues(deps: {
64
64
  generator?: HarnessDriverOptions;
65
65
  /** One line about where the drive is, so a value suits the page it is typed on. */
66
66
  context?: () => string;
67
+ /**
68
+ * A value the user SUPPLIED for this field — the same `RETICLE_SECRET_<FIELD>` replay reads for
69
+ * a redacted one. Checked first so a drive gets past a login, and never cached: the cache is a
70
+ * file on disk.
71
+ */
72
+ secret?: (label: string) => string | undefined;
67
73
  }): (label: string) => Promise<string>;
@@ -135,6 +135,9 @@ async function generateOne(options, label, context) {
135
135
  export function fillValues(deps) {
136
136
  let spent = 0;
137
137
  return async (label) => {
138
+ const supplied = deps.secret?.(label);
139
+ if (supplied !== undefined && supplied.length > 0)
140
+ return supplied;
138
141
  const cached = deps.cache?.get(label);
139
142
  if (cached !== undefined)
140
143
  return cached;
@@ -21,7 +21,7 @@
21
21
  * exist because this product is the verdict, and a verdict sourced from a model's confidence is the
22
22
  * thing Reticle sells the absence of.
23
23
  */
24
- import { RETICLE_URL_PARAM, ReticleEnv, ReticleTool, apiKeyFrom, asRecord, parseInteractive, } from '@reticlehq/core';
24
+ import { RETICLE_URL_PARAM, ReticleEnv, ReticleTool, platformCredentialFrom, asRecord, parseInteractive, } from '@reticlehq/core';
25
25
  import { FINISH_TOOL } from './harness.js';
26
26
  import { heuristicFillValue } from './fill-values.js';
27
27
  export const DEFAULT_JEV_MODEL = 'jev-latest';
@@ -55,12 +55,15 @@ const Tool = {
55
55
  RECORD: ReticleTool.RECORD,
56
56
  FLOW_SAVE: ReticleTool.FLOW_SAVE,
57
57
  FLOW_REPLAY: ReticleTool.FLOW_REPLAY,
58
+ NAVIGATE: ReticleTool.NAVIGATE,
58
59
  FINISH: FINISH_TOOL.name,
59
60
  };
60
61
  /** The synthetic option meaning "stop driving". Not a tool arg — a key in the choice set. */
61
62
  const FINISH_OPTION = 'finish';
62
63
  /** The synthetic option meaning "I cannot tell from this page; look again". */
63
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';
64
67
  /**
65
68
  * Tools the model may route to, beyond acting on a control.
66
69
  *
@@ -244,14 +247,11 @@ export function jevOptionsFromEnv(env) {
244
247
  };
245
248
  }
246
249
  // The ordinary path: the key the user minted on the platform, against the platform's own proxy.
247
- // Reticle never ships a Jev key, so without a base URL to send it to this is not a usable driver.
248
- const cloudKey = apiKeyFrom(env);
249
- const cloudUrl = env[ReticleEnv.CLOUD_URL];
250
- if (cloudKey === undefined || 0 === cloudKey.length)
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)
251
253
  return undefined;
252
- if (cloudUrl === undefined || 0 === cloudUrl.length)
253
- return undefined;
254
- return { apiKey: cloudKey, baseUrl: cloudUrl };
254
+ return { apiKey: cloud.apiKey, baseUrl: cloud.url };
255
255
  }
256
256
  /** Strip the snapshot's list marker, so a description reads as a phrase rather than a bullet. */
257
257
  function cleanDesc(desc) {
@@ -287,6 +287,8 @@ function readState(history) {
287
287
  saved: [],
288
288
  tree: undefined,
289
289
  route: undefined,
290
+ pages: [],
291
+ proved: [],
290
292
  replayed: [],
291
293
  acted: [],
292
294
  blocked: [],
@@ -333,13 +335,22 @@ function readState(history) {
333
335
  if ('string' === typeof tree)
334
336
  state.tree = tree;
335
337
  const route = asRecord(result['status'])['route'];
336
- if ('string' === typeof route)
338
+ if ('string' === typeof route) {
337
339
  state.route = appRoute(route);
340
+ if (state.pages.at(-1) !== route)
341
+ state.pages.push(route);
342
+ }
338
343
  }
344
+ if (Tool.NAVIGATE === outcome.name)
345
+ state.tree = undefined;
339
346
  if (Tool.ACT_AND_WAIT === outcome.name) {
340
347
  const ref = asRecord(outcome.args)['ref'];
341
348
  const failure = asRecord(outcome.result)['error'];
342
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);
343
354
  if ('string' === typeof ref) {
344
355
  // A refused act never happened, so it is not something this drive has driven. Recording
345
356
  // it as driven would retire the control after an attempt that never reached the app.
@@ -496,12 +507,10 @@ export function jevDriver(options) {
496
507
  const unsaved = drive.unsaved[0];
497
508
  if (unsaved !== undefined)
498
509
  return only(
499
- // `intent` is not decoration. A flow saved without one still replays, but when it goes
500
- // red the report can only name the step that broke, not the thing that stopped being true.
501
- request(Tool.FLOW_SAVE, {
502
- flowName: unsaved,
503
- intent: `Autonomous coverage drive of ${slugAfter(unsaved)}: ${String(drive.acted.length)} actions.`,
504
- }), `save ${unsaved}`);
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}`);
505
514
  /*
506
515
  * THE PLAN'S CHEAP HALF, and it runs before the model is asked anything.
507
516
  *
@@ -552,7 +561,7 @@ export function jevDriver(options) {
552
561
  // ── the one real decision ────────────────────────────────────────────────────────────────
553
562
  // What the drive is currently for: the first plan step that is not a replay. Replays are all
554
563
  // done by the time we reach here, so whatever is left is the intent nobody has proved.
555
- const objective = plan.find((step) => PLAN_REPLAY !== step.kind);
564
+ const objective = plan.find((step) => PLAN_REPLAY !== step.kind && !drive.proved.includes(step.target));
556
565
  const candidates = candidatesFrom(drive.tree);
557
566
  /**
558
567
  * A page with nothing to act on ends the DRIVE, not just the journey.
@@ -569,11 +578,15 @@ export function jevDriver(options) {
569
578
  return only(request(Tool.RECORD, { action: 'stop', recordingName: drive.open.name }), 'nothing interactive on this page; wind up');
570
579
  }
571
580
  const criteria = {
572
- [FINISH_OPTION]: 'Stop driving: the app has been covered, or nothing here leads anywhere new.',
581
+ [FINISH_OPTION]: 'Stop driving: every journey started here reached its end state, or nothing leads anywhere new.',
573
582
  [RELOOK_OPTION]: 'Look at the page again without acting, because this reading looks incomplete.',
574
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.',
575
584
  [STATE_OPTION]: "Read the application's own state, which is the strongest evidence there is and the one thing a screen cannot fake.",
576
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.`;
577
590
  for (const candidate of candidates) {
578
591
  const verb = actionFor(candidate.role);
579
592
  const already = drive.acted.includes(candidate.ref) ? ' (already driven once)' : '';
@@ -582,12 +595,12 @@ export function jevDriver(options) {
582
595
  const response = await callJev({ apiKey: options.apiKey, model, baseUrl, path, doFetch }, buildState(input.system, input.history, drive, objective), {
583
596
  next_action: {
584
597
  type: 'choice',
585
- instructions: 'Which single action best advances coverage of this application right now? Prefer a control that completes a real user journey, and prefer something not already driven.',
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.',
586
599
  criteria,
587
600
  },
588
601
  journey_complete: {
589
602
  type: 'noul',
590
- instructions: 'The application has been meaningfully covered by the actions driven so far, and further clicking would add nothing.',
603
+ instructions: 'Every journey started so far has been carried to its end state and checked there, and further driving would add nothing.',
591
604
  },
592
605
  });
593
606
  const usage = {
@@ -604,6 +617,8 @@ export function jevDriver(options) {
604
617
  }
605
618
  if (RELOOK_OPTION === chosen)
606
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);
607
622
  // Routing to a READ rather than an action. Neither changes the app, so neither is recorded as
608
623
  // something driven — they are how the drive finds out whether what it drove worked.
609
624
  if (OBSERVE_OPTION === chosen)
@@ -640,9 +655,8 @@ export function jevDriver(options) {
640
655
  ref: picked.ref,
641
656
  action,
642
657
  ...(wasRefused ? { args: { [DANGEROUS_ARG]: true } } : {}),
643
- // The element's own description, so the drive reads back as a journey rather than as refs.
644
- // A ref is a handle that expired when the page changed; this survives being read tomorrow.
645
- intent: `${action} ${picked.desc}`,
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.
646
660
  ...(consequence === undefined ? {} : { until: consequence.predicate }),
647
661
  };
648
662
  if ('fill' === action) {
@@ -17,7 +17,7 @@
17
17
  * it is reported below so the number is visible rather than assumed.
18
18
  */
19
19
  import { z } from 'zod';
20
- import { ReticleEnv, apiKeyFrom } from '@reticlehq/core';
20
+ import { ReticleEnv, platformCredentialFrom } from '@reticlehq/core';
21
21
  /**
22
22
  * The default model.
23
23
  *
@@ -71,13 +71,10 @@ export function openAiOptionsFromEnv(env) {
71
71
  const direct = env[ReticleEnv.HARNESS_OPENAI_KEY];
72
72
  if (direct !== undefined && 0 < direct.length)
73
73
  return withModel({ apiKey: direct });
74
- const cloudKey = apiKeyFrom(env);
75
- const cloudUrl = env[ReticleEnv.CLOUD_URL];
76
- if (cloudKey === undefined || 0 === cloudKey.length)
74
+ const cloud = platformCredentialFrom(env);
75
+ if (cloud === undefined)
77
76
  return undefined;
78
- if (cloudUrl === undefined || 0 === cloudUrl.length)
79
- return undefined;
80
- return withModel({ apiKey: cloudKey, baseUrl: cloudUrl });
77
+ return withModel({ apiKey: cloud.apiKey, baseUrl: cloud.url });
81
78
  }
82
79
  function toWireTool(tool) {
83
80
  return {
@@ -30,6 +30,16 @@ export interface PlatformModelConfig {
30
30
  * report "you turned this off" to somebody whose free months quietly ran out.
31
31
  */
32
32
  harnessEntitled: boolean;
33
+ /**
34
+ * Whether the platform actually holds a key for the provider this project is pointed at.
35
+ *
36
+ * Entitlement and readiness are different facts and the HUD needs both. A workspace can be fully
37
+ * entitled -- claimed period, `harnessEnabled` on -- against a deployment that has no provider key
38
+ * configured, and every signal then reads healthy while a drive cannot run. Absent reads as READY,
39
+ * on the same rule as the two booleans above: an older API that does not report availability must
40
+ * not have its silence treated as a refusal.
41
+ */
42
+ providerReady: boolean;
33
43
  }
34
44
  /** A GET, narrowed to what this file uses, so a test can answer it without a network. */
35
45
  export type ConfigFetch = (url: string, init: {
@@ -16,7 +16,7 @@
16
16
  * - it never overrides someone who was EXPLICIT. A driver named in the call, or set in the
17
17
  * environment, wins over the stored preference. Precedence lives in the caller.
18
18
  */
19
- import { ReticleEnv, apiKeyFrom } from '@reticlehq/core';
19
+ import { platformCredentialFrom } from '@reticlehq/core';
20
20
  const CONFIG_PATH = '/v1/model/config';
21
21
  /**
22
22
  * How long the daemon will wait for a preference before driving without it.
@@ -41,10 +41,18 @@ function parse(body) {
41
41
  // Same rule for both, for the same reason: an older API that reports neither must not have its
42
42
  // silence read as a refusal.
43
43
  const entitled = record['harnessEntitled'];
44
+ // `available` is keyed by provider and says which ones the platform holds a key for. Read only
45
+ // the entry for the provider this project uses: another provider being configured says nothing
46
+ // about whether THIS one can drive.
47
+ const available = record['available'];
48
+ const ready = 'object' === typeof available && null !== available
49
+ ? available[provider]
50
+ : undefined;
44
51
  return {
45
52
  provider,
46
53
  harnessEnabled: 'boolean' === typeof enabled ? enabled : true,
47
54
  harnessEntitled: 'boolean' === typeof entitled ? entitled : true,
55
+ providerReady: 'boolean' === typeof ready ? ready : true,
48
56
  };
49
57
  }
50
58
  catch {
@@ -60,12 +68,11 @@ function parse(body) {
60
68
  * warning printed on a path that then works correctly is how people learn to ignore stderr.
61
69
  */
62
70
  export async function fetchPlatformConfig(env, doFetch = (url, init) => fetch(url, init), timeoutMs = TIMEOUT_MS) {
63
- const key = apiKeyFrom(env);
64
- const host = env[ReticleEnv.CLOUD_URL];
65
- if (key === undefined || 0 === key.length)
66
- return undefined;
67
- if (host === undefined || 0 === host.length)
71
+ const cloud = platformCredentialFrom(env);
72
+ if (cloud === undefined)
68
73
  return undefined;
74
+ const key = cloud.apiKey;
75
+ const host = cloud.url;
69
76
  const controller = new AbortController();
70
77
  const timer = setTimeout(() => {
71
78
  controller.abort();
package/dist/index.d.ts CHANGED
@@ -15,13 +15,22 @@ export type { ToolDeps, ToolDef } from './surface/tools/tools.js';
15
15
  export { createToolInvoker, UNKNOWN_TOOL_ERROR } from './surface/tools/tool-invoker.js';
16
16
  export { runTool, SESSION_BOUND_TOOLS, SESSION_EXEMPT_TOOLS } from './surface/tools/invoke-tool.js';
17
17
  export type { ToolInvoker } from './surface/tools/tool-invoker.js';
18
+ /**
19
+ * The port-presence check the CLI commands (`drive`, `verify`, `status`, `doctor`, `kill`) all share,
20
+ * re-exported so a consumer embedding `start()` in its own process can refuse a taken port the same
21
+ * honest way instead of letting a raw `EADDRINUSE` stack out — the gap `@reticlehq/test`'s
22
+ * `bootSession()` had (reticlehq/reticle#1141): it called `start()` directly with no pre-flight probe.
23
+ */
24
+ export { probePresence, describePresence, PortPresence, } from './command/daemon/binding/port-presence.js';
25
+ export { probeDaemon } from './surface/mcp/proxy/proxy-daemon-probe.js';
26
+ export { fetchStatus } from './command/daemon/binding/daemon-status-probe.js';
18
27
  export { BaselineStore, normalizeLines, diffLines } from './memory/project/baselines.js';
19
28
  export { RecordingStore } from './language/flows/recording/tape/recordings.js';
20
29
  export type { RecordedStep, CompiledProgram } from './language/flows/recording/tape/recordings.js';
21
30
  export { FlowStore, recordedStepToFlowStep } from './language/flows/flows.js';
22
31
  export type { FlowResult } from './language/flows/flows.js';
23
32
  export type { Clock } from './machine/clock.js';
24
- export { assertSuccess, successToPredicate, dynamicTestids, successLabel, } from './language/flows/flow-success.js';
33
+ export { assertSuccess, dynamicTestids, successLabel, successToPredicate, } from './language/flows/flow-success.js';
25
34
  export { classifyFlowAssertions, FlowAssertionGrade } from './language/flows/flow-classify.js';
26
35
  export type { FlowAssertionClassification } from './language/flows/flow-classify.js';
27
36
  export { buildDomainModel } from './judgement/domain/domain-model.js';