@reticlehq/server 2.4.0 → 2.5.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 (416) hide show
  1. package/SKILL.md +702 -0
  2. package/dist/bridge/auth-failure-reason.d.ts +19 -0
  3. package/dist/bridge/auth-failure-reason.js +29 -0
  4. package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
  5. package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
  6. package/dist/{bridge.d.ts → bridge/bridge.d.ts} +1 -1
  7. package/dist/{bridge.js → bridge/bridge.js} +63 -13
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +1 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +9 -9
  10. package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
  11. package/dist/capsule/capsule-store.d.ts +8 -3
  12. package/dist/capsule/capsule-store.js +7 -2
  13. package/dist/capsule/capsule.js +3 -3
  14. package/dist/capsule/causal-summary.d.ts +8 -0
  15. package/dist/capsule/causal-summary.js +22 -12
  16. package/dist/capsule/divergence.d.ts +9 -4
  17. package/dist/capsule/divergence.js +8 -8
  18. package/dist/capsule/predicate-to-links.js +11 -8
  19. package/dist/{cli-doctor.js → cli/cli-doctor.js} +9 -2
  20. package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
  21. package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
  22. package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
  23. package/dist/cli/cli-launch.js +171 -0
  24. package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +2 -11
  25. package/dist/{cli-parse.js → cli/cli-parse.js} +113 -60
  26. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
  27. package/dist/{cli-port.js → cli/cli-port.js} +9 -9
  28. package/dist/cli/cli-update-commands.d.ts +4 -0
  29. package/dist/cli/cli-update-commands.js +93 -0
  30. package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
  31. package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
  32. package/dist/cli.d.ts +2 -2
  33. package/dist/cli.js +174 -92
  34. package/dist/cloud/cloud-config.d.ts +0 -1
  35. package/dist/cloud/cloud-config.js +9 -9
  36. package/dist/cloud/cloud-sync.d.ts +1 -7
  37. package/dist/cloud/cloud-sync.js +12 -12
  38. package/dist/crawl/crawl-empty.d.ts +16 -0
  39. package/dist/crawl/crawl-empty.js +24 -0
  40. package/dist/crawl/crawl-tools.js +4 -1
  41. package/dist/crawl/crawl.js +26 -7
  42. package/dist/daemon/daemon-resilience.d.ts +49 -0
  43. package/dist/daemon/daemon-resilience.js +191 -0
  44. package/dist/daemon/daemon-usefulness.d.ts +61 -0
  45. package/dist/daemon/daemon-usefulness.js +62 -0
  46. package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
  47. package/dist/{daemon.js → daemon/daemon.js} +80 -48
  48. package/dist/daemon/idle-grace.d.ts +32 -0
  49. package/dist/daemon/idle-grace.js +41 -0
  50. package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
  51. package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
  52. package/dist/domain/domain-model.js +2 -2
  53. package/dist/events/body-failures.js +8 -8
  54. package/dist/events/contradictions.d.ts +1 -1
  55. package/dist/events/contradictions.js +60 -10
  56. package/dist/events/echo-mismatch.js +10 -10
  57. package/dist/events/event-filters.js +6 -6
  58. package/dist/events/json-salvage.d.ts +2 -1
  59. package/dist/events/json-salvage.js +6 -6
  60. package/dist/events/observed-in-window.d.ts +12 -0
  61. package/dist/events/observed-in-window.js +21 -0
  62. package/dist/events/predicate-eval.d.ts +43 -20
  63. package/dist/events/predicate-eval.js +159 -55
  64. package/dist/events/predicate.d.ts +2 -2
  65. package/dist/events/predicate.js +112 -35
  66. package/dist/events/reconcile.js +5 -5
  67. package/dist/events/ring-buffer.js +1 -1
  68. package/dist/events/stale-response.js +6 -6
  69. package/dist/events/testid-near-miss.d.ts +22 -0
  70. package/dist/events/testid-near-miss.js +33 -0
  71. package/dist/events/unit-mismatch.js +8 -8
  72. package/dist/flows/affected-tools.js +19 -4
  73. package/dist/flows/affected.js +1 -1
  74. package/dist/flows/annotate-target.d.ts +1 -0
  75. package/dist/flows/annotate-target.js +20 -0
  76. package/dist/flows/annotate-tools.js +25 -3
  77. package/dist/flows/annotate.js +17 -4
  78. package/dist/flows/assertion-integrity.d.ts +2 -1
  79. package/dist/flows/assertion-tiers-store.d.ts +3 -66
  80. package/dist/flows/assertion-tiers-store.js +2 -2
  81. package/dist/flows/attributed-failure.d.ts +17 -0
  82. package/dist/flows/attributed-failure.js +20 -0
  83. package/dist/flows/buddy-status.d.ts +2 -1
  84. package/dist/flows/buddy-status.js +2 -2
  85. package/dist/flows/coverage.d.ts +3 -2
  86. package/dist/flows/coverage.js +2 -2
  87. package/dist/flows/decision.js +24 -9
  88. package/dist/flows/empty-flow.d.ts +6 -0
  89. package/dist/flows/empty-flow.js +24 -0
  90. package/dist/flows/flake-store.d.ts +0 -1
  91. package/dist/flows/flake-store.js +1 -1
  92. package/dist/flows/flake.d.ts +2 -1
  93. package/dist/flows/flake.js +2 -2
  94. package/dist/flows/flow-classify.js +12 -0
  95. package/dist/flows/flow-replay-run.js +4 -4
  96. package/dist/flows/flow-replay.d.ts +5 -7
  97. package/dist/flows/flow-replay.js +114 -47
  98. package/dist/flows/flow-report.js +1 -1
  99. package/dist/flows/flow-scope.d.ts +1 -6
  100. package/dist/flows/flow-step-runners.d.ts +26 -6
  101. package/dist/flows/flow-step-runners.js +157 -6
  102. package/dist/flows/flow-success.js +20 -15
  103. package/dist/flows/flow-tools.js +53 -7
  104. package/dist/flows/flows.js +15 -11
  105. package/dist/flows/gate.d.ts +4 -3
  106. package/dist/flows/gate.js +1 -1
  107. package/dist/flows/heal-run.d.ts +0 -8
  108. package/dist/flows/heal-run.js +5 -5
  109. package/dist/flows/heal.js +3 -3
  110. package/dist/flows/predicate-to-expect.d.ts +38 -0
  111. package/dist/flows/predicate-to-expect.js +95 -0
  112. package/dist/flows/replay.d.ts +16 -1
  113. package/dist/flows/replay.js +58 -22
  114. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  115. package/dist/flows/role-anchor-nearest.js +45 -0
  116. package/dist/flows/server-verify.d.ts +1 -1
  117. package/dist/flows/server-verify.js +5 -5
  118. package/dist/flows/verify-change-tools.js +32 -10
  119. package/dist/flows/verify-change-verdict.d.ts +15 -0
  120. package/dist/flows/verify-change-verdict.js +25 -0
  121. package/dist/flows/watch-batcher.d.ts +3 -2
  122. package/dist/honesty/already-true.d.ts +2 -0
  123. package/dist/honesty/already-true.js +31 -0
  124. package/dist/honesty/blind-spots.d.ts +16 -3
  125. package/dist/honesty/blind-spots.js +24 -12
  126. package/dist/honesty/honesty.d.ts +3 -2
  127. package/dist/honesty/honesty.js +4 -4
  128. package/dist/honesty/uncaptured-bodies.js +1 -1
  129. package/dist/honesty/unread-outcome.js +2 -2
  130. package/dist/honesty/verified.d.ts +22 -3
  131. package/dist/honesty/verified.js +48 -8
  132. package/dist/http-server.js +14 -7
  133. package/dist/hunt/hunt-report.d.ts +2 -1
  134. package/dist/hunt/hunt-report.js +2 -2
  135. package/dist/index.d.ts +8 -6
  136. package/dist/index.js +32 -25
  137. package/dist/init/agent-rules.d.ts +2 -1
  138. package/dist/init/agent-rules.js +45 -7
  139. package/dist/init/app-choice.d.ts +20 -0
  140. package/dist/init/app-choice.js +25 -0
  141. package/dist/init/astro-host.d.ts +21 -0
  142. package/dist/init/astro-host.js +27 -0
  143. package/dist/init/astro-patch.d.ts +16 -0
  144. package/dist/init/astro-patch.js +240 -0
  145. package/dist/init/capabilities.js +4 -1
  146. package/dist/init/cra.d.ts +37 -0
  147. package/dist/init/cra.js +90 -0
  148. package/dist/init/cursor.js +39 -4
  149. package/dist/init/desktop-doctor.d.ts +3 -2
  150. package/dist/init/desktop-doctor.js +4 -4
  151. package/dist/init/detect.d.ts +3 -2
  152. package/dist/init/detect.js +16 -5
  153. package/dist/init/mcp-registered.d.ts +12 -0
  154. package/dist/init/mcp-registered.js +14 -0
  155. package/dist/init/mcp.d.ts +27 -2
  156. package/dist/init/mcp.js +40 -4
  157. package/dist/init/next-patch.d.ts +2 -4
  158. package/dist/init/next-patch.js +109 -19
  159. package/dist/init/node-io.js +23 -6
  160. package/dist/init/plan-framework.d.ts +16 -1
  161. package/dist/init/plan-framework.js +132 -8
  162. package/dist/init/plan.d.ts +73 -8
  163. package/dist/init/plan.js +133 -34
  164. package/dist/init/project-id.d.ts +5 -9
  165. package/dist/init/project-id.js +10 -22
  166. package/dist/init/run.d.ts +5 -0
  167. package/dist/init/run.js +210 -36
  168. package/dist/init/slash-command.d.ts +9 -0
  169. package/dist/init/slash-command.js +10 -1
  170. package/dist/init/snippets.d.ts +7 -10
  171. package/dist/init/snippets.js +44 -15
  172. package/dist/init/vite-config.js +1 -1
  173. package/dist/init/workspace-apps.d.ts +23 -0
  174. package/dist/init/workspace-apps.js +68 -0
  175. package/dist/input/driven-redaction.js +1 -1
  176. package/dist/input/network-detail.js +8 -8
  177. package/dist/input/network-mock-tools.js +2 -2
  178. package/dist/input/network-mock.js +4 -4
  179. package/dist/input/real-input.js +8 -3
  180. package/dist/input/scroll-find.js +2 -2
  181. package/dist/input/scroll-tools.d.ts +0 -5
  182. package/dist/input/scroll-tools.js +11 -4
  183. package/dist/input/viewport-tools.js +2 -2
  184. package/dist/journal/ambient-store.d.ts +0 -2
  185. package/dist/journal/ambient-store.js +1 -1
  186. package/dist/journal/ambient.js +1 -1
  187. package/dist/journal/attach-journal.d.ts +2 -1
  188. package/dist/journal/deviation-report.js +6 -6
  189. package/dist/journal/deviation-service.js +1 -1
  190. package/dist/journal/envelope-store.d.ts +0 -2
  191. package/dist/journal/envelope-store.js +1 -1
  192. package/dist/journal/envelope.d.ts +2 -3
  193. package/dist/journal/envelope.js +3 -3
  194. package/dist/journal/journal-query.js +1 -1
  195. package/dist/journal/journal-recorder.d.ts +2 -1
  196. package/dist/journal/journal-recorder.js +2 -2
  197. package/dist/journal/rollups.js +9 -9
  198. package/dist/journal/session-end.d.ts +2 -1
  199. package/dist/journal/session-journal.js +4 -4
  200. package/dist/license/license.d.ts +0 -14
  201. package/dist/license/license.js +8 -8
  202. package/dist/log.d.ts +10 -0
  203. package/dist/log.js +11 -1
  204. package/dist/mcp/mcp-is-error.d.ts +13 -0
  205. package/dist/mcp/mcp-is-error.js +18 -0
  206. package/dist/mcp/mcp-outage.d.ts +31 -0
  207. package/dist/mcp/mcp-outage.js +48 -0
  208. package/dist/mcp/mcp-proxy.d.ts +124 -0
  209. package/dist/mcp/mcp-proxy.js +697 -0
  210. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  211. package/dist/{mcp.js → mcp/mcp.js} +110 -35
  212. package/dist/mcp/proxy-handshake.d.ts +3 -0
  213. package/dist/mcp/proxy-handshake.js +54 -0
  214. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  215. package/dist/mcp/proxy-lifecycle.js +70 -0
  216. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  217. package/dist/mcp/tool-catalog-cache.js +55 -0
  218. package/dist/oracles/propose-consequences.d.ts +2 -1
  219. package/dist/oracles/propose-consequences.js +16 -11
  220. package/dist/oracles/self-instrument.d.ts +2 -1
  221. package/dist/oracles/self-instrument.js +1 -1
  222. package/dist/phenomena/phenomena.js +3 -3
  223. package/dist/platform.d.ts +16 -0
  224. package/dist/platform.js +16 -0
  225. package/dist/pool/playwright-launcher.d.ts +15 -2
  226. package/dist/pool/playwright-launcher.js +21 -2
  227. package/dist/project/fs-port.js +1 -1
  228. package/dist/project/project-tools.js +2 -2
  229. package/dist/runs/build-verification-run.js +1 -1
  230. package/dist/runs/repair-prompt.d.ts +0 -6
  231. package/dist/runs/repair-prompt.js +3 -3
  232. package/dist/runs/risk-classify.js +1 -1
  233. package/dist/runs/run-diff.d.ts +0 -2
  234. package/dist/runs/run-diff.js +3 -3
  235. package/dist/runs/run-tools.js +2 -2
  236. package/dist/runs/verification-sync.js +2 -2
  237. package/dist/runs/verify-http.js +1 -1
  238. package/dist/runs/verify-server.js +1 -1
  239. package/dist/session/command-timeout.d.ts +11 -3
  240. package/dist/session/command-timeout.js +2 -2
  241. package/dist/session/control-envelope.d.ts +6 -0
  242. package/dist/session/control-envelope.js +7 -1
  243. package/dist/session/dev-server-probe.d.ts +13 -0
  244. package/dist/session/dev-server-probe.js +52 -0
  245. package/dist/session/last-act.d.ts +17 -3
  246. package/dist/session/last-act.js +16 -4
  247. package/dist/session/live-control-tools.js +7 -2
  248. package/dist/session/live-control.js +1 -1
  249. package/dist/session/looks-like-dev-server.d.ts +14 -0
  250. package/dist/session/looks-like-dev-server.js +25 -0
  251. package/dist/session/no-session-diagnosis.d.ts +38 -0
  252. package/dist/session/no-session-diagnosis.js +70 -0
  253. package/dist/session/no-session-watch.d.ts +19 -0
  254. package/dist/session/no-session-watch.js +61 -0
  255. package/dist/session/observed-state.d.ts +4 -0
  256. package/dist/session/observed-state.js +19 -1
  257. package/dist/session/output-budget.js +1 -1
  258. package/dist/session/session-health.d.ts +8 -1
  259. package/dist/session/session-health.js +8 -7
  260. package/dist/session/session-info.d.ts +26 -7
  261. package/dist/session/session-info.js +42 -1
  262. package/dist/session/session-lease.d.ts +0 -11
  263. package/dist/session/session-lease.js +1 -1
  264. package/dist/session/session-manager.d.ts +3 -0
  265. package/dist/session/session-manager.js +52 -9
  266. package/dist/session/session-readiness.d.ts +1 -1
  267. package/dist/session/session-readiness.js +6 -1
  268. package/dist/session/session-reaper.js +1 -1
  269. package/dist/session/session-reconnect.d.ts +32 -0
  270. package/dist/session/session-reconnect.js +42 -0
  271. package/dist/session/session.d.ts +14 -2
  272. package/dist/session/session.js +69 -26
  273. package/dist/session/state-select.d.ts +1 -1
  274. package/dist/session/state-select.js +1 -1
  275. package/dist/status-payload.d.ts +19 -0
  276. package/dist/status-payload.js +11 -0
  277. package/dist/telemetry/argument-shape.js +10 -1
  278. package/dist/telemetry/browser-mode.d.ts +27 -0
  279. package/dist/telemetry/browser-mode.js +33 -0
  280. package/dist/telemetry/bug-found.d.ts +17 -21
  281. package/dist/telemetry/bug-found.js +120 -8
  282. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  283. package/dist/telemetry/cli-telemetry.js +27 -4
  284. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  285. package/dist/telemetry/daemon-telemetry.js +12 -2
  286. package/dist/telemetry/dev-repo.js +4 -4
  287. package/dist/telemetry/error-fingerprint.js +21 -2
  288. package/dist/telemetry/feedback-cli.d.ts +1 -1
  289. package/dist/telemetry/feedback-cli.js +4 -4
  290. package/dist/telemetry/feedback-context.d.ts +22 -0
  291. package/dist/telemetry/feedback-context.js +41 -1
  292. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  293. package/dist/telemetry/feedback-delivery.js +30 -0
  294. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  295. package/dist/telemetry/feedback-outbox.js +87 -0
  296. package/dist/telemetry/feedback.d.ts +22 -1
  297. package/dist/telemetry/feedback.js +67 -8
  298. package/dist/telemetry/git-facts.js +1 -1
  299. package/dist/telemetry/session-metrics.d.ts +2 -0
  300. package/dist/telemetry/session-metrics.js +68 -6
  301. package/dist/telemetry/telemetry.d.ts +27 -2
  302. package/dist/telemetry/telemetry.js +119 -29
  303. package/dist/telemetry/verification-of.d.ts +22 -0
  304. package/dist/telemetry/verification-of.js +84 -0
  305. package/dist/tools/act-capsule.js +2 -2
  306. package/dist/tools/act-danger.d.ts +12 -0
  307. package/dist/tools/act-danger.js +20 -3
  308. package/dist/tools/act-helpers.js +4 -4
  309. package/dist/tools/act-tools.d.ts +0 -8
  310. package/dist/tools/act-tools.js +84 -115
  311. package/dist/tools/act-view.js +7 -7
  312. package/dist/tools/alias-args.d.ts +17 -0
  313. package/dist/tools/alias-args.js +25 -0
  314. package/dist/tools/assert-grade.js +9 -9
  315. package/dist/tools/assert-verdict.d.ts +3 -1
  316. package/dist/tools/assert-verdict.js +8 -5
  317. package/dist/tools/browser-tools.js +30 -11
  318. package/dist/tools/contract-tools.js +1 -1
  319. package/dist/tools/coverage-identity.d.ts +34 -0
  320. package/dist/tools/coverage-identity.js +46 -0
  321. package/dist/tools/coverage-tools.js +10 -14
  322. package/dist/tools/dynamic-tools.d.ts +2 -1
  323. package/dist/tools/dynamic-tools.js +90 -18
  324. package/dist/tools/error-recovery.d.ts +20 -2
  325. package/dist/tools/error-recovery.js +179 -4
  326. package/dist/tools/feedback-tools.d.ts +12 -1
  327. package/dist/tools/feedback-tools.js +28 -5
  328. package/dist/tools/invoke-tool.d.ts +0 -6
  329. package/dist/tools/invoke-tool.js +57 -32
  330. package/dist/tools/lease-hint.d.ts +17 -0
  331. package/dist/tools/lease-hint.js +24 -0
  332. package/dist/tools/lease-tools.js +6 -5
  333. package/dist/tools/merge-tools.d.ts +10 -1
  334. package/dist/tools/merge-tools.js +9 -3
  335. package/dist/tools/merged-name-redirect.d.ts +13 -0
  336. package/dist/tools/merged-name-redirect.js +55 -0
  337. package/dist/tools/navigate-result.d.ts +17 -0
  338. package/dist/tools/navigate-result.js +31 -0
  339. package/dist/tools/observe-tools.js +54 -20
  340. package/dist/tools/observed-nothing.d.ts +25 -0
  341. package/dist/tools/observed-nothing.js +33 -0
  342. package/dist/tools/query-paginate.js +2 -2
  343. package/dist/tools/query-shape.d.ts +18 -0
  344. package/dist/tools/query-shape.js +39 -0
  345. package/dist/tools/read-tools.js +81 -20
  346. package/dist/tools/real-input-attempt.d.ts +28 -0
  347. package/dist/tools/real-input-attempt.js +88 -0
  348. package/dist/tools/reconcile-tools.js +7 -7
  349. package/dist/tools/reload-result.d.ts +14 -0
  350. package/dist/tools/reload-result.js +29 -0
  351. package/dist/tools/snapshot-delta.d.ts +4 -5
  352. package/dist/tools/snapshot-delta.js +0 -0
  353. package/dist/tools/tool-kit.d.ts +8 -0
  354. package/dist/tools/tool-surface.d.ts +83 -0
  355. package/dist/tools/tool-surface.js +204 -0
  356. package/dist/tools/tools-helpers.js +6 -6
  357. package/dist/tools/tools.d.ts +15 -0
  358. package/dist/tools/tools.js +53 -17
  359. package/dist/tools/unadvertised-help.d.ts +5 -0
  360. package/dist/tools/unadvertised-help.js +39 -0
  361. package/dist/trace.d.ts +69 -0
  362. package/dist/trace.js +150 -0
  363. package/dist/update/nudge-credit.d.ts +4 -0
  364. package/dist/update/nudge-credit.js +53 -0
  365. package/dist/update/sdk-sync.d.ts +21 -0
  366. package/dist/update/sdk-sync.js +42 -0
  367. package/dist/update/update-checker.js +3 -3
  368. package/dist/update/update-nudge.d.ts +63 -6
  369. package/dist/update/update-nudge.js +128 -15
  370. package/dist/update/updater.d.ts +1 -9
  371. package/dist/update/updater.js +13 -8
  372. package/dist/version/peer-announce.d.ts +4 -0
  373. package/dist/version/peer-announce.js +30 -0
  374. package/dist/{server-version.js → version/server-version.js} +5 -1
  375. package/dist/version/version-nudge.d.ts +28 -0
  376. package/dist/version/version-nudge.js +40 -0
  377. package/dist/version/version-skew.d.ts +66 -0
  378. package/dist/version/version-skew.js +71 -0
  379. package/dist/visual/visual-diff.js +2 -2
  380. package/dist/visual/visual-tools.js +4 -4
  381. package/docs/agent-cheatsheet.md +85 -0
  382. package/docs/architecture.md +113 -0
  383. package/docs/benchmarks.md +255 -0
  384. package/docs/debugging.md +102 -0
  385. package/docs/deploy-checks.md +69 -0
  386. package/docs/desktop-apps.md +256 -0
  387. package/docs/enterprise.md +62 -0
  388. package/docs/fixtures.md +28 -0
  389. package/docs/flows.md +166 -0
  390. package/docs/getting-started.md +469 -0
  391. package/docs/human-control.md +63 -0
  392. package/docs/integration-patterns.md +171 -0
  393. package/docs/local-registry.md +126 -0
  394. package/docs/mint.json +61 -0
  395. package/docs/multi-agent-testing.md +55 -0
  396. package/docs/platform-integration.md +122 -0
  397. package/docs/telemetry-contract.md +214 -0
  398. package/docs/telemetry.md +184 -0
  399. package/docs/testing.md +82 -0
  400. package/docs/token-efficiency.md +80 -0
  401. package/docs/usage.md +1046 -0
  402. package/package.json +8 -5
  403. package/dist/cli-launch.js +0 -112
  404. package/dist/daemon-resilience.d.ts +0 -22
  405. package/dist/daemon-resilience.js +0 -85
  406. package/dist/mcp-proxy.d.ts +0 -67
  407. package/dist/mcp-proxy.js +0 -337
  408. package/dist/tools/profiles.d.ts +0 -37
  409. package/dist/tools/profiles.js +0 -139
  410. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  411. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  412. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  413. /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
  414. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  415. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  416. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -2,18 +2,43 @@
2
2
  * Read / record / replay tools — baselines + diff, recordings + replay, narrate, clock, state,
3
3
  * explore. Split out of tools.ts; assembled back via...READ_TOOLS.
4
4
  */
5
+ import { resolveAnnotateTarget } from '../flows/annotate-target.js';
5
6
  import { z } from 'zod';
6
7
  import { EventType, ReticleCommand, REPLAY_PROGRAM_VERSION, SnapshotMode } from '@reticlehq/core';
7
8
  import { ReticleTool } from './tool-names.js';
8
9
  import { proposeConsequences } from '../oracles/propose-consequences.js';
9
10
  import { replayProgram } from '../flows/replay.js';
10
11
  import { diffLines } from '../project/baselines.js';
11
- import { selectPath, capDepth } from '../session/state-select.js';
12
+ import { selectPath, capDepth, projectComponentState } from '../session/state-select.js';
12
13
  import { costHint } from '../session/output-budget.js';
13
14
  import { buildReactionReport } from '../events/reaction.js';
14
15
  import { asString, asNumber, parseInteractive } from './tools-helpers.js';
15
16
  import { sessionIdShape, commandOrThrow, snapshotTree } from './tool-kit.js';
16
17
  import { bufferEnvelope } from '../session/session-health.js';
18
+ /**
19
+ * What record-stop says about a step that compiled to no anchor at all.
20
+ *
21
+ * `stable: false` does not mean "brittle". It means the compiler found no testid, no accessible
22
+ * role+name and no component/source, so the step is bound to a live `ref` — a handle that dies with
23
+ * the session. The replayer already states this outcome in full (see DEGRADED_STEP_REASON): the step
24
+ * can never resolve on replay.
25
+ *
26
+ * The old wording here — "replay may be brittle (in-session only)" — described a fatal condition as
27
+ * a quality note, so the agent saved the flow and learned the truth several calls later, as an
28
+ * unhealable `anchor_degraded` drift at flow_verify, by which point nothing on screen points back
29
+ * to the element that needed the attribute. Capture time is the only moment the fix is cheap: the
30
+ * element is still on the page and the human is still in the loop.
31
+ */
32
+ function unanchoredWarning(count) {
33
+ return (`${String(count)} step(s) not bound to a testid, an accessible role+name, or a component — ` +
34
+ 'they are pinned to a live ref, so they will replay in THIS session and can never resolve in ' +
35
+ 'another one. Add a data-testid to those elements and record the flow again, or accept that ' +
36
+ 'this recording is single-session only.');
37
+ }
38
+ /** Severities the presenter HUD can render. */
39
+ const HUD_LEVELS = ['info', 'warn', 'error'];
40
+ const HUD_LEVEL_LIST = HUD_LEVELS.join(' | ');
41
+ const hudLevelEnum = z.enum(HUD_LEVELS);
17
42
  export const READ_TOOLS = [
18
43
  {
19
44
  name: ReticleTool.BASELINE_SAVE,
@@ -64,7 +89,11 @@ export const READ_TOOLS = [
64
89
  buffer: z.unknown().optional(),
65
90
  },
66
91
  handler: async (deps, args) => {
67
- const name = asString(args['baseline']) ?? 'default';
92
+ // `name` too: the merged reticle_baseline family made this required field optional, and the
93
+ // SIBLING that creates a baseline calls it `name` — its description even says to reuse it
94
+ // here. So `{ action:"diff", name:"x" }` is a valid call that used to look up 'default' and
95
+ // report "no baseline named 'default'", naming something the caller never mentioned.
96
+ const name = asString(args['baseline']) ?? asString(args['name']) ?? 'default';
68
97
  const base = deps.baselines.get(name);
69
98
  if (base === undefined)
70
99
  throw new Error(`no baseline named '${name}'`);
@@ -127,10 +156,17 @@ export const READ_TOOLS = [
127
156
  },
128
157
  handler: (deps, args) => {
129
158
  const session = deps.sessions.resolve(asString(args['sessionId']));
130
- const name = asString(args['recordingName']) ?? 'default';
159
+ // The recording actually RUNNING when there is exactly one, not the literal name `default` —
160
+ // the same defaulting that made `annotate` report "no steps" against a recording full of them.
161
+ // With several running, `default` stays the documented answer rather than a guess.
162
+ const name = resolveAnnotateTarget(asString(args['recordingName']), deps.recordings.active());
131
163
  const rec = deps.recordings.stop(name);
132
- if (rec === undefined)
133
- throw new Error(`no active recording named '${name}'`);
164
+ if (rec === undefined) {
165
+ const active = deps.recordings.active();
166
+ throw new Error(0 === active.length
167
+ ? `no active recording named '${name}' — none is in progress`
168
+ : `no active recording named '${name}'; in progress: ${active.map((r) => `'${r}'`).join(', ')}`);
169
+ }
134
170
  const events = session.eventsSince(rec.cursor);
135
171
  const program = {
136
172
  name,
@@ -147,7 +183,7 @@ export const READ_TOOLS = [
147
183
  program,
148
184
  ...(unstable > 0
149
185
  ? {
150
- warning: `${String(unstable)} step(s) not bound to a testid; replay may be brittle (in-session only)`,
186
+ warning: unanchoredWarning(unstable),
151
187
  }
152
188
  : {}),
153
189
  ...(proposedConsequences.length > 0 ? { proposedConsequences } : {}),
@@ -186,7 +222,7 @@ export const READ_TOOLS = [
186
222
  throw new Error(`no compiled recording named '${name}'`);
187
223
  const session = deps.sessions.resolve(asString(args['sessionId']));
188
224
  const since = session.elapsed();
189
- const steps = await replayProgram(session, program, args['confirmDangerous'] === true);
225
+ const steps = await replayProgram(session, program, true === args['confirmDangerous']);
190
226
  return { recordingName: name, since, steps, ok: steps.every((s) => s.ok) };
191
227
  },
192
228
  },
@@ -197,10 +233,11 @@ export const READ_TOOLS = [
197
233
  text: z
198
234
  .string()
199
235
  .describe('Short sentence describing your next action, shown on the presenter HUD for the developer watching.'),
200
- level: z
201
- .string()
236
+ // Derived, like every other advertised vocabulary here: a free string let a typo through to
237
+ // a HUD that then rendered an unknown severity.
238
+ level: hudLevelEnum
202
239
  .optional()
203
- .describe('Display severity: info | warn | error. Default: info.'),
240
+ .describe(`Display severity: ${HUD_LEVEL_LIST}. Default: info.`),
204
241
  ...sessionIdShape,
205
242
  },
206
243
  outputSchema: { ok: z.boolean() },
@@ -227,9 +264,11 @@ export const READ_TOOLS = [
227
264
  reset: z.boolean().optional().describe('Restore the real clock.'),
228
265
  ...sessionIdShape,
229
266
  },
267
+ // The command returns `{ frozen }`. It used to declare `{ ok, elapsed }` — neither of which any
268
+ // clock code path produces — and MCP strips undeclared fields from structuredContent, so a
269
+ // successful freeze and a failed one both validated to `{}` and became indistinguishable.
230
270
  outputSchema: {
231
- ok: z.boolean().optional(),
232
- elapsed: z.number().optional(),
271
+ frozen: z.boolean().optional(),
233
272
  },
234
273
  handler: (deps, args) => commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.CLOCK, {
235
274
  freeze: args['freeze'],
@@ -275,7 +314,21 @@ export const READ_TOOLS = [
275
314
  // concludes the key it wants is absent when it is merely past the cap.
276
315
  totalKeys: z.number().optional(),
277
316
  component: z
278
- .object({ ok: z.boolean(), reason: z.string().optional(), state: z.unknown().optional() })
317
+ .object({
318
+ ok: z.boolean(),
319
+ reason: z.string().optional(),
320
+ state: z.unknown().optional(),
321
+ // The component name and the projected hook VALUES — declared so a schema-strict client
322
+ // keeps them (they were the point of passing `ref` at all).
323
+ component: z.string().optional(),
324
+ hooks: z.array(z.unknown()).optional(),
325
+ // Present only when effect hooks were projected out. Declared for the same reason as the
326
+ // store truncation report below: a shortened list with no marker reads as a complete one.
327
+ truncation: z
328
+ .object({ droppedItems: z.number(), note: z.string() })
329
+ .optional()
330
+ .describe('Present only when effect hooks were dropped — `hooks` is a projection.'),
331
+ })
279
332
  .optional(),
280
333
  // Truncation report — present ONLY when a transport cap trimmed the value. Declared so a
281
334
  // schema-strict client on the `full` profile KEEPS it: this is a false-green GUARD, and dropping
@@ -298,23 +351,31 @@ export const READ_TOOLS = [
298
351
  // Forward path/depth so a CURRENT browser SDK scopes the read IN-PAGE, before the transport —
299
352
  // the value never gets size-truncated in transit. (An older SDK ignores them and returns the
300
353
  // whole store; we then scope server-side below as a back-compat fallback.)
301
- const result = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.STATE_READ, {
354
+ const raw = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.STATE_READ, {
302
355
  ref: args['ref'],
303
356
  store,
304
357
  path,
305
358
  depth,
306
359
  });
360
+ // Project the component hook read BEFORE anything else touches it: React hands back the raw
361
+ // fiber hook list, whose effect entries are chained null-filled internals an agent cannot act
362
+ // on (measured: 2632 -> 1459 bytes on a five-state/three-effect component). Done here rather
363
+ // than in the SDK so an older browser build gets the same projection. The drop is disclosed
364
+ // on `component.truncation`.
365
+ const result = 'object' === typeof raw && null !== raw && 'component' in raw
366
+ ? { ...raw, component: projectComponentState(raw.component) }
367
+ : raw;
307
368
  // Normalize storeNames to a string[] regardless of how the wire delivered it — the
308
369
  // outputSchema requires an array, and a non-array here makes MCP reject the whole result
309
370
  // (so the agent gets nothing instead of the state). Defensive: a string becomes a 1-element array.
310
371
  const root = result;
311
372
  const names = Array.isArray(root.storeNames)
312
- ? root.storeNames.filter((n) => typeof n === 'string')
313
- : typeof root.storeNames === 'string' && root.storeNames.length > 0
373
+ ? root.storeNames.filter((n) => 'string' === typeof n)
374
+ : 'string' === typeof root.storeNames && root.storeNames.length > 0
314
375
  ? [root.storeNames]
315
376
  : [];
316
377
  // The browser already scoped it in-page (the `found` shape) — pass through, just safe storeNames.
317
- if (typeof root.found === 'boolean') {
378
+ if ('boolean' === typeof root.found) {
318
379
  return { ...root, storeNames: names };
319
380
  }
320
381
  if (path === undefined && depth === undefined) {
@@ -372,7 +433,7 @@ export const READ_TOOLS = [
372
433
  // The walk stops at its node cap and returns a document-order prefix, so an inventory taken
373
434
  // from a big page is a floor, not a census — and this is the tool crawl's description points
374
435
  // agents at first for "a non-destructive list of what is here".
375
- ...(snap.truncated === true ? { truncated: true } : {}),
436
+ ...(true === snap.truncated ? { truncated: true } : {}),
376
437
  consoleErrors,
377
438
  hint: 'act on each ref, observe the reaction, and report failed requests / console errors / dead controls',
378
439
  // Buffer-honesty: the console-error count spans the whole buffer, which evicts — signal it.
@@ -412,13 +473,13 @@ export const READ_TOOLS = [
412
473
  const area = asString(args['area']);
413
474
  const key = asString(args['key']);
414
475
  const result = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.STORAGE_READ, area !== undefined ? { area } : {});
415
- const data = (typeof result === 'object' && result !== null ? result : {});
476
+ const data = ('object' === typeof result && result !== null ? result : {});
416
477
  if (key === undefined)
417
478
  return data;
418
479
  // Look up the key in the scoped area, or across all three areas when none was named.
419
480
  const areas = area !== undefined ? [data] : [data['local'], data['session'], data['cookies']];
420
481
  for (const a of areas) {
421
- if (typeof a === 'object' && a !== null && key in a) {
482
+ if ('object' === typeof a && a !== null && key in a) {
422
483
  return { area, key, value: String(a[key]), found: true };
423
484
  }
424
485
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The native-input attempt — everything that decides whether a pointer action is driven through a
3
+ * real input provider or falls back to the occlusion-honest synthetic path, and WHY.
4
+ *
5
+ * Split out of act-tools.ts along its natural seam: the act tools care only about the outcome
6
+ * (`result` defined = it went native), never about provider availability, box resolution,
7
+ * drag-target inspection or the reason taxonomy.
8
+ */
9
+ import { ActionType, InputModeReason } from '@reticlehq/core';
10
+ import type { Session } from '../session/session.js';
11
+ import { type ToolDeps } from './tool-kit.js';
12
+ interface RealActResult {
13
+ /** Defined only on a successful native action; `undefined` means the synthetic path runs. */
14
+ result: unknown;
15
+ settled: boolean;
16
+ /** Set when a provider was available but threw — surfaces the fallback to the agent. */
17
+ fellBack?: boolean;
18
+ /** Why we went synthetic despite a configured provider (field bug #2: never a silent fallback). */
19
+ reason?: InputModeReason;
20
+ }
21
+ /**
22
+ * Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
23
+ * `reason` when a provider is configured) whenever the synthetic path should run — no matching
24
+ * page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
25
+ * flagged with `fellBack`. `result` is defined only on a real success.
26
+ */
27
+ export declare function tryRealInput(deps: ToolDeps, session: Session, ref: string, action: ActionType, args: Record<string, unknown>): Promise<RealActResult>;
28
+ export {};
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The native-input attempt — everything that decides whether a pointer action is driven through a
3
+ * real input provider or falls back to the occlusion-honest synthetic path, and WHY.
4
+ *
5
+ * Split out of act-tools.ts along its natural seam: the act tools care only about the outcome
6
+ * (`result` defined = it went native), never about provider availability, box resolution,
7
+ * drag-target inspection or the reason taxonomy.
8
+ */
9
+ import { ActionType, InputModeReason, ReticleCommand } from '@reticlehq/core';
10
+ import { isPointerAction } from '../input/real-input.js';
11
+ import { assertDragNotDestructive, assertNotDestructive } from './act-danger.js';
12
+ import { NATIVE_INPUT_ARG } from '@reticlehq/core';
13
+ import { asString, asRecord } from './tools-helpers.js';
14
+ import { commandOrThrow } from './tool-kit.js';
15
+ import { asBox } from './act-helpers.js';
16
+ /** Synthetic outcome with a diagnostic reason (provider configured but native input skipped). */
17
+ function synthetic(reason) {
18
+ return reason === undefined
19
+ ? { result: undefined, settled: false }
20
+ : { result: undefined, settled: false, reason };
21
+ }
22
+ /**
23
+ * Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
24
+ * `reason` when a provider is configured) whenever the synthetic path should run — no matching
25
+ * page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
26
+ * flagged with `fellBack`. `result` is defined only on a real success.
27
+ */
28
+ export async function tryRealInput(deps, session, ref, action, args) {
29
+ const provider = deps.realInput;
30
+ if (provider === undefined)
31
+ return synthetic(); // real input not configured — no diagnostic
32
+ if (!isPointerAction(action))
33
+ return synthetic(InputModeReason.NOT_POINTER); // fill/type stay synthetic
34
+ const inner = asRecord(args['args']);
35
+ // "Don't click, run the code": a click/dblclick runs the occlusion-honest SYNTHETIC path by default
36
+ // even with a provider configured — no coordinate gesture to be intercepted by the HUD or missed
37
+ // off-screen. Opt into a trusted native click with args.native:true (file pickers, clipboard,
38
+ // isTrusted-gated handlers). hover/drag genuinely need native pointer state, so they stay real.
39
+ if ((action === ActionType.CLICK || action === ActionType.DBLCLICK) &&
40
+ inner[NATIVE_INPUT_ARG] !== true) {
41
+ return synthetic(InputModeReason.SYNTHETIC_CLICK_PREFERRED);
42
+ }
43
+ if (!(await provider.isAvailableFor(session.url)))
44
+ return synthetic(InputModeReason.PAGE_NOT_CORRELATED);
45
+ const inspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, { ref });
46
+ assertNotDestructive(action, inner, inspected);
47
+ const box = asBox(inspected);
48
+ if (box === undefined)
49
+ return synthetic(InputModeReason.ELEMENT_NOT_LOCATABLE);
50
+ let toBox;
51
+ if (action === ActionType.DRAG) {
52
+ const toRef = asString(inner['toRef']);
53
+ if (toRef === undefined)
54
+ return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
55
+ const targetInspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, {
56
+ ref: toRef,
57
+ });
58
+ // A drag is judged on BOTH ends: dropping onto "Trash" is destructive however innocent the
59
+ // thing being dragged looks.
60
+ assertDragNotDestructive(inner, inspected, targetInspected);
61
+ toBox = asBox(targetInspected);
62
+ if (toBox === undefined)
63
+ return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
64
+ }
65
+ const performArgs = {};
66
+ const value = asString(inner['value']);
67
+ if (value !== undefined)
68
+ performArgs.value = value;
69
+ const text = asString(inner['text']);
70
+ if (text !== undefined)
71
+ performArgs.text = text;
72
+ if (toBox !== undefined)
73
+ performArgs.toBox = toBox;
74
+ try {
75
+ const performed = await provider.perform(session.url, action, box, performArgs);
76
+ if (!performed.performed)
77
+ return synthetic(InputModeReason.PROVIDER_DECLINED);
78
+ return { result: { performed: true, center: performed.center, action }, settled: true };
79
+ }
80
+ catch {
81
+ return {
82
+ result: undefined,
83
+ settled: false,
84
+ fellBack: true,
85
+ reason: InputModeReason.PROVIDER_ERROR,
86
+ };
87
+ }
88
+ }
@@ -28,17 +28,17 @@ async function capturedBodies(session, since, urlContains) {
28
28
  for (const event of events) {
29
29
  if (event.type !== EventType.NET_REQUEST)
30
30
  continue;
31
- const url = typeof event.data['url'] === 'string' ? event.data['url'] : '';
31
+ const url = 'string' === typeof event.data['url'] ? event.data['url'] : '';
32
32
  if (urlContains !== undefined && !url.includes(urlContains))
33
33
  continue;
34
34
  total += 1;
35
35
  const raw = event.data['responseBody'];
36
- if (typeof raw !== 'string' || raw.length === 0)
36
+ if (typeof raw !== 'string' || 0 === raw.length)
37
37
  continue;
38
38
  // A capped body is not an absent one. Recover the records that closed before the cut rather than
39
39
  // reporting nothing about the page with the most data on it.
40
40
  const salvaged = salvageJson(raw);
41
- if (salvaged.values.length === 0)
41
+ if (0 === salvaged.values.length)
42
42
  continue;
43
43
  bodies.push(...salvaged.values);
44
44
  withBody += 1;
@@ -79,11 +79,11 @@ export const RECONCILE_TOOLS = [
79
79
  const { bodies, withBody, total, truncated } = await capturedBodies(session, since, asString(args['urlContains']));
80
80
  // An empty result over data that was never read is the exact false green this tool exists to
81
81
  // prevent, so the two cases are reported differently and neither is silent.
82
- if (bodies.length === 0) {
82
+ if (0 === bodies.length) {
83
83
  return withControl(session, {
84
84
  mismatches: [],
85
85
  compared: 0,
86
- note: total === 0
86
+ note: 0 === total
87
87
  ? 'no responses in this window matched — nothing was compared'
88
88
  : `${String(total)} response(s) matched but NONE carried a recorded body, so nothing was compared. Enable it where your app calls connect(): \`reticle.connect({ captureNetworkBodies: true })\`, then re-run`,
89
89
  });
@@ -92,7 +92,7 @@ export const RECONCILE_TOOLS = [
92
92
  mode: SnapshotMode.FULL,
93
93
  });
94
94
  const tree = snapshot.tree;
95
- const mismatches = reconcile(bodies, typeof tree === 'string' ? tree : '');
95
+ const mismatches = reconcile(bodies, 'string' === typeof tree ? tree : '');
96
96
  // A truncated body is declared whether or not anything was found in it: "no mismatches" over a
97
97
  // partially-read payload is a weaker statement than over a whole one, and the difference is
98
98
  // exactly the kind of omission this layer exists to refuse.
@@ -100,7 +100,7 @@ export const RECONCILE_TOOLS = [
100
100
  ? {
101
101
  note: `${String(truncated)} of ${String(withBody)} response(s) exceeded the body cap and were read only up to the cut — records after it were not compared`,
102
102
  }
103
- : mismatches.length === 0
103
+ : 0 === mismatches.length
104
104
  ? {
105
105
  note: `compared ${String(withBody)} response(s); nothing on screen contradicts them`,
106
106
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * What `navigate { reload: true }` reports.
3
+ *
4
+ * It answered a bare `{ ok: true }`, while the URL branch of the same tool returns `confirmed: false`
5
+ * plus a note — because `ok` means the browser accepted the instruction, not that the page arrived.
6
+ * Identical semantics, one branch disclosing them and one not, and the silent one is the path most
7
+ * likely to need the caveat: a reload tears the SDK down, and a caller that acts on `ok: true` hits
8
+ * the window before it comes back.
9
+ *
10
+ * The permanent session loss reported alongside this is fixed separately — session-continuity.ts
11
+ * remembers the id in sessionStorage so a reload rejoins the SAME session instead of appearing as a
12
+ * new one. This is the remaining half: saying that the page is not back yet.
13
+ */
14
+ export declare function reloadResult(reconnected?: boolean): Record<string, unknown>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * What `navigate { reload: true }` reports.
3
+ *
4
+ * It answered a bare `{ ok: true }`, while the URL branch of the same tool returns `confirmed: false`
5
+ * plus a note — because `ok` means the browser accepted the instruction, not that the page arrived.
6
+ * Identical semantics, one branch disclosing them and one not, and the silent one is the path most
7
+ * likely to need the caveat: a reload tears the SDK down, and a caller that acts on `ok: true` hits
8
+ * the window before it comes back.
9
+ *
10
+ * The permanent session loss reported alongside this is fixed separately — session-continuity.ts
11
+ * remembers the id in sessionStorage so a reload rejoins the SAME session instead of appearing as a
12
+ * new one. This is the remaining half: saying that the page is not back yet.
13
+ */
14
+ /** The reload's own disclosure — the same shape and the same advice the URL branch gives. */
15
+ const RELOAD_NOTE = 'ok means the reload was DISPATCHED, not that the page came back — the SDK is torn down by the ' +
16
+ 'reload itself, so nothing here can see the new document yet. Call reticle_sessions to confirm ' +
17
+ 'the session reconnected before acting; the session id is preserved across a reload, so it will ' +
18
+ 'be the same one.';
19
+ /**
20
+ * What a CONFIRMED reload says. The page re-announced itself under the same id before this returned,
21
+ * so the next call is safe — which is the whole reason the tool now waits instead of advising.
22
+ */
23
+ const RELOAD_RECONNECTED_NOTE = 'the page came back and re-announced itself under the same session id, so this session is live ' +
24
+ 'again — no re-selection needed. Anything captured before the reload is gone with the old document.';
25
+ export function reloadResult(reconnected = false) {
26
+ return reconnected
27
+ ? { ok: true, confirmed: true, note: RELOAD_RECONNECTED_NOTE }
28
+ : { ok: true, confirmed: false, note: RELOAD_NOTE };
29
+ }
@@ -18,13 +18,13 @@ export declare const SnapshotDeltaMode: {
18
18
  readonly UNCHANGED: "unchanged";
19
19
  };
20
20
  export type SnapshotDeltaMode = (typeof SnapshotDeltaMode)[keyof typeof SnapshotDeltaMode];
21
- export interface SnapshotDelta {
21
+ interface SnapshotDelta {
22
22
  added: string[];
23
23
  removed: string[];
24
24
  addedCount: number;
25
25
  removedCount: number;
26
26
  }
27
- export type DeltaDecision = {
27
+ type DeltaDecision = {
28
28
  mode: typeof SnapshotDeltaMode.FULL;
29
29
  } | {
30
30
  mode: typeof SnapshotDeltaMode.UNCHANGED;
@@ -43,9 +43,7 @@ export declare class SnapshotCache {
43
43
  remember(key: string, route: string, tree: string): void;
44
44
  }
45
45
  export declare function snapshotCacheKey(sessionId: string, scope: string, mode: string): string;
46
- /** Said out loud when a diff was computed over a capped tree, so "unchanged" cannot mean "nothing happened". */
47
- export declare const CAPPED_DIFF_NOTE = "this diff covers only the first N nodes of the page (the snapshot hit its cap), so \"unchanged\" means \"unchanged in the part that was captured\" \u2014 narrow with `scope` to see the rest";
48
- export interface SnapshotDeltaOpts {
46
+ interface SnapshotDeltaOpts {
49
47
  sessionId: string;
50
48
  scope: string;
51
49
  mode: string;
@@ -58,3 +56,4 @@ export interface SnapshotDeltaOpts {
58
56
  * the pure `snapshotDelta`.
59
57
  */
60
58
  export declare function applySnapshotDelta(raw: unknown, opts: SnapshotDeltaOpts, cache: SnapshotCache): unknown;
59
+ export {};
Binary file
@@ -35,6 +35,14 @@ export interface ToolDeps {
35
35
  reticleRoot: string;
36
36
  /** injected clock for the contract's generatedAt stamp. */
37
37
  now: () => number;
38
+ /**
39
+ * The port this daemon's bridge listens on.
40
+ *
41
+ * Needed wherever a message has to name the OTHER half of a port mismatch — the commonest reason
42
+ * a leased tab loads the app and never dials in. Optional so every existing test construction of
43
+ * ToolDeps keeps working; absent falls back to the default port.
44
+ */
45
+ bridgePort?: number;
38
46
  }
39
47
  export interface ToolDef {
40
48
  name: string;
@@ -0,0 +1,83 @@
1
+ import type { ToolDef } from './tools.js';
2
+ /**
3
+ * There is ONE tool surface. This is not a menu.
4
+ *
5
+ * The advertised tool DEFINITIONS are re-sent to the model on every turn, so the surface is a
6
+ * per-turn cost that compounds across a loop, and fewer tools also makes the model wander less.
7
+ * What ships is the verify loop (navigate→look→act→observe→assert, with direct network + console +
8
+ * state) advertised directly, plus two meta-tools — `reticle_tools` to discover and `reticle_run` to
9
+ * invoke — that keep every other tool exactly one call away. Nothing is unreachable; the cold tail
10
+ * just is not re-sent every turn.
11
+ *
12
+ * Five profiles were tried. Four are gone, each for a measured reason rather than a taste:
13
+ *
14
+ * `core` was BYTE-IDENTICAL to the default — 16 tools, 18,183 bytes, the same list. One behaviour
15
+ * behind two names is how "I set it and nothing changed" becomes a support question with no answer.
16
+ *
17
+ * `standard` advertised 17 more tools directly for ~3,500 extra tokens EVERY TURN, buying only the
18
+ * removal of an occasional `reticle_run` hop. Nothing about that was characterisable as a use case.
19
+ *
20
+ * `dynamic` advertised the 2 meta-tools and nothing else. Not one harness, app or bench ever
21
+ * selected it, and this repo's own measurement (bench/agent-loop-and-replay.md) says a pure
22
+ * on-demand surface does NOT hold accuracy with a generic model: "it needs the hot-set schemas.
23
+ * On-demand is for the cold tail, not the hot path." An option that is unused and measured-worse is
24
+ * a trap, not a choice — it looks like a 4,000-token saving and costs correctness.
25
+ *
26
+ * ALL is what remains, and it is deliberately NOT a profile: it is a verification switch. It is the
27
+ * only mode that advertises `outputSchema`, which is what makes the MCP layer validate tool OUTPUT —
28
+ * the check that caught `reticle_verify_change` returning a payload its own schema rejected. It
29
+ * cannot be folded into the default: measured, carrying output schemas on the 16-tool surface costs
30
+ * 18,183 -> 41,117 bytes, 2.26x, +5,733 tokens per turn. And it cannot simply be deleted without
31
+ * losing that defect class. So it stays, named for what it is, and no user is asked to pick it.
32
+ *
33
+ * Sizes are NOT restated here — not as a current figure, not as a historical one. Four generations
34
+ * of this comment got them wrong. They live in surface-sizes.test.ts, which reads them off the real
35
+ * surface. (The numbers above are the two measurements that JUSTIFY a decision, which is a different
36
+ * job from documenting the current size; both were taken with a fresh daemon per reading.)
37
+ */
38
+ export declare const TOOL_SURFACE: {
39
+ /** What every user gets: the verify loop, plus the 2 meta-tools that reach everything else. */
40
+ readonly DEFAULT: "default";
41
+ /** Every tool advertised directly, WITH output schemas. A verification switch — see above. */
42
+ readonly ALL: "all";
43
+ };
44
+ export type ToolSurface = (typeof TOOL_SURFACE)[keyof typeof TOOL_SURFACE];
45
+ /**
46
+ * The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
47
+ *
48
+ * Named for what it does rather than which "profile" it selects, because the previous name invited
49
+ * users to shop among alternatives that did not meaningfully differ.
50
+ */
51
+ export declare const ADVERTISE_ALL_ENV = "RETICLE_ADVERTISE_ALL_TOOLS";
52
+ /**
53
+ * The retired setting, still read so nobody's shell profile breaks.
54
+ *
55
+ * Every value it ever accepted resolves to something sensible: `full` to the ALL surface, everything
56
+ * else to the default. Silently honouring them would repeat the original sin, so `describeToolSurface`
57
+ * says the setting retired and what was used instead.
58
+ */
59
+ export declare const TOOL_PROFILE_ENV = "RETICLE_TOOL_PROFILE";
60
+ export declare const CORE_TOOL_NAMES: ReadonlySet<string>;
61
+ /**
62
+ * Which surface is live.
63
+ *
64
+ * `explicit` is the programmatic override (tests, `advertisedTools` callers). Otherwise the ALL
65
+ * switch decides, and the retired setting is honoured last so an old shell profile still works.
66
+ */
67
+ export declare function resolveToolSurface(explicit?: string): ToolSurface;
68
+ /** The live surface plus what chose it — see describeToolSurface. */
69
+ export interface ToolSurfaceOrigin {
70
+ active: ToolSurface;
71
+ source: string;
72
+ }
73
+ /**
74
+ * Which surface is live, and what chose it.
75
+ *
76
+ * These settings are read by the DAEMON at startup, never by the client, so exporting one in an
77
+ * agent's environment while a daemon is already running changes nothing at all — which is exactly
78
+ * the observation that produced a "standard and full advertise the same tools" report. Documenting
79
+ * that was not enough; the setting failing to take has to be VISIBLE, so this rides along in the
80
+ * reticle_tools catalog.
81
+ */
82
+ export declare function describeToolSurface(active: ToolSurface, requested?: string): ToolSurfaceOrigin;
83
+ export declare function filterTools(tools: ToolDef[], surface: ToolSurface): ToolDef[];