@reticlehq/server 2.3.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 (424) 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} +105 -15
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -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/cli-parse.d.ts +143 -0
  25. package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
  26. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
  27. package/dist/{cli-port.js → cli/cli-port.js} +29 -8
  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 +182 -93
  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.d.ts +0 -6
  88. package/dist/flows/decision.js +64 -8
  89. package/dist/flows/empty-flow.d.ts +6 -0
  90. package/dist/flows/empty-flow.js +24 -0
  91. package/dist/flows/flake-store.d.ts +0 -1
  92. package/dist/flows/flake-store.js +1 -1
  93. package/dist/flows/flake.d.ts +2 -1
  94. package/dist/flows/flake.js +2 -2
  95. package/dist/flows/flow-classify.js +12 -0
  96. package/dist/flows/flow-replay-run.js +4 -4
  97. package/dist/flows/flow-replay.d.ts +5 -7
  98. package/dist/flows/flow-replay.js +114 -47
  99. package/dist/flows/flow-report.js +1 -1
  100. package/dist/flows/flow-scope.d.ts +1 -6
  101. package/dist/flows/flow-step-runners.d.ts +26 -6
  102. package/dist/flows/flow-step-runners.js +157 -6
  103. package/dist/flows/flow-success.js +20 -15
  104. package/dist/flows/flow-tools.js +67 -13
  105. package/dist/flows/flows.js +15 -11
  106. package/dist/flows/gate.d.ts +4 -3
  107. package/dist/flows/gate.js +1 -1
  108. package/dist/flows/heal-run.d.ts +0 -8
  109. package/dist/flows/heal-run.js +5 -5
  110. package/dist/flows/heal.js +3 -3
  111. package/dist/flows/predicate-to-expect.d.ts +38 -0
  112. package/dist/flows/predicate-to-expect.js +95 -0
  113. package/dist/flows/replay.d.ts +16 -1
  114. package/dist/flows/replay.js +58 -22
  115. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  116. package/dist/flows/role-anchor-nearest.js +45 -0
  117. package/dist/flows/server-verify.d.ts +1 -1
  118. package/dist/flows/server-verify.js +5 -5
  119. package/dist/flows/verify-change-tools.js +32 -10
  120. package/dist/flows/verify-change-verdict.d.ts +15 -0
  121. package/dist/flows/verify-change-verdict.js +25 -0
  122. package/dist/flows/watch-batcher.d.ts +3 -2
  123. package/dist/honesty/already-true.d.ts +2 -0
  124. package/dist/honesty/already-true.js +31 -0
  125. package/dist/honesty/blind-spots.d.ts +16 -3
  126. package/dist/honesty/blind-spots.js +24 -12
  127. package/dist/honesty/honesty.d.ts +3 -2
  128. package/dist/honesty/honesty.js +4 -4
  129. package/dist/honesty/uncaptured-bodies.js +1 -1
  130. package/dist/honesty/unread-outcome.js +2 -2
  131. package/dist/honesty/verified.d.ts +22 -3
  132. package/dist/honesty/verified.js +48 -8
  133. package/dist/http-server.js +14 -7
  134. package/dist/hunt/hunt-report.d.ts +2 -1
  135. package/dist/hunt/hunt-report.js +2 -2
  136. package/dist/index.d.ts +8 -6
  137. package/dist/index.js +32 -25
  138. package/dist/init/agent-rules.d.ts +2 -1
  139. package/dist/init/agent-rules.js +45 -7
  140. package/dist/init/app-choice.d.ts +20 -0
  141. package/dist/init/app-choice.js +25 -0
  142. package/dist/init/astro-host.d.ts +21 -0
  143. package/dist/init/astro-host.js +27 -0
  144. package/dist/init/astro-patch.d.ts +16 -0
  145. package/dist/init/astro-patch.js +240 -0
  146. package/dist/init/capabilities.d.ts +17 -0
  147. package/dist/init/capabilities.js +54 -0
  148. package/dist/init/cra.d.ts +37 -0
  149. package/dist/init/cra.js +90 -0
  150. package/dist/init/cursor.js +39 -4
  151. package/dist/init/desktop-doctor.d.ts +3 -2
  152. package/dist/init/desktop-doctor.js +4 -4
  153. package/dist/init/detect.d.ts +26 -0
  154. package/dist/init/detect.js +78 -5
  155. package/dist/init/mcp-registered.d.ts +12 -0
  156. package/dist/init/mcp-registered.js +14 -0
  157. package/dist/init/mcp.d.ts +27 -2
  158. package/dist/init/mcp.js +40 -4
  159. package/dist/init/next-patch.d.ts +39 -0
  160. package/dist/init/next-patch.js +196 -0
  161. package/dist/init/node-io.js +48 -6
  162. package/dist/init/patch-kind.d.ts +20 -0
  163. package/dist/init/patch-kind.js +10 -0
  164. package/dist/init/plan-framework.d.ts +50 -0
  165. package/dist/init/plan-framework.js +341 -0
  166. package/dist/init/plan.d.ts +119 -6
  167. package/dist/init/plan.js +230 -131
  168. package/dist/init/project-id.d.ts +5 -9
  169. package/dist/init/project-id.js +10 -22
  170. package/dist/init/run.d.ts +22 -0
  171. package/dist/init/run.js +393 -28
  172. package/dist/init/slash-command.d.ts +27 -0
  173. package/dist/init/slash-command.js +61 -0
  174. package/dist/init/snippets.d.ts +41 -3
  175. package/dist/init/snippets.js +185 -10
  176. package/dist/init/vite-config.d.ts +4 -10
  177. package/dist/init/vite-config.js +15 -7
  178. package/dist/init/workspace-apps.d.ts +23 -0
  179. package/dist/init/workspace-apps.js +68 -0
  180. package/dist/input/driven-redaction.d.ts +15 -0
  181. package/dist/input/driven-redaction.js +76 -0
  182. package/dist/input/network-detail.d.ts +9 -3
  183. package/dist/input/network-detail.js +43 -23
  184. package/dist/input/network-mock-tools.js +2 -2
  185. package/dist/input/network-mock.js +4 -4
  186. package/dist/input/real-input.js +8 -3
  187. package/dist/input/scroll-find.js +2 -2
  188. package/dist/input/scroll-tools.d.ts +0 -5
  189. package/dist/input/scroll-tools.js +11 -4
  190. package/dist/input/viewport-tools.js +2 -2
  191. package/dist/journal/ambient-store.d.ts +0 -2
  192. package/dist/journal/ambient-store.js +1 -1
  193. package/dist/journal/ambient.js +1 -1
  194. package/dist/journal/attach-journal.d.ts +2 -1
  195. package/dist/journal/deviation-report.js +6 -6
  196. package/dist/journal/deviation-service.js +1 -1
  197. package/dist/journal/envelope-store.d.ts +0 -2
  198. package/dist/journal/envelope-store.js +1 -1
  199. package/dist/journal/envelope.d.ts +2 -3
  200. package/dist/journal/envelope.js +3 -3
  201. package/dist/journal/journal-query.js +1 -1
  202. package/dist/journal/journal-recorder.d.ts +2 -1
  203. package/dist/journal/journal-recorder.js +2 -2
  204. package/dist/journal/rollups.js +9 -9
  205. package/dist/journal/session-end.d.ts +2 -1
  206. package/dist/journal/session-journal.js +4 -4
  207. package/dist/license/license.d.ts +0 -14
  208. package/dist/license/license.js +8 -8
  209. package/dist/log.d.ts +10 -0
  210. package/dist/log.js +11 -1
  211. package/dist/mcp/mcp-is-error.d.ts +13 -0
  212. package/dist/mcp/mcp-is-error.js +18 -0
  213. package/dist/mcp/mcp-outage.d.ts +31 -0
  214. package/dist/mcp/mcp-outage.js +48 -0
  215. package/dist/mcp/mcp-proxy.d.ts +124 -0
  216. package/dist/mcp/mcp-proxy.js +697 -0
  217. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  218. package/dist/{mcp.js → mcp/mcp.js} +110 -35
  219. package/dist/mcp/proxy-handshake.d.ts +3 -0
  220. package/dist/mcp/proxy-handshake.js +54 -0
  221. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  222. package/dist/mcp/proxy-lifecycle.js +70 -0
  223. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  224. package/dist/mcp/tool-catalog-cache.js +55 -0
  225. package/dist/oracles/propose-consequences.d.ts +2 -1
  226. package/dist/oracles/propose-consequences.js +16 -11
  227. package/dist/oracles/self-instrument.d.ts +2 -1
  228. package/dist/oracles/self-instrument.js +1 -1
  229. package/dist/phenomena/phenomena.js +3 -3
  230. package/dist/platform.d.ts +16 -0
  231. package/dist/platform.js +16 -0
  232. package/dist/pool/playwright-launcher.d.ts +15 -2
  233. package/dist/pool/playwright-launcher.js +21 -2
  234. package/dist/project/fs-port.js +1 -1
  235. package/dist/project/project-tools.js +2 -2
  236. package/dist/runs/build-verification-run.js +1 -1
  237. package/dist/runs/repair-prompt.d.ts +0 -6
  238. package/dist/runs/repair-prompt.js +3 -3
  239. package/dist/runs/risk-classify.js +1 -1
  240. package/dist/runs/run-diff.d.ts +0 -2
  241. package/dist/runs/run-diff.js +3 -3
  242. package/dist/runs/run-tools.js +2 -2
  243. package/dist/runs/verification-sync.js +2 -2
  244. package/dist/runs/verify-http.js +1 -1
  245. package/dist/runs/verify-server.js +1 -1
  246. package/dist/session/command-timeout.d.ts +11 -3
  247. package/dist/session/command-timeout.js +2 -2
  248. package/dist/session/control-envelope.d.ts +6 -0
  249. package/dist/session/control-envelope.js +7 -1
  250. package/dist/session/dev-server-probe.d.ts +13 -0
  251. package/dist/session/dev-server-probe.js +52 -0
  252. package/dist/session/last-act.d.ts +17 -3
  253. package/dist/session/last-act.js +16 -4
  254. package/dist/session/live-control-tools.js +7 -2
  255. package/dist/session/live-control.js +1 -1
  256. package/dist/session/looks-like-dev-server.d.ts +14 -0
  257. package/dist/session/looks-like-dev-server.js +25 -0
  258. package/dist/session/no-session-diagnosis.d.ts +38 -0
  259. package/dist/session/no-session-diagnosis.js +70 -0
  260. package/dist/session/no-session-watch.d.ts +19 -0
  261. package/dist/session/no-session-watch.js +61 -0
  262. package/dist/session/observed-state.d.ts +4 -0
  263. package/dist/session/observed-state.js +19 -1
  264. package/dist/session/output-budget.js +1 -1
  265. package/dist/session/session-health.d.ts +8 -1
  266. package/dist/session/session-health.js +8 -7
  267. package/dist/session/session-info.d.ts +26 -7
  268. package/dist/session/session-info.js +42 -1
  269. package/dist/session/session-lease.d.ts +0 -11
  270. package/dist/session/session-lease.js +1 -1
  271. package/dist/session/session-manager.d.ts +3 -0
  272. package/dist/session/session-manager.js +58 -9
  273. package/dist/session/session-readiness.d.ts +1 -1
  274. package/dist/session/session-readiness.js +6 -1
  275. package/dist/session/session-reaper.js +1 -1
  276. package/dist/session/session-reconnect.d.ts +32 -0
  277. package/dist/session/session-reconnect.js +42 -0
  278. package/dist/session/session.d.ts +20 -2
  279. package/dist/session/session.js +76 -26
  280. package/dist/session/state-select.d.ts +1 -1
  281. package/dist/session/state-select.js +1 -1
  282. package/dist/status-payload.d.ts +19 -0
  283. package/dist/status-payload.js +11 -0
  284. package/dist/telemetry/argument-shape.js +10 -1
  285. package/dist/telemetry/browser-mode.d.ts +27 -0
  286. package/dist/telemetry/browser-mode.js +33 -0
  287. package/dist/telemetry/bug-found.d.ts +17 -21
  288. package/dist/telemetry/bug-found.js +120 -8
  289. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  290. package/dist/telemetry/cli-telemetry.js +27 -4
  291. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  292. package/dist/telemetry/daemon-telemetry.js +12 -2
  293. package/dist/telemetry/dev-repo.js +4 -4
  294. package/dist/telemetry/error-fingerprint.js +21 -2
  295. package/dist/telemetry/feedback-cli.d.ts +1 -1
  296. package/dist/telemetry/feedback-cli.js +4 -4
  297. package/dist/telemetry/feedback-context.d.ts +22 -0
  298. package/dist/telemetry/feedback-context.js +41 -1
  299. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  300. package/dist/telemetry/feedback-delivery.js +30 -0
  301. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  302. package/dist/telemetry/feedback-outbox.js +87 -0
  303. package/dist/telemetry/feedback.d.ts +22 -1
  304. package/dist/telemetry/feedback.js +67 -8
  305. package/dist/telemetry/git-facts.js +1 -1
  306. package/dist/telemetry/session-metrics.d.ts +2 -0
  307. package/dist/telemetry/session-metrics.js +68 -6
  308. package/dist/telemetry/telemetry.d.ts +27 -2
  309. package/dist/telemetry/telemetry.js +119 -29
  310. package/dist/telemetry/verification-of.d.ts +22 -0
  311. package/dist/telemetry/verification-of.js +84 -0
  312. package/dist/tools/act-capsule.js +2 -2
  313. package/dist/tools/act-danger.d.ts +12 -0
  314. package/dist/tools/act-danger.js +20 -3
  315. package/dist/tools/act-helpers.js +4 -4
  316. package/dist/tools/act-tools.d.ts +0 -8
  317. package/dist/tools/act-tools.js +84 -115
  318. package/dist/tools/act-view.js +7 -7
  319. package/dist/tools/alias-args.d.ts +17 -0
  320. package/dist/tools/alias-args.js +25 -0
  321. package/dist/tools/assert-grade.js +9 -9
  322. package/dist/tools/assert-verdict.d.ts +3 -1
  323. package/dist/tools/assert-verdict.js +8 -5
  324. package/dist/tools/browser-tools.js +30 -11
  325. package/dist/tools/contract-tools.js +1 -1
  326. package/dist/tools/coverage-identity.d.ts +34 -0
  327. package/dist/tools/coverage-identity.js +46 -0
  328. package/dist/tools/coverage-tools.js +10 -14
  329. package/dist/tools/dynamic-tools.d.ts +2 -1
  330. package/dist/tools/dynamic-tools.js +90 -18
  331. package/dist/tools/error-recovery.d.ts +20 -2
  332. package/dist/tools/error-recovery.js +179 -4
  333. package/dist/tools/feedback-tools.d.ts +12 -1
  334. package/dist/tools/feedback-tools.js +28 -5
  335. package/dist/tools/invoke-tool.d.ts +0 -6
  336. package/dist/tools/invoke-tool.js +57 -32
  337. package/dist/tools/lease-hint.d.ts +17 -0
  338. package/dist/tools/lease-hint.js +24 -0
  339. package/dist/tools/lease-tools.js +6 -5
  340. package/dist/tools/merge-tools.d.ts +10 -1
  341. package/dist/tools/merge-tools.js +9 -3
  342. package/dist/tools/merged-name-redirect.d.ts +13 -0
  343. package/dist/tools/merged-name-redirect.js +55 -0
  344. package/dist/tools/navigate-result.d.ts +17 -0
  345. package/dist/tools/navigate-result.js +31 -0
  346. package/dist/tools/observe-tools.js +54 -20
  347. package/dist/tools/observed-nothing.d.ts +25 -0
  348. package/dist/tools/observed-nothing.js +33 -0
  349. package/dist/tools/query-paginate.js +2 -2
  350. package/dist/tools/query-shape.d.ts +18 -0
  351. package/dist/tools/query-shape.js +39 -0
  352. package/dist/tools/read-tools.js +85 -20
  353. package/dist/tools/real-input-attempt.d.ts +28 -0
  354. package/dist/tools/real-input-attempt.js +88 -0
  355. package/dist/tools/reconcile-tools.js +7 -7
  356. package/dist/tools/reload-result.d.ts +14 -0
  357. package/dist/tools/reload-result.js +29 -0
  358. package/dist/tools/snapshot-delta.d.ts +4 -5
  359. package/dist/tools/snapshot-delta.js +0 -0
  360. package/dist/tools/tool-kit.d.ts +8 -0
  361. package/dist/tools/tool-surface.d.ts +83 -0
  362. package/dist/tools/tool-surface.js +204 -0
  363. package/dist/tools/tools-helpers.js +6 -6
  364. package/dist/tools/tools.d.ts +15 -0
  365. package/dist/tools/tools.js +53 -17
  366. package/dist/tools/unadvertised-help.d.ts +5 -0
  367. package/dist/tools/unadvertised-help.js +39 -0
  368. package/dist/trace.d.ts +69 -0
  369. package/dist/trace.js +150 -0
  370. package/dist/update/nudge-credit.d.ts +4 -0
  371. package/dist/update/nudge-credit.js +53 -0
  372. package/dist/update/sdk-sync.d.ts +21 -0
  373. package/dist/update/sdk-sync.js +42 -0
  374. package/dist/update/update-checker.js +3 -3
  375. package/dist/update/update-nudge.d.ts +63 -6
  376. package/dist/update/update-nudge.js +128 -15
  377. package/dist/update/updater.d.ts +1 -9
  378. package/dist/update/updater.js +13 -8
  379. package/dist/version/peer-announce.d.ts +4 -0
  380. package/dist/version/peer-announce.js +30 -0
  381. package/dist/{server-version.js → version/server-version.js} +5 -1
  382. package/dist/version/version-nudge.d.ts +28 -0
  383. package/dist/version/version-nudge.js +40 -0
  384. package/dist/version/version-skew.d.ts +66 -0
  385. package/dist/version/version-skew.js +71 -0
  386. package/dist/visual/visual-diff.js +2 -2
  387. package/dist/visual/visual-tools.js +4 -4
  388. package/docs/agent-cheatsheet.md +85 -0
  389. package/docs/architecture.md +113 -0
  390. package/docs/benchmarks.md +255 -0
  391. package/docs/debugging.md +102 -0
  392. package/docs/deploy-checks.md +69 -0
  393. package/docs/desktop-apps.md +256 -0
  394. package/docs/enterprise.md +62 -0
  395. package/docs/fixtures.md +28 -0
  396. package/docs/flows.md +166 -0
  397. package/docs/getting-started.md +469 -0
  398. package/docs/human-control.md +63 -0
  399. package/docs/integration-patterns.md +171 -0
  400. package/docs/local-registry.md +126 -0
  401. package/docs/mint.json +61 -0
  402. package/docs/multi-agent-testing.md +55 -0
  403. package/docs/platform-integration.md +122 -0
  404. package/docs/telemetry-contract.md +214 -0
  405. package/docs/telemetry.md +184 -0
  406. package/docs/testing.md +82 -0
  407. package/docs/token-efficiency.md +80 -0
  408. package/docs/usage.md +1046 -0
  409. package/package.json +8 -5
  410. package/dist/cli-launch.js +0 -112
  411. package/dist/cli-parse.d.ts +0 -140
  412. package/dist/daemon-resilience.d.ts +0 -22
  413. package/dist/daemon-resilience.js +0 -85
  414. package/dist/mcp-proxy.d.ts +0 -35
  415. package/dist/mcp-proxy.js +0 -190
  416. package/dist/tools/profiles.d.ts +0 -37
  417. package/dist/tools/profiles.js +0 -139
  418. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  419. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  420. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  421. /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
  422. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  423. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  424. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -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[];
@@ -0,0 +1,204 @@
1
+ import { ReticleTool } from './tool-names.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 const TOOL_SURFACE = {
39
+ /** What every user gets: the verify loop, plus the 2 meta-tools that reach everything else. */
40
+ DEFAULT: 'default',
41
+ /** Every tool advertised directly, WITH output schemas. A verification switch — see above. */
42
+ ALL: 'all',
43
+ };
44
+ /**
45
+ * The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
46
+ *
47
+ * Named for what it does rather than which "profile" it selects, because the previous name invited
48
+ * users to shop among alternatives that did not meaningfully differ.
49
+ */
50
+ export const ADVERTISE_ALL_ENV = 'RETICLE_ADVERTISE_ALL_TOOLS';
51
+ /**
52
+ * The retired setting, still read so nobody's shell profile breaks.
53
+ *
54
+ * Every value it ever accepted resolves to something sensible: `full` to the ALL surface, everything
55
+ * else to the default. Silently honouring them would repeat the original sin, so `describeToolSurface`
56
+ * says the setting retired and what was used instead.
57
+ */
58
+ export const TOOL_PROFILE_ENV = 'RETICLE_TOOL_PROFILE';
59
+ const RETIRED_PROFILE_VALUES = {
60
+ full: TOOL_SURFACE.ALL,
61
+ hybrid: TOOL_SURFACE.DEFAULT,
62
+ core: TOOL_SURFACE.DEFAULT,
63
+ standard: TOOL_SURFACE.DEFAULT,
64
+ dynamic: TOOL_SURFACE.DEFAULT,
65
+ };
66
+ // The set an agent needs to verify a change end-to-end. Tool DEFINITIONS are re-sent every turn, so
67
+ // this set is a per-turn cost, and every name in it has to earn its place.
68
+ //
69
+ // MEASURED per-turn `tools/list` cost, off the real wire (spawn `mcp`, read tools/list, measure the
70
+ // serialized result), with a FRESH DAEMON per reading — the setting is read by the daemon at startup,
71
+ // so a loop that reuses one daemon measures the first surface every time and looks like proof that
72
+ // the setting does nothing. That happened while taking this very reading.
73
+ //
74
+ // default 18,183 B ~4,546 tok/turn 16 tools
75
+ // all 127,903 B ~31,976 tok/turn 48 tools
76
+ //
77
+ // Treat these as the SHAPE of the gap and re-measure before quoting one; counts are asserted in
78
+ // surface-sizes.test.ts, never from this comment.
79
+ //
80
+ // Where the cost sits on the default surface: inputSchema is 76% of the payload (parameter
81
+ // descriptions are half of that), tool descriptions are 12%, outputSchema ~0 because it is dropped.
82
+ // So the next real saving is in parameter prose, not in dropping more tools.
83
+ //
84
+ // There is a floor, though: an 8-tool cut (dropping act/navigate/wait_for/sessions) was MEASURED to
85
+ // regress real-agent accuracy 5/5 -> 3/5, because the model loses scaffolding and wanders on harder
86
+ // flows. Direct network/console stay (far more discoverable than observe-with-filters -> fewer turns,
87
+ // better verdicts).
88
+ //
89
+ // Evidence status: the 5/5 figure came from a single gpt-4o run and is STALE as a justification.
90
+ // Current-model evidence is indirect but real — the cost-delta run (bench/fix-loop/COST-DELTA.md)
91
+ // drove this surface on a current model and fixed 4/4 cells with ~25% FEWER tool calls than the
92
+ // baseline. A formal A/B against a leaner surface on a current model is still UNRUN.
93
+ // See bench/agent-loop-and-replay.md.
94
+ export const CORE_TOOL_NAMES = new Set([
95
+ ReticleTool.SESSIONS,
96
+ ReticleTool.NAVIGATE,
97
+ ReticleTool.SNAPSHOT,
98
+ ReticleTool.QUERY,
99
+ ReticleTool.ACT,
100
+ ReticleTool.ACT_AND_WAIT,
101
+ ReticleTool.OBSERVE,
102
+ ReticleTool.NETWORK,
103
+ ReticleTool.CONSOLE,
104
+ ReticleTool.WAIT_FOR,
105
+ ReticleTool.ASSERT,
106
+ ReticleTool.STATE,
107
+ // INSPECT is what turns a finding into an EDIT: it maps a DOM node to `src/App.tsx:104`. Finding a
108
+ // bug is half the job; knowing which file to open is the half that makes the agent useful, and it
109
+ // is the one capability here with no substitute in any other verification tool. It sat in
110
+ // `standard`, so under the default profile an agent had to already know it existed and reach it
111
+ // through reticle_run — which, observed over a drive of the whole surface, means it never gets called.
112
+ // The measured floor that justifies a lean core was about CUTTING to 8 (accuracy 5/5 → 3/5), not
113
+ // about holding at 12; one tool of schema tax to close the find→fix loop is the right trade.
114
+ ReticleTool.INSPECT,
115
+ // FEEDBACK is in every profile for the same reason INSPECT is: a tool an agent has to already know
116
+ // about, and reach through reticle_run, is a tool that never gets called. That is fatal here in a way
117
+ // it is not elsewhere — an unadvertised feedback channel collects nothing, which is indistinguishable
118
+ // from not having built one. It is also the cheapest tool on the surface to carry (three params) and
119
+ // the only one whose whole purpose is telling us which of the other fifteen are failing.
120
+ ReticleTool.FEEDBACK,
121
+ // SESSION is here because the product ORDERS the agent to call it. The session lease block is
122
+ // spliced onto the first result of every session ("call reticle_session {action:'yield'}"), and
123
+ // the pause hint is spliced onto every refusal while a human has the session paused, where
124
+ // {action:"resume"} is the only exit. Both were naming a tool the default surface did not
125
+ // advertise: an agent that obeyed got `unknown tool`, and an agent that did not left the panel
126
+ // reading "live" after it had stopped driving — which is the state the whole handback protocol
127
+ // exists to prevent.
128
+ //
129
+ // Measured cost: ~1.3 KB of prose (455 B description + ~780 B of parameter descriptions) on a
130
+ // surface whose prose is ~23.7 KB, so roughly +5%, a few hundred tokens a turn. The alternative —
131
+ // deleting the instruction from the lease and the pause hint — deletes the handback protocol,
132
+ // because there is nowhere else those two calls are ever named.
133
+ ReticleTool.SESSION,
134
+ ]);
135
+ /** Is the truthy form of a boolean env var set? `1`, `true`, `yes` — anything else is off. */
136
+ function envFlagOn(raw) {
137
+ if (raw === undefined)
138
+ return false;
139
+ const value = raw.trim().toLowerCase();
140
+ return '1' === value || 'true' === value || 'yes' === value || 'on' === value;
141
+ }
142
+ /**
143
+ * Which surface is live.
144
+ *
145
+ * `explicit` is the programmatic override (tests, `advertisedTools` callers). Otherwise the ALL
146
+ * switch decides, and the retired setting is honoured last so an old shell profile still works.
147
+ */
148
+ export function resolveToolSurface(explicit) {
149
+ if (explicit === TOOL_SURFACE.ALL)
150
+ return TOOL_SURFACE.ALL;
151
+ if (explicit === TOOL_SURFACE.DEFAULT)
152
+ return TOOL_SURFACE.DEFAULT;
153
+ const retiredExplicit = explicit === undefined ? undefined : RETIRED_PROFILE_VALUES[explicit];
154
+ if (retiredExplicit !== undefined)
155
+ return retiredExplicit;
156
+ if (envFlagOn(process.env[ADVERTISE_ALL_ENV]))
157
+ return TOOL_SURFACE.ALL;
158
+ const retiredEnv = RETIRED_PROFILE_VALUES[process.env[TOOL_PROFILE_ENV] ?? ''];
159
+ return retiredEnv ?? TOOL_SURFACE.DEFAULT;
160
+ }
161
+ /**
162
+ * Which surface is live, and what chose it.
163
+ *
164
+ * These settings are read by the DAEMON at startup, never by the client, so exporting one in an
165
+ * agent's environment while a daemon is already running changes nothing at all — which is exactly
166
+ * the observation that produced a "standard and full advertise the same tools" report. Documenting
167
+ * that was not enough; the setting failing to take has to be VISIBLE, so this rides along in the
168
+ * reticle_tools catalog.
169
+ */
170
+ export function describeToolSurface(active, requested) {
171
+ const retired = requested ?? process.env[TOOL_PROFILE_ENV];
172
+ if (retired !== undefined && retired in RETIRED_PROFILE_VALUES) {
173
+ return {
174
+ active,
175
+ source: `${TOOL_PROFILE_ENV}=${retired} is RETIRED — there is one tool surface now; using '${active}' (set ${ADVERTISE_ALL_ENV}=1 for the full, schema-carrying surface)`,
176
+ };
177
+ }
178
+ if (retired !== undefined && 0 < retired.length) {
179
+ return {
180
+ active,
181
+ source: `${TOOL_PROFILE_ENV} is RETIRED and '${retired}' was never one of its values; using '${active}'`,
182
+ };
183
+ }
184
+ const flag = process.env[ADVERTISE_ALL_ENV];
185
+ if (envFlagOn(flag)) {
186
+ return { active, source: `${ADVERTISE_ALL_ENV} set in the DAEMON's environment at startup` };
187
+ }
188
+ // "unset" and "set to 0" are different facts, and only one of them means "you did not ask for it".
189
+ // Reporting the second as the first is how somebody spends an afternoon on a switch that IS being
190
+ // read and is simply off.
191
+ return flag === undefined || 0 === flag.length
192
+ ? {
193
+ active,
194
+ source: `the one tool surface (${ADVERTISE_ALL_ENV} unset when the daemon started)`,
195
+ }
196
+ : { active, source: `the one tool surface (${ADVERTISE_ALL_ENV}='${flag}' is off)` };
197
+ }
198
+ export function filterTools(tools, surface) {
199
+ // CORE_TOOL_NAMES is what it always really was: the set advertised directly. It was never the
200
+ // interesting thing about the `core` PROFILE, whose only distinction was a second name for this.
201
+ if (surface === TOOL_SURFACE.DEFAULT)
202
+ return tools.filter((t) => CORE_TOOL_NAMES.has(t.name));
203
+ return tools;
204
+ }
@@ -11,13 +11,13 @@ export function parseInteractive(tree) {
11
11
  return items;
12
12
  }
13
13
  export function asString(value) {
14
- return typeof value === 'string' ? value : undefined;
14
+ return 'string' === typeof value ? value : undefined;
15
15
  }
16
16
  export function asNumber(value) {
17
- return typeof value === 'number' ? value : undefined;
17
+ return 'number' === typeof value ? value : undefined;
18
18
  }
19
19
  export function asRecord(value) {
20
- return typeof value === 'object' && value !== null ? value : {};
20
+ return 'object' === typeof value && value !== null ? value : {};
21
21
  }
22
22
  /**
23
23
  * A `{ file, line }` source location off an untrusted result payload, or undefined.
@@ -27,15 +27,15 @@ export function asRecord(value) {
27
27
  * worse than no location at all — it looks like an answer.
28
28
  */
29
29
  export function sourceOf(value) {
30
- if (value === null || typeof value !== 'object')
30
+ if (null === value || typeof value !== 'object')
31
31
  return undefined;
32
32
  const record = value;
33
33
  const file = record['file'];
34
34
  const line = record['line'];
35
- if (typeof file !== 'string' || file.length === 0 || typeof line !== 'number')
35
+ if (typeof file !== 'string' || 0 === file.length || typeof line !== 'number')
36
36
  return undefined;
37
37
  const out = { file, line };
38
- if (typeof record['column'] === 'number')
38
+ if ('number' === typeof record['column'])
39
39
  out.column = record['column'];
40
40
  return out;
41
41
  }
@@ -1,3 +1,18 @@
1
1
  import { type ToolDef } from './tool-kit.js';
2
+ import { type MergePlan } from './merge-tools.js';
2
3
  export type { ToolDef, ToolDeps } from './tool-kit.js';
4
+ /**
5
+ * surface consolidation. Tool defs are re-sent EVERY turn, so the advertised count is a per-turn
6
+ * tax multiplied by loop length. Sibling families collapse into one action-dispatched tool; the member
7
+ * handlers stay defined above and are simply no longer advertised separately.
8
+ *
9
+ * Guardrail (from the plan): the 12-tool core hot-set keeps its EXACT names and shapes and is never
10
+ * merged — sessions/navigate/snapshot/query/act/act_and_wait/observe/network/console/wait_for/assert/state.
11
+ */
12
+ export declare const MERGE_PLANS: MergePlan[];
13
+ /**
14
+ * Retired from the MCP surface entirely (capability preserved elsewhere, per the plan):
15
+ * - run_record: auto-recording on flow_replay already persists run outcomes.
16
+ */
17
+ export declare const RETIRED_FROM_SURFACE: string[];
3
18
  export declare const TOOLS: ToolDef[];