@reticlehq/server 2.11.0 → 2.13.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 (513) hide show
  1. package/SKILL.md +93 -111
  2. package/dist/bridge/auth-failure-reason.d.ts +6 -2
  3. package/dist/bridge/auth-failure-reason.js +15 -8
  4. package/dist/bridge/bridge.d.ts +18 -14
  5. package/dist/bridge/bridge.js +248 -165
  6. package/dist/bridge/bridge.test-harness.d.ts +2 -0
  7. package/dist/bridge/bridge.test-harness.js +8 -1
  8. package/dist/bridge/pairing-token.d.ts +5 -0
  9. package/dist/bridge/pairing-token.js +28 -0
  10. package/dist/bridge/protocol-skew.d.ts +37 -0
  11. package/dist/bridge/protocol-skew.js +45 -0
  12. package/dist/capsule/capsule-store.d.ts +8 -7
  13. package/dist/capsule/capsule-store.js +1 -1
  14. package/dist/capsule/causal-summary.d.ts +2 -2
  15. package/dist/capsule/causal-summary.js +7 -2
  16. package/dist/chromium-launch-options.d.ts +28 -0
  17. package/dist/chromium-launch-options.js +29 -0
  18. package/dist/cli/cli-doctor.js +39 -1
  19. package/dist/cli/cli-flow-commands.d.ts +3 -1
  20. package/dist/cli/cli-flow-commands.js +34 -4
  21. package/dist/cli/cli-kill.d.ts +2 -1
  22. package/dist/cli/cli-launch.d.ts +11 -1
  23. package/dist/cli/cli-launch.js +59 -10
  24. package/dist/cli/cli-parse.d.ts +17 -1
  25. package/dist/cli/cli-parse.js +238 -12
  26. package/dist/cli/cli-update-commands.js +20 -1
  27. package/dist/cli/cli-verify.d.ts +2 -1
  28. package/dist/cli/cli-verify.js +5 -4
  29. package/dist/cli/cloud-cli.js +428 -253
  30. package/dist/cli/cloud-keystore.d.ts +37 -0
  31. package/dist/cli/cloud-keystore.js +97 -0
  32. package/dist/cli/cloud-kit.d.ts +37 -0
  33. package/dist/cli/cloud-kit.js +121 -0
  34. package/dist/cli/cloud-login.d.ts +17 -0
  35. package/dist/cli/cloud-login.js +183 -0
  36. package/dist/cli/cloud-session.d.ts +48 -0
  37. package/dist/cli/cloud-session.js +53 -0
  38. package/dist/cli/config-discovery.d.ts +2 -1
  39. package/dist/cli/config-discovery.js +1 -0
  40. package/dist/cli/daemon-start-options.d.ts +32 -0
  41. package/dist/cli/daemon-start-options.js +38 -0
  42. package/dist/cli/device-flow.d.ts +76 -0
  43. package/dist/cli/device-flow.js +56 -0
  44. package/dist/cli/doctor-rows.d.ts +12 -1
  45. package/dist/cli/doctor-rows.js +12 -1
  46. package/dist/cli/drive-attach.d.ts +13 -0
  47. package/dist/cli/drive-attach.js +18 -0
  48. package/dist/cli/drive-command.js +7 -3
  49. package/dist/cli/gate-exit.d.ts +21 -0
  50. package/dist/cli/gate-exit.js +21 -0
  51. package/dist/cli/gate-hook-message.d.ts +33 -0
  52. package/dist/cli/gate-hook-message.js +46 -0
  53. package/dist/cli/mcp-command.d.ts +25 -0
  54. package/dist/cli/mcp-command.js +174 -0
  55. package/dist/cli/project-name.d.ts +30 -0
  56. package/dist/cli/project-name.js +44 -0
  57. package/dist/cli/sibling-ports.d.ts +37 -0
  58. package/dist/cli/sibling-ports.js +56 -0
  59. package/dist/cli/status-next-action.d.ts +14 -0
  60. package/dist/cli/status-next-action.js +4 -4
  61. package/dist/cli.d.ts +1 -0
  62. package/dist/cli.js +167 -186
  63. package/dist/cloud/cloud-config.d.ts +24 -2
  64. package/dist/cloud/cloud-config.js +64 -5
  65. package/dist/cloud/cloud-sync.d.ts +16 -5
  66. package/dist/cloud/cloud-sync.js +64 -1
  67. package/dist/cloud/sync-cycle.d.ts +110 -0
  68. package/dist/cloud/sync-cycle.js +270 -0
  69. package/dist/cloud/sync-daemon.d.ts +69 -0
  70. package/dist/cloud/sync-daemon.js +260 -0
  71. package/dist/cloud/sync-disk.d.ts +9 -0
  72. package/dist/cloud/sync-disk.js +191 -0
  73. package/dist/cloud/sync-hash.d.ts +2 -0
  74. package/dist/cloud/sync-hash.js +35 -0
  75. package/dist/crawl/crawl-tools.js +5 -3
  76. package/dist/crawl/crawl.d.ts +12 -13
  77. package/dist/crawl/crawl.js +25 -3
  78. package/dist/daemon/daemon-resolve.d.ts +122 -0
  79. package/dist/daemon/daemon-resolve.js +187 -0
  80. package/dist/daemon/dev-servers.d.ts +15 -0
  81. package/dist/daemon/dev-servers.js +68 -0
  82. package/dist/daemon/free-port.d.ts +29 -0
  83. package/dist/daemon/free-port.js +55 -0
  84. package/dist/daemon/heartbeat.d.ts +0 -4
  85. package/dist/daemon/heartbeat.js +2 -2
  86. package/dist/daemon/wake-decision.d.ts +32 -0
  87. package/dist/daemon/wake-decision.js +38 -0
  88. package/dist/dev/stale-issue-guard.d.ts +0 -2
  89. package/dist/dev/stale-issue-guard.js +1 -1
  90. package/dist/domain/domain-tools.js +2 -2
  91. package/dist/events/contradictions.d.ts +59 -0
  92. package/dist/events/contradictions.js +253 -27
  93. package/dist/events/declared.d.ts +17 -0
  94. package/dist/events/declared.js +43 -1
  95. package/dist/events/echo-mismatch.js +65 -1
  96. package/dist/events/event-filters.d.ts +8 -0
  97. package/dist/events/event-filters.js +19 -2
  98. package/dist/events/observed-in-window.d.ts +12 -0
  99. package/dist/events/observed-in-window.js +17 -0
  100. package/dist/events/predicate-asks.d.ts +13 -0
  101. package/dist/events/predicate-asks.js +22 -0
  102. package/dist/events/predicate-eval.js +117 -27
  103. package/dist/events/predicate-parse.d.ts +0 -6
  104. package/dist/events/predicate-parse.js +43 -3
  105. package/dist/events/predicate-precheck.d.ts +8 -0
  106. package/dist/events/predicate-precheck.js +41 -0
  107. package/dist/events/predicate-route.d.ts +14 -0
  108. package/dist/events/predicate-route.js +36 -8
  109. package/dist/events/predicate-schema.d.ts +44 -0
  110. package/dist/events/predicate-schema.js +126 -23
  111. package/dist/events/predicate.d.ts +20 -0
  112. package/dist/events/predicate.js +77 -6
  113. package/dist/events/split-text-miss.d.ts +30 -0
  114. package/dist/events/split-text-miss.js +44 -0
  115. package/dist/flows/coverage.d.ts +0 -8
  116. package/dist/flows/coverage.js +1 -1
  117. package/dist/flows/decision.d.ts +5 -1
  118. package/dist/flows/decision.js +33 -7
  119. package/dist/flows/flake.d.ts +6 -8
  120. package/dist/flows/flake.js +1 -1
  121. package/dist/flows/flow-intent.d.ts +52 -0
  122. package/dist/flows/flow-intent.js +123 -0
  123. package/dist/flows/flow-memory-consult.d.ts +55 -0
  124. package/dist/flows/flow-memory-consult.js +38 -0
  125. package/dist/flows/flow-replay-run.d.ts +18 -7
  126. package/dist/flows/flow-replay-run.js +263 -23
  127. package/dist/flows/flow-replay.js +11 -2
  128. package/dist/flows/flow-step-runners.d.ts +8 -0
  129. package/dist/flows/flow-step-runners.js +8 -2
  130. package/dist/flows/flow-store-for-session.d.ts +31 -0
  131. package/dist/flows/flow-store-for-session.js +33 -0
  132. package/dist/flows/flow-success.js +15 -3
  133. package/dist/flows/flow-tools.js +87 -33
  134. package/dist/flows/flows.d.ts +14 -1
  135. package/dist/flows/flows.js +502 -24
  136. package/dist/flows/heal-run.js +5 -2
  137. package/dist/flows/predicate-to-expect.d.ts +17 -12
  138. package/dist/flows/predicate-to-expect.js +36 -15
  139. package/dist/flows/recordings.d.ts +13 -1
  140. package/dist/flows/recordings.js +17 -2
  141. package/dist/flows/replay.d.ts +22 -2
  142. package/dist/flows/replay.js +28 -2
  143. package/dist/flows/server-verify.js +16 -2
  144. package/dist/flows/verify-change-tools.js +9 -3
  145. package/dist/honesty/blind-spots.d.ts +51 -15
  146. package/dist/honesty/blind-spots.js +64 -4
  147. package/dist/honesty/feature-capture.d.ts +150 -0
  148. package/dist/honesty/feature-capture.js +233 -0
  149. package/dist/honesty/honesty.d.ts +24 -0
  150. package/dist/honesty/honesty.js +25 -1
  151. package/dist/honesty/instrumentation-gaps.d.ts +39 -6
  152. package/dist/honesty/instrumentation-gaps.js +88 -5
  153. package/dist/honesty/tool-hit-rate.d.ts +86 -0
  154. package/dist/honesty/tool-hit-rate.js +90 -0
  155. package/dist/honesty/undeclared-change.d.ts +51 -0
  156. package/dist/honesty/undeclared-change.js +56 -0
  157. package/dist/honesty/verified.d.ts +16 -0
  158. package/dist/honesty/verified.js +84 -5
  159. package/dist/http-server.d.ts +0 -1
  160. package/dist/http-server.js +13 -1
  161. package/dist/hunt/hunt-report.d.ts +0 -2
  162. package/dist/hunt/hunt-report.js +1 -1
  163. package/dist/impact/impact-recorder.d.ts +31 -8
  164. package/dist/impact/impact-recorder.js +104 -21
  165. package/dist/impact/impact-store.d.ts +13 -4
  166. package/dist/impact/impact-store.js +44 -3
  167. package/dist/index.d.ts +4 -1
  168. package/dist/index.js +113 -7
  169. package/dist/init/agent-rules.d.ts +30 -6
  170. package/dist/init/agent-rules.js +54 -13
  171. package/dist/init/astro-patch.d.ts +16 -0
  172. package/dist/init/astro-patch.js +28 -0
  173. package/dist/init/capabilities.d.ts +4 -3
  174. package/dist/init/capabilities.js +23 -3
  175. package/dist/init/closing-hint.d.ts +36 -0
  176. package/dist/init/closing-hint.js +120 -0
  177. package/dist/init/confirm.d.ts +27 -28
  178. package/dist/init/confirm.js +51 -11
  179. package/dist/init/cra.d.ts +34 -5
  180. package/dist/init/cra.js +96 -25
  181. package/dist/init/csp-check.js +17 -2
  182. package/dist/init/csp-doctor.d.ts +8 -1
  183. package/dist/init/csp-doctor.js +8 -3
  184. package/dist/init/dev-script.d.ts +50 -0
  185. package/dist/init/dev-script.js +66 -0
  186. package/dist/init/format-generated.d.ts +18 -0
  187. package/dist/init/format-generated.js +39 -0
  188. package/dist/init/install-hint.d.ts +9 -0
  189. package/dist/init/install-hint.js +29 -0
  190. package/dist/init/mcp-clients.d.ts +7 -0
  191. package/dist/init/mcp-clients.js +7 -0
  192. package/dist/init/mcp.d.ts +17 -6
  193. package/dist/init/mcp.js +27 -11
  194. package/dist/init/node-io.js +11 -1
  195. package/dist/init/plan-framework.d.ts +0 -5
  196. package/dist/init/plan-framework.js +147 -37
  197. package/dist/init/plan.d.ts +30 -37
  198. package/dist/init/plan.js +50 -60
  199. package/dist/init/preflight.d.ts +28 -0
  200. package/dist/init/preflight.js +38 -0
  201. package/dist/init/refresh-rules.d.ts +39 -0
  202. package/dist/init/refresh-rules.js +51 -0
  203. package/dist/init/run.d.ts +32 -35
  204. package/dist/init/run.js +151 -202
  205. package/dist/init/slash-command.d.ts +1 -1
  206. package/dist/init/snippets.js +90 -31
  207. package/dist/init/vite-config.d.ts +1 -1
  208. package/dist/init/vite-config.js +39 -25
  209. package/dist/init/workspace-apps.d.ts +17 -10
  210. package/dist/init/workspace-apps.js +110 -0
  211. package/dist/input/network-mock-tools.js +3 -6
  212. package/dist/input/real-input.d.ts +2 -0
  213. package/dist/input/real-input.js +28 -7
  214. package/dist/input/scroll-find.d.ts +7 -4
  215. package/dist/input/scroll-find.js +63 -25
  216. package/dist/input/scroll-tools.js +4 -6
  217. package/dist/input/viewport-tools.js +5 -4
  218. package/dist/intent/inline-intent.d.ts +37 -0
  219. package/dist/intent/inline-intent.js +193 -0
  220. package/dist/intent/intent-shard-store.d.ts +72 -0
  221. package/dist/intent/intent-shard-store.js +203 -0
  222. package/dist/intent/intent-shard.d.ts +411 -0
  223. package/dist/intent/intent-shard.js +176 -0
  224. package/dist/intent/intent-store.d.ts +49 -0
  225. package/dist/intent/intent-store.js +133 -0
  226. package/dist/intent/intent-subject.d.ts +45 -0
  227. package/dist/intent/intent-subject.js +177 -0
  228. package/dist/intent/intent-tools.d.ts +2 -0
  229. package/dist/intent/intent-tools.js +143 -0
  230. package/dist/intent/open-intents.d.ts +42 -0
  231. package/dist/intent/open-intents.js +40 -0
  232. package/dist/journal/envelope.d.ts +26 -26
  233. package/dist/journal/journal-recorder.d.ts +23 -0
  234. package/dist/journal/journal-recorder.js +35 -0
  235. package/dist/license/license-env.d.ts +29 -0
  236. package/dist/license/license-env.js +148 -0
  237. package/dist/loopback-agent.d.ts +31 -0
  238. package/dist/loopback-agent.js +57 -0
  239. package/dist/mcp/attach-memory.d.ts +83 -0
  240. package/dist/mcp/attach-memory.js +185 -0
  241. package/dist/mcp/client-identity.d.ts +31 -0
  242. package/dist/mcp/client-identity.js +51 -0
  243. package/dist/mcp/mcp-post-transport.d.ts +26 -0
  244. package/dist/mcp/mcp-post-transport.js +109 -0
  245. package/dist/mcp/mcp-proxy.d.ts +2 -8
  246. package/dist/mcp/mcp-proxy.js +64 -62
  247. package/dist/mcp/mcp.d.ts +2 -0
  248. package/dist/mcp/mcp.js +52 -24
  249. package/dist/mcp/proxy-backoff.d.ts +11 -0
  250. package/dist/mcp/proxy-backoff.js +13 -0
  251. package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
  252. package/dist/mcp/proxy-daemon-probe.js +7 -1
  253. package/dist/mcp/proxy-handshake.d.ts +23 -0
  254. package/dist/mcp/proxy-handshake.js +31 -0
  255. package/dist/mcp/server-instructions.js +45 -3
  256. package/dist/mcp/tool-catalog-cache.d.ts +16 -0
  257. package/dist/mcp/tool-catalog-cache.js +22 -0
  258. package/dist/memory/memory-tools.d.ts +2 -0
  259. package/dist/memory/memory-tools.js +82 -0
  260. package/dist/memory/project-memory.d.ts +34 -0
  261. package/dist/memory/project-memory.js +96 -0
  262. package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
  263. package/dist/oracles/flow-instrument-gaps.js +4 -5
  264. package/dist/oracles/propose-consequences.js +12 -3
  265. package/dist/oracles/self-instrument.d.ts +9 -9
  266. package/dist/oracles/self-instrument.js +19 -13
  267. package/dist/pool/browser-pool.d.ts +75 -5
  268. package/dist/pool/browser-pool.js +144 -5
  269. package/dist/pool/playwright-launcher.js +12 -1
  270. package/dist/project/fs-port.d.ts +3 -0
  271. package/dist/project/fs-port.js +3 -2
  272. package/dist/project/memory-fs.js +6 -1
  273. package/dist/project/project-tools.js +6 -35
  274. package/dist/project/reticle-dir.d.ts +17 -2
  275. package/dist/project/reticle-dir.js +22 -4
  276. package/dist/runs/context-tools.d.ts +2 -0
  277. package/dist/runs/context-tools.js +89 -0
  278. package/dist/runs/run-context.d.ts +40 -0
  279. package/dist/runs/run-context.js +158 -0
  280. package/dist/runs/run-diff.d.ts +2 -1
  281. package/dist/runs/run-store.d.ts +10 -0
  282. package/dist/runs/run-store.js +10 -0
  283. package/dist/runs/verification-sync.d.ts +0 -11
  284. package/dist/runs/verification-sync.js +24 -3
  285. package/dist/runs/verify-server.d.ts +8 -1
  286. package/dist/runs/verify-server.js +14 -2
  287. package/dist/session/command-timeout.d.ts +5 -2
  288. package/dist/session/command-timeout.js +5 -4
  289. package/dist/session/dev-server-probe.d.ts +0 -8
  290. package/dist/session/dev-server-probe.js +1 -1
  291. package/dist/session/last-act.d.ts +7 -1
  292. package/dist/session/last-act.js +2 -2
  293. package/dist/session/lease-visibility.d.ts +67 -0
  294. package/dist/session/lease-visibility.js +76 -0
  295. package/dist/session/live-control-tools.js +1 -42
  296. package/dist/session/no-session-diagnosis.d.ts +33 -0
  297. package/dist/session/no-session-diagnosis.js +82 -24
  298. package/dist/session/no-session-next-action.d.ts +12 -0
  299. package/dist/session/no-session-next-action.js +77 -6
  300. package/dist/session/no-session-watch.d.ts +18 -6
  301. package/dist/session/no-session-watch.js +125 -75
  302. package/dist/session/output-budget.js +4 -1
  303. package/dist/session/pending-commands.d.ts +11 -1
  304. package/dist/session/pending-commands.js +12 -2
  305. package/dist/session/resolve-within.d.ts +34 -0
  306. package/dist/session/resolve-within.js +53 -0
  307. package/dist/session/session-health.d.ts +9 -0
  308. package/dist/session/session-health.js +23 -0
  309. package/dist/session/session-info.d.ts +18 -0
  310. package/dist/session/session-info.js +11 -0
  311. package/dist/session/session-manager.d.ts +14 -0
  312. package/dist/session/session-manager.js +111 -4
  313. package/dist/session/session-mirror.d.ts +16 -0
  314. package/dist/session/session-mirror.js +22 -0
  315. package/dist/session/session-recommendation.d.ts +19 -5
  316. package/dist/session/session-recommendation.js +25 -9
  317. package/dist/session/session-successor.d.ts +37 -0
  318. package/dist/session/session-successor.js +113 -0
  319. package/dist/session/session-tools.js +2 -2
  320. package/dist/session/session.d.ts +53 -3
  321. package/dist/session/session.js +162 -9
  322. package/dist/session/wall-clock.d.ts +12 -0
  323. package/dist/session/wall-clock.js +14 -0
  324. package/dist/setup/agent-configs.d.ts +96 -0
  325. package/dist/setup/agent-configs.js +333 -0
  326. package/dist/setup/agent-io.d.ts +9 -0
  327. package/dist/setup/agent-io.js +16 -0
  328. package/dist/setup/agent-writer.d.ts +51 -0
  329. package/dist/setup/agent-writer.js +115 -0
  330. package/dist/setup/approval-migration.d.ts +47 -0
  331. package/dist/setup/approval-migration.js +68 -0
  332. package/dist/setup/auto-approve.d.ts +85 -0
  333. package/dist/setup/auto-approve.js +150 -0
  334. package/dist/setup/bridge-port.d.ts +15 -0
  335. package/dist/setup/bridge-port.js +24 -0
  336. package/dist/setup/desktop-shape.d.ts +57 -0
  337. package/dist/setup/desktop-shape.js +63 -0
  338. package/dist/setup/dev-server-wait.d.ts +60 -0
  339. package/dist/setup/dev-server-wait.js +65 -0
  340. package/dist/setup/drive-agent.d.ts +71 -0
  341. package/dist/setup/drive-agent.js +171 -0
  342. package/dist/setup/drive-plan.d.ts +68 -0
  343. package/dist/setup/drive-plan.js +130 -0
  344. package/dist/setup/ensure-daemon.d.ts +29 -0
  345. package/dist/setup/ensure-daemon.js +58 -0
  346. package/dist/setup/init-runtime.d.ts +47 -0
  347. package/dist/setup/init-runtime.js +160 -0
  348. package/dist/setup/interrupt.d.ts +25 -0
  349. package/dist/setup/interrupt.js +40 -0
  350. package/dist/setup/license-key.d.ts +39 -0
  351. package/dist/setup/license-key.js +72 -0
  352. package/dist/setup/listeners.d.ts +37 -0
  353. package/dist/setup/listeners.js +85 -0
  354. package/dist/setup/node-effects.d.ts +60 -0
  355. package/dist/setup/node-effects.js +210 -0
  356. package/dist/setup/page-probe.d.ts +39 -0
  357. package/dist/setup/page-probe.js +49 -0
  358. package/dist/setup/relaunch.d.ts +36 -0
  359. package/dist/setup/relaunch.js +57 -0
  360. package/dist/setup/remaining-steps.d.ts +19 -0
  361. package/dist/setup/remaining-steps.js +31 -0
  362. package/dist/setup/run-setup.d.ts +99 -0
  363. package/dist/setup/run-setup.js +187 -0
  364. package/dist/setup/session-pick.d.ts +47 -0
  365. package/dist/setup/session-pick.js +51 -0
  366. package/dist/setup/setup-command.d.ts +45 -0
  367. package/dist/setup/setup-command.js +199 -0
  368. package/dist/setup/setup-options.d.ts +74 -0
  369. package/dist/setup/setup-options.js +67 -0
  370. package/dist/setup/transcripts.d.ts +16 -0
  371. package/dist/setup/transcripts.js +43 -0
  372. package/dist/status-payload.d.ts +14 -1
  373. package/dist/status-payload.js +23 -1
  374. package/dist/telemetry/automation-hint.d.ts +2 -1
  375. package/dist/telemetry/daemon-telemetry.d.ts +8 -1
  376. package/dist/telemetry/daemon-telemetry.js +52 -5
  377. package/dist/telemetry/error-class.js +1 -1
  378. package/dist/telemetry/feedback-context.d.ts +9 -1
  379. package/dist/telemetry/feedback-context.js +60 -29
  380. package/dist/telemetry/feedback-local.d.ts +15 -0
  381. package/dist/telemetry/feedback-local.js +56 -0
  382. package/dist/telemetry/feedback-outbox.d.ts +2 -1
  383. package/dist/telemetry/feedback.d.ts +11 -0
  384. package/dist/telemetry/feedback.js +19 -6
  385. package/dist/telemetry/init-telemetry.d.ts +2 -0
  386. package/dist/telemetry/init-telemetry.js +2 -0
  387. package/dist/telemetry/install-source.d.ts +14 -0
  388. package/dist/telemetry/install-source.js +30 -0
  389. package/dist/telemetry/license-activation.d.ts +7 -1
  390. package/dist/telemetry/license-activation.js +9 -5
  391. package/dist/telemetry/mcp-connection.js +7 -0
  392. package/dist/telemetry/project-profile.d.ts +12 -9
  393. package/dist/telemetry/project-profile.js +12 -7
  394. package/dist/telemetry/proxy-telemetry.d.ts +3 -0
  395. package/dist/telemetry/proxy-telemetry.js +21 -0
  396. package/dist/telemetry/run-telemetry.d.ts +0 -2
  397. package/dist/telemetry/run-telemetry.js +1 -1
  398. package/dist/telemetry/session-metrics.d.ts +12 -0
  399. package/dist/telemetry/session-metrics.js +35 -1
  400. package/dist/telemetry/telemetry.js +17 -2
  401. package/dist/telemetry/tool-refused.d.ts +3 -1
  402. package/dist/telemetry/tool-refused.js +34 -2
  403. package/dist/telemetry/verification-of.js +2 -2
  404. package/dist/tools/act-capsule.d.ts +10 -0
  405. package/dist/tools/act-capsule.js +8 -2
  406. package/dist/tools/act-danger.d.ts +2 -1
  407. package/dist/tools/act-danger.js +11 -3
  408. package/dist/tools/act-observation.d.ts +41 -0
  409. package/dist/tools/act-observation.js +36 -0
  410. package/dist/tools/act-preflight.d.ts +20 -0
  411. package/dist/tools/act-preflight.js +98 -0
  412. package/dist/tools/act-sequence-retry.d.ts +45 -0
  413. package/dist/tools/act-sequence-retry.js +58 -0
  414. package/dist/tools/act-sequence-tool.d.ts +13 -0
  415. package/dist/tools/act-sequence-tool.js +135 -0
  416. package/dist/tools/act-target.d.ts +14 -0
  417. package/dist/tools/act-target.js +47 -0
  418. package/dist/tools/act-tools.d.ts +21 -1
  419. package/dist/tools/act-tools.js +196 -204
  420. package/dist/tools/assert-source.d.ts +22 -0
  421. package/dist/tools/assert-source.js +53 -0
  422. package/dist/tools/assert-verdict.d.ts +20 -3
  423. package/dist/tools/assert-verdict.js +58 -20
  424. package/dist/tools/browser-tools.js +6 -22
  425. package/dist/tools/complete-snapshot.d.ts +48 -0
  426. package/dist/tools/complete-snapshot.js +75 -0
  427. package/dist/tools/coverage-tools.d.ts +10 -1
  428. package/dist/tools/coverage-tools.js +123 -69
  429. package/dist/tools/dynamic-tools.js +53 -13
  430. package/dist/tools/error-recovery.d.ts +25 -14
  431. package/dist/tools/error-recovery.js +78 -9
  432. package/dist/tools/feedback-tools.d.ts +1 -1
  433. package/dist/tools/feedback-tools.js +2 -2
  434. package/dist/tools/invoke-tool.js +121 -11
  435. package/dist/tools/lease-hint.d.ts +10 -0
  436. package/dist/tools/lease-hint.js +53 -4
  437. package/dist/tools/lease-tools.d.ts +35 -5
  438. package/dist/tools/lease-tools.js +191 -13
  439. package/dist/tools/merged-name-redirect.d.ts +13 -0
  440. package/dist/tools/merged-name-redirect.js +22 -0
  441. package/dist/tools/navigate-arrival.d.ts +0 -2
  442. package/dist/tools/navigate-arrival.js +1 -1
  443. package/dist/tools/numeric-bounds.d.ts +100 -0
  444. package/dist/tools/numeric-bounds.js +125 -0
  445. package/dist/tools/observe-tools.js +109 -65
  446. package/dist/tools/read-tools.js +31 -8
  447. package/dist/tools/real-input-attempt.d.ts +32 -0
  448. package/dist/tools/real-input-attempt.js +212 -2
  449. package/dist/tools/reconcile-tools.js +22 -8
  450. package/dist/tools/resolve-target.d.ts +0 -7
  451. package/dist/tools/sdk-marker-probe.d.ts +29 -0
  452. package/dist/tools/sdk-marker-probe.js +57 -0
  453. package/dist/tools/snapshot-delta.d.ts +1 -1
  454. package/dist/tools/tool-kit.d.ts +24 -0
  455. package/dist/tools/tool-kit.js +21 -0
  456. package/dist/tools/tool-names.d.ts +5 -0
  457. package/dist/tools/tool-names.js +5 -0
  458. package/dist/tools/tool-surface.d.ts +85 -6
  459. package/dist/tools/tool-surface.js +122 -2
  460. package/dist/tools/tools-helpers.d.ts +19 -0
  461. package/dist/tools/tools-helpers.js +46 -0
  462. package/dist/tools/tools.d.ts +2 -0
  463. package/dist/tools/tools.js +78 -12
  464. package/dist/tools/unadvertised-help.js +4 -4
  465. package/dist/tools/verify-next-baton.d.ts +53 -0
  466. package/dist/tools/verify-next-baton.js +52 -0
  467. package/dist/update/reticle-deps.d.ts +9 -0
  468. package/dist/update/reticle-deps.js +27 -0
  469. package/dist/update/sdk-sync.d.ts +1 -2
  470. package/dist/update/sdk-sync.js +1 -21
  471. package/dist/update/update-nudge.d.ts +25 -10
  472. package/dist/update/update-nudge.js +32 -3
  473. package/dist/update/updater.d.ts +1 -1
  474. package/dist/version/peer-announce.js +4 -2
  475. package/dist/version/sdk-fix.d.ts +47 -0
  476. package/dist/version/sdk-fix.js +127 -0
  477. package/dist/version/version-nudge.d.ts +14 -0
  478. package/dist/version/version-nudge.js +21 -0
  479. package/dist/version/version-skew.d.ts +38 -3
  480. package/dist/version/version-skew.js +83 -7
  481. package/dist/visual/visual-store.d.ts +6 -6
  482. package/dist/visual/visual-store.js +18 -16
  483. package/dist/visual/visual-tools.js +57 -12
  484. package/docs/README.md +2 -1
  485. package/docs/cli/cloud.mdx +1 -1
  486. package/docs/cli/doctor.mdx +2 -0
  487. package/docs/cli/serve.mdx +4 -2
  488. package/docs/cli/verify.mdx +4 -5
  489. package/docs/cli.mdx +7 -3
  490. package/docs/desktop.mdx +1 -1
  491. package/docs/docs.json +2 -2
  492. package/docs/gates.md +1 -1
  493. package/docs/getting-started.md +19 -3
  494. package/docs/index.mdx +9 -6
  495. package/docs/install-agentic.mdx +38 -12
  496. package/docs/install-manual.mdx +1 -1
  497. package/docs/packages/browser.mdx +2 -2
  498. package/docs/packages/server.mdx +1 -1
  499. package/docs/packages.mdx +8 -6
  500. package/docs/platform-integration.md +17 -0
  501. package/docs/predicates.mdx +8 -0
  502. package/docs/reticle-manual.md +106 -0
  503. package/docs/skill-file.mdx +3 -3
  504. package/docs/telemetry-contract.md +108 -4
  505. package/docs/tools-act-sequence.mdx +16 -0
  506. package/docs/tools-tools-and-run.mdx +2 -4
  507. package/docs/troubleshooting.mdx +9 -0
  508. package/docs/usage.md +4 -3
  509. package/package.json +4 -3
  510. package/dist/init/cursor.d.ts +0 -24
  511. package/dist/init/cursor.js +0 -80
  512. package/dist/session/session-readiness.d.ts +0 -34
  513. package/dist/session/session-readiness.js +0 -36
@@ -70,6 +70,45 @@ export const TOOL_SURFACE = {
70
70
  * supplies the evidence the surface would otherwise have to go and find.
71
71
  */
72
72
  VERIFY: 'verify',
73
+ /**
74
+ * EXPERIMENTAL, opt-in, and UNDER MEASUREMENT. Not a recommendation, and not on a path to becoming
75
+ * the default until it has a number of its own.
76
+ *
77
+ * It exists because of the finding recorded on VERIFY above, read forwards instead of backwards.
78
+ * That surface cut the bill 37% and TRIPLED false alarms, and the five new false alarms were not
79
+ * scattered: every one of them was a defect whose evidence lives in `reticle_state`,
80
+ * `reticle_network` or `reticle_observe`. So the token saving and the accuracy loss came from two
81
+ * different cuts, and only one of them has to be paid for. `lean` keeps every observation tool and
82
+ * cuts the rest.
83
+ *
84
+ * What stays, and why each one is not a candidate for removal:
85
+ * SNAPSHOT / QUERY look. Without them the agent cannot name an element it did not already know.
86
+ * STATE / NETWORK / CONSOLE / OBSERVE the four evidence tools. Dropping these is the MEASURED
87
+ * cause of the tripled false-alarm rate. They are the point of the profile.
88
+ * ACT_AND_WAIT the only tool that acts AND returns a verdict. Omitting `until` makes it
89
+ * act-then-settle, which is what `reticle_act` does, so `act` is redundant here.
90
+ * ASSERT the only way to get a verdict WITHOUT acting. `act_and_wait` requires an
91
+ * `action`, so this is a capability it genuinely cannot express, not a synonym.
92
+ *
93
+ * What goes, and what it costs (one `reticle_run` hop each — `unadvertisedToolHelp` hands the agent
94
+ * the exact call, so a dropped name never comes back as "not found"):
95
+ * ACT subsumed: `act_and_wait` with `until` omitted is act-then-settle.
96
+ * WAIT_FOR subsumed: `act_and_wait { until }` takes the same PredicateSchema.
97
+ * ACT_SEQUENCE batching is a cost optimisation on top of a surface built to be cheap.
98
+ * NAVIGATE once per run, not once per turn — the wrong thing to pay for every turn.
99
+ * SESSIONS the CLI answers this (`reticle status`) without spending any turn budget.
100
+ * INSPECT fix-side, not verdict-side: it is called once a bug is FOUND, so its hop is
101
+ * paid once per finding rather than once per turn. Nothing else maps a node to
102
+ * a source file, which is why it is a hop and not a deletion.
103
+ * SESSION the lease block and the pause hint name it in prose, which is what made it
104
+ * load-bearing on the default surface. Under a trimmed surface the
105
+ * unadvertised-tool help turns that into a working `reticle_run` call.
106
+ * FEEDBACK the one drop with a KNOWN CEILING: an unadvertised feedback channel collects
107
+ * little to nothing, so a long-lived profile must not ship without it. Acceptable
108
+ * only because this profile is opt-in and short-lived by construction; if it
109
+ * ever stops being an experiment, feedback comes back first.
110
+ */
111
+ LEAN: 'lean',
73
112
  };
74
113
  /**
75
114
  * The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
@@ -79,7 +118,7 @@ export const TOOL_SURFACE = {
79
118
  */
80
119
  export const ADVERTISE_ALL_ENV = 'RETICLE_ADVERTISE_ALL_TOOLS';
81
120
  /** Opt into the smallest verdict-capable surface. Read by the DAEMON at startup, like the others. */
82
- export const VERIFY_SURFACE_ENV = 'RETICLE_VERIFY_SURFACE';
121
+ const VERIFY_SURFACE_ENV = 'RETICLE_VERIFY_SURFACE';
83
122
  /**
84
123
  * The retired setting, still read so nobody's shell profile breaks.
85
124
  *
@@ -185,6 +224,17 @@ export const CORE_TOOL_NAMES = new Set([
185
224
  * 48 by itself can push a user's other servers out or be dropped wholesale. The budget is a count,
186
225
  * so no amount of trimming parameter prose buys anything back — only advertising fewer names does.
187
226
  *
227
+ * That is true of the COUNT cap and false of everything else, which is worth separating here before
228
+ * somebody reads it as "prose is free". Measured against two competitor MCP servers on the same
229
+ * agent loop: this server advertises the FEWEST tools of the three and ships the HEAVIEST schema
230
+ * block, and 83% of that weight is parameter descriptions, not tool descriptions. The block is
231
+ * re-sent every turn, so it is multiplied by turn count before one byte of evidence is counted, and
232
+ * it was most of the gap in that run.
233
+ *
234
+ * Which does NOT license trimming by eye. Those descriptions are what make a tool get called
235
+ * correctly, and one malformed call costs a whole extra turn — more than the bytes saved. The
236
+ * outcome to measure is turn count and error rate, not size.
237
+ *
188
238
  * Everything omitted stays in the registry, stays catalogued by `reticle_tools`, and stays callable
189
239
  * by name through `reticle_run { tool, args }`. The cost is one discovery hop on the cold tail, which
190
240
  * is the same trade the default surface has always made, applied one level further out.
@@ -206,6 +256,13 @@ export const EXTENDED_TOOL_NAMES = new Set([
206
256
  ReticleTool.CAPABILITIES,
207
257
  ReticleTool.FLOW_SAVE,
208
258
  ReticleTool.FLOW_REPLAY,
259
+ // New and unproven, so it does not take a default-surface slot under the cap. Same terms the
260
+ // capabilities demotion set: reachable in one reticle_run hop by any agent that wants it.
261
+ ReticleTool.INTENT,
262
+ // Same terms again, plus one argument specific to it: its caller is BY CONSTRUCTION an agent that
263
+ // just lost its context and is re-reading the tool list, so the discovery hop it costs is a call
264
+ // that caller was already going to make. See context-tools.ts for the full argument.
265
+ ReticleTool.CONTEXT,
209
266
  ReticleTool.RECORD,
210
267
  ReticleTool.SCREENSHOT,
211
268
  ReticleTool.VISUAL_DIFF,
@@ -220,7 +277,53 @@ export const EXTENDED_TOOL_NAMES = new Set([
220
277
  * everything else. `act_and_wait` can resolve its own target, so no query tool is needed to name an
221
278
  * element — that round trip was half the token cost of a verification.
222
279
  */
223
- export const VERIFY_TOOL_NAMES = new Set([ReticleTool.ACT_AND_WAIT]);
280
+ const VERIFY_TOOL_NAMES = new Set([ReticleTool.ACT_AND_WAIT]);
281
+ /**
282
+ * The lean surface: look, observe, act-with-a-verdict, assert. Pinned by lean-surface.test.ts,
283
+ * because an experiment whose independent variable drifts mid-flight measures nothing. Every
284
+ * inclusion and every exclusion is argued at TOOL_SURFACE.LEAN.
285
+ *
286
+ * ## MEASURED: it is cheaper and less correct. Do not promote it to the default.
287
+ *
288
+ * Run as its own arm of the fix-and-verify benchmark — same five bugs, same model, same budget, the
289
+ * full surface as its control:
290
+ *
291
+ * | | full surface | lean |
292
+ * |---|---|---|
293
+ * | bugs fixed | **5/5** | **3/5** |
294
+ * | FALSE GREENS | **0** | **1** |
295
+ *
296
+ * The false green is the finding, and it is the first this benchmark has ever produced. On
297
+ * `broken-form-validation` the lean agent finished in SIX turns and 62k tokens — the cheapest cell
298
+ * of the whole run, a fifth of what the full surface spent — edited the file, took one snapshot,
299
+ * and ended with a hypothetical walkthrough: "Enter spaces + valid name -> spaces are trimmed,
300
+ * valid part is used. VERDICT: FIXED". The submit button was still enabled for a whitespace-only
301
+ * service. It reasoned about what its own code would now do instead of driving it, which is exactly
302
+ * the failure this product exists to catch, produced by our own surface.
303
+ *
304
+ * The other loss has the same root from the other side. On `cross-component-regression` the agent
305
+ * called `reticle_tools` three times and `reticle_run` eight, saying "since Reticle isn't
306
+ * connecting, let me see what reticle_tools offers" — it spent the run hunting for capabilities
307
+ * this surface does not advertise instead of using them, and never fixed the bug.
308
+ *
309
+ * That is the same result the `verify` surface already recorded — dropping the observation tools
310
+ * TRIPLED false alarms — arriving from the other direction: strip the surface and the agent stops
311
+ * verifying, then claims anyway. The known ceiling written here was that `reticle_feedback` goes
312
+ * uncollected. This is a bigger one and it was not predicted.
313
+ *
314
+ * It stays opt-in and it stays measured. The one thing it genuinely bought — the ceiling-bound cell
315
+ * halved, 30 turns to 14 — is not worth a verdict that lies, because the product is the verdict.
316
+ */
317
+ export const LEAN_TOOL_NAMES = new Set([
318
+ ReticleTool.SNAPSHOT,
319
+ ReticleTool.QUERY,
320
+ ReticleTool.ACT_AND_WAIT,
321
+ ReticleTool.ASSERT,
322
+ ReticleTool.OBSERVE,
323
+ ReticleTool.NETWORK,
324
+ ReticleTool.CONSOLE,
325
+ ReticleTool.STATE,
326
+ ]);
224
327
  /** Is the truthy form of a boolean env var set? `1`, `true`, `yes` — anything else is off. */
225
328
  function envFlagOn(raw) {
226
329
  if (raw === undefined)
@@ -235,6 +338,8 @@ function envFlagOn(raw) {
235
338
  * switch decides, and the retired setting is honoured last so an old shell profile still works.
236
339
  */
237
340
  export function resolveToolSurface(explicit) {
341
+ if (explicit === TOOL_SURFACE.LEAN)
342
+ return TOOL_SURFACE.LEAN;
238
343
  if (explicit === TOOL_SURFACE.VERIFY)
239
344
  return TOOL_SURFACE.VERIFY;
240
345
  if (explicit === TOOL_SURFACE.ALL)
@@ -244,6 +349,11 @@ export function resolveToolSurface(explicit) {
244
349
  const retiredExplicit = explicit === undefined ? undefined : RETIRED_PROFILE_VALUES[explicit];
245
350
  if (retiredExplicit !== undefined)
246
351
  return retiredExplicit;
352
+ // The one LIVE value of the otherwise-retired setting. It rides there rather than on a switch of
353
+ // its own because the experiment is an A/B between two surfaces, and a boolean cannot name an arm.
354
+ if (TOOL_SURFACE.LEAN === process.env[TOOL_PROFILE_ENV]?.trim().toLowerCase()) {
355
+ return TOOL_SURFACE.LEAN;
356
+ }
247
357
  if (envFlagOn(process.env[VERIFY_SURFACE_ENV]))
248
358
  return TOOL_SURFACE.VERIFY;
249
359
  if (envFlagOn(process.env[ADVERTISE_ALL_ENV]))
@@ -262,6 +372,14 @@ export function resolveToolSurface(explicit) {
262
372
  */
263
373
  export function describeToolSurface(active, requested) {
264
374
  const retired = requested ?? process.env[TOOL_PROFILE_ENV];
375
+ // `lean` is the one value of this setting that is NOT retired. Reporting it as retired would tell
376
+ // an agent its arm did not take, which on an A/B is worse than saying nothing.
377
+ if (TOOL_SURFACE.LEAN === active) {
378
+ return {
379
+ active,
380
+ source: `${TOOL_PROFILE_ENV}=${TOOL_SURFACE.LEAN} — an EXPERIMENTAL surface under measurement; unadvertised tools stay callable via ${ReticleTool.RUN}`,
381
+ };
382
+ }
265
383
  if (retired !== undefined && retired in RETIRED_PROFILE_VALUES) {
266
384
  return {
267
385
  active,
@@ -293,6 +411,8 @@ export function filterTools(tools, surface) {
293
411
  // interesting thing about the `core` PROFILE, whose only distinction was a second name for this.
294
412
  if (surface === TOOL_SURFACE.VERIFY)
295
413
  return tools.filter((t) => VERIFY_TOOL_NAMES.has(t.name));
414
+ if (surface === TOOL_SURFACE.LEAN)
415
+ return tools.filter((t) => LEAN_TOOL_NAMES.has(t.name));
296
416
  if (surface === TOOL_SURFACE.DEFAULT)
297
417
  return tools.filter((t) => CORE_TOOL_NAMES.has(t.name));
298
418
  // `all` is the extended surface, not the whole registry — the cap is a hard budget shared with
@@ -8,6 +8,25 @@ export declare function parseInteractive(tree: string): InteractiveItem[];
8
8
  export declare function asString(value: unknown): string | undefined;
9
9
  export declare function asNumber(value: unknown): number | undefined;
10
10
  export declare function asRecord(value: unknown): Record<string, unknown>;
11
+ /**
12
+ * The session this call is aimed at: a top-level `sessionId`, or the same key on sequence steps.
13
+ *
14
+ * `reticle_act_sequence` describes each step as equivalent to one `reticle_act`, so an agent that
15
+ * learned the escape hatch on the single-action tool puts `sessionId` on the step. Reading only the
16
+ * top-level key then auto-selects a different tab, the step refs miss, and the refusal reads as a
17
+ * stale ref — a confident diagnosis of the wrong thing. Top-level still wins when both are given.
18
+ *
19
+ * Mixed step ids refuse rather than pick: two named tabs is a guess we will not make.
20
+ */
21
+ export declare function sessionIdFromArgs(args: Record<string, unknown>): string | undefined;
22
+ /**
23
+ * The ref this call is about to spend: a top-level `ref`, or the first sequence step's.
24
+ *
25
+ * Wrong-tab refusal keys off this. A sequence that only carries refs inside `steps` used to look
26
+ * like a call with no ref, so auto-selection could pick a different tab and the miss was blamed
27
+ * on the DOM.
28
+ */
29
+ export declare function spentRefFromArgs(args: Record<string, unknown>): string | undefined;
11
30
  /**
12
31
  * A `{ file, line }` source location off an untrusted result payload, or undefined.
13
32
  *
@@ -19,6 +19,52 @@ export function asNumber(value) {
19
19
  export function asRecord(value) {
20
20
  return 'object' === typeof value && value !== null ? value : {};
21
21
  }
22
+ /**
23
+ * The session this call is aimed at: a top-level `sessionId`, or the same key on sequence steps.
24
+ *
25
+ * `reticle_act_sequence` describes each step as equivalent to one `reticle_act`, so an agent that
26
+ * learned the escape hatch on the single-action tool puts `sessionId` on the step. Reading only the
27
+ * top-level key then auto-selects a different tab, the step refs miss, and the refusal reads as a
28
+ * stale ref — a confident diagnosis of the wrong thing. Top-level still wins when both are given.
29
+ *
30
+ * Mixed step ids refuse rather than pick: two named tabs is a guess we will not make.
31
+ */
32
+ export function sessionIdFromArgs(args) {
33
+ const top = asString(args['sessionId']);
34
+ if (top !== undefined)
35
+ return top;
36
+ const steps = args['steps'];
37
+ if (!Array.isArray(steps))
38
+ return undefined;
39
+ let found;
40
+ for (const raw of steps) {
41
+ const id = asString(asRecord(raw)['sessionId']);
42
+ if (id === undefined)
43
+ continue;
44
+ if (found !== undefined && found !== id) {
45
+ throw new Error(`reticle_act_sequence steps name different sessionIds ('${found}' and '${id}'). ` +
46
+ 'Pass one sessionId at the top level to target a tab. Nothing was acted on.');
47
+ }
48
+ found = id;
49
+ }
50
+ return found;
51
+ }
52
+ /**
53
+ * The ref this call is about to spend: a top-level `ref`, or the first sequence step's.
54
+ *
55
+ * Wrong-tab refusal keys off this. A sequence that only carries refs inside `steps` used to look
56
+ * like a call with no ref, so auto-selection could pick a different tab and the miss was blamed
57
+ * on the DOM.
58
+ */
59
+ export function spentRefFromArgs(args) {
60
+ const top = asString(args['ref']);
61
+ if (top !== undefined)
62
+ return top;
63
+ const steps = args['steps'];
64
+ if (!Array.isArray(steps) || 0 === steps.length)
65
+ return undefined;
66
+ return asString(asRecord(steps[0])['ref']);
67
+ }
22
68
  /**
23
69
  * A `{ file, line }` source location off an untrusted result payload, or undefined.
24
70
  *
@@ -1,6 +1,8 @@
1
1
  import { type ToolDef } from './tool-kit.js';
2
2
  import { type MergePlan } from './merge-tools.js';
3
3
  export type { ToolDef, ToolDeps } from './tool-kit.js';
4
+ /** Every handler, including tools retired from the advertised MCP surface. */
5
+ export declare const RAW_TOOLS: ToolDef[];
4
6
  /**
5
7
  * surface consolidation. Tool defs are re-sent EVERY turn, so the advertised count is a per-turn
6
8
  * tax multiplied by loop length. Sibling families collapse into one action-dispatched tool; the member
@@ -3,7 +3,8 @@ import { NoSessionAction, QueryBy, ReticleCommand, SnapshotMode } from '@reticle
3
3
  import { ReticleTool } from './tool-names.js';
4
4
  import { withSizeCost } from '../session/output-budget.js';
5
5
  import { applySnapshotDelta, SnapshotCache } from './snapshot-delta.js';
6
- import { asString, asNumber } from './tools-helpers.js';
6
+ import { asRecord, asString, asNumber } from './tools-helpers.js';
7
+ import { countSchema } from './numeric-bounds.js';
7
8
  import { normalizeQueryArgs } from './query-shape.js';
8
9
  import { paginateQueryResult } from './query-paginate.js';
9
10
  /**
@@ -21,11 +22,14 @@ import { CONTRACT_TOOLS } from './contract-tools.js';
21
22
  import { DOMAIN_TOOLS } from '../domain/domain-tools.js';
22
23
  import { BROWSER_TOOLS } from './browser-tools.js';
23
24
  import { FLOW_TOOLS } from '../flows/flow-tools.js';
25
+ import { INTENT_TOOLS } from '../intent/intent-tools.js';
26
+ import { CONTEXT_TOOLS } from '../runs/context-tools.js';
24
27
  import { PROJECT_TOOLS } from '../project/project-tools.js';
28
+ import { MEMORY_TOOLS } from '../memory/memory-tools.js';
25
29
  import { RUN_TOOLS } from '../runs/run-tools.js';
26
30
  import { VISUAL_TOOLS } from '../visual/visual-tools.js';
27
31
  import { AFFECTED_TOOLS } from '../flows/affected-tools.js';
28
- import { COVERAGE_TOOLS } from './coverage-tools.js';
32
+ import { buildCoverageTools } from './coverage-tools.js';
29
33
  import { VERIFY_CHANGE_TOOLS } from '../flows/verify-change-tools.js';
30
34
  import { CRAWL_TOOLS } from '../crawl/crawl-tools.js';
31
35
  import { SCROLL_TOOLS } from '../input/scroll-tools.js';
@@ -44,10 +48,11 @@ import { LEASE_TOOLS } from './lease-tools.js';
44
48
  import { FEEDBACK_TOOLS } from './feedback-tools.js';
45
49
  /** Per-server last-snapshot cache backing reticle_snapshot's diff:true delta mode (route-invalidated). */
46
50
  const SNAPSHOT_CACHE = new SnapshotCache();
47
- const RAW_TOOLS = [
51
+ /** Every handler, including tools retired from the advertised MCP surface. */
52
+ export const RAW_TOOLS = [
48
53
  {
49
54
  name: ReticleTool.SESSIONS,
50
- description: 'List connected browser sessions (tab url/title, sessionId, last-seen, health: hidden/focused/throttled, and `realInputAvailable` — true when native CDP/launched real input is driving this tab), plus a `recommendation` pointing to `reticle drive` when a tab is hidden/throttled and may be un-scriptable from here.',
55
+ description: 'List connected browser sessions (tab url/title, sessionId, last-seen, health: hidden/focused/throttled, and `realInputAvailable` — true when native CDP/launched real input is driving this tab), plus a `recommendation` naming the in-protocol escape hatch (`reticle_run { tool: "reticle_lease" }`, with `reticle drive` as the human-side equivalent) when a tab is hidden/throttled and may be un-scriptable from here.',
51
56
  inputSchema: {},
52
57
  outputSchema: {
53
58
  sessions: z
@@ -61,6 +66,10 @@ const RAW_TOOLS = [
61
66
  title: z.string().optional(),
62
67
  adapters: z.array(z.string()),
63
68
  hasCapabilities: z.boolean(),
69
+ runtime: z
70
+ .string()
71
+ .optional()
72
+ .describe("Which shell answered: web, electron or tauri. Absent on an SDK too old to report one — never defaulted, because a browser tab and a desktop window on the same url are otherwise indistinguishable and only one of them has the app's IPC."),
64
73
  versionSkew: z
65
74
  .string()
66
75
  .optional()
@@ -73,9 +82,26 @@ const RAW_TOOLS = [
73
82
  leased: z.boolean().optional(),
74
83
  stale: z.boolean().optional(),
75
84
  cleanup_suggestion: z.string().optional(),
85
+ unresponsive: z
86
+ .literal(true)
87
+ .optional()
88
+ .describe('Present only when this tab is attached but has stopped answering commands: every call against it will time out. The other health fields still look fine, which is what makes this state invisible without the flag.'),
89
+ unresponsive_suggestion: z.string().optional(),
76
90
  pendingMarks: z.number().optional(),
77
91
  review_suggestion: z.string().optional(),
78
92
  recommendation: z.string().optional(),
93
+ // Attached by SessionManager.list() (#117): whether this tab ever dropped and came back,
94
+ // how often, and how long the last drop lasted. Undeclared here, a validating client
95
+ // stripped the outage history while the row still looked complete — a verdict over a
96
+ // window with a four-second blind gap read as trustworthy.
97
+ attachment: z
98
+ .object({
99
+ connectedSinceMs: z.number(),
100
+ outages: z.number(),
101
+ lastOutage: z.object({ startedMs: z.number(), durationMs: z.number() }).optional(),
102
+ })
103
+ .optional()
104
+ .describe('Present only when this tab has dropped and reconnected at least once: how long it has been attached in total, how many outages occurred, and when the last one started and how long it lasted. A verdict over this window spans a gap where nothing was observed.'),
79
105
  }))
80
106
  .describe('Connected browser sessions with health state. `projectId` groups sessions by app (stable across port changes); `leased` marks a pool-managed headless context vs a human tab.'),
81
107
  why: z
@@ -90,7 +116,7 @@ const RAW_TOOLS = [
90
116
  reason: z.string(),
91
117
  })
92
118
  .optional()
93
- .describe("Present ONLY when `sessions` is empty: the same answer as `why`, executable. `command` is the LITERAL command to run, sourced from this project's own package.json scripts and lockfile — it is absent, never guessed, when the project declares no dev script. `action` is one of start_dev_server | run_init | open_app | reopen_app."),
119
+ .describe("Present ONLY when `sessions` is empty: the same answer as `why`, executable. `command` is the LITERAL command to run, sourced from this project's own package.json scripts and lockfile — it is absent, never guessed, when the project declares no dev script. `action` is one of daemon_split | start_dev_server | run_init | open_app | reopen_app. `daemon_split` outranks the rest and means the app IS running and instrumented, on a DIFFERENT daemon than the one you are attached to — do not start or re-init anything, read `reason`."),
94
120
  },
95
121
  handler: async (deps) => {
96
122
  const provider = deps.realInput;
@@ -207,18 +233,18 @@ const RAW_TOOLS = [
207
233
  return commandOrThrow(deps, resolved.id, ReticleCommand.SNAPSHOT, {
208
234
  scope: args['scope'],
209
235
  mode,
210
- }).then((raw) => withSizeCost(applySnapshotDelta(raw, {
236
+ }).then((raw) => withSizeCost(noteEmptyLeanTree(applySnapshotDelta(raw, {
211
237
  sessionId: resolved.id,
212
238
  scope: asString(args['scope']) ?? '',
213
239
  mode,
214
240
  diff: true === args['diff'],
215
- }, SNAPSHOT_CACHE)));
241
+ }, SNAPSHOT_CACHE), mode)));
216
242
  },
217
243
  },
218
244
  {
219
245
  name: ReticleTool.QUERY,
220
246
  example: { by: 'testid', value: 'todo-list' },
221
- description: `Find elements by Testing-Library semantics, INCLUDING open shadow roots — \`count_only:true\` gives just the count (~30x smaller); \`limit\` caps descriptors. Pass \`by\` (${QUERY_BY_LIST}) and \`value\` (the query string). Returns matching refs + descriptors + visibility. Pass \`attrs:["href"]\` to project attributes (link/image URLs) onto each match. Pass \`limit\` to cap descriptors (broad role queries can be large) or \`count_only:true\` for just the match count — both cut tokens. On zero matches, also returns hint:{ route, presentRegions[], knownEmptyState } so you can distinguish an empty state from a missing element WITHOUT taking a snapshot.`,
247
+ description: `Find elements by Testing-Library semantics, INCLUDING open shadow roots — \`count_only:true\` gives just the count (~30x smaller); \`limit\` caps descriptors. Pass \`by\` (${QUERY_BY_LIST}) and \`value\` (the query string). Returns matching refs + descriptors + visibility. Pass \`attrs:["href"]\` to project attributes (link/image URLs) onto each match. Pass \`limit\` to cap descriptors (broad role queries can be large) or \`count_only:true\` for just the match count — both cut tokens. On zero matches, also returns hint:{ route, presentRegions[], knownEmptyState } so you can distinguish an empty state from a missing element WITHOUT taking a snapshot. ASKING SEVERAL QUESTIONS ABOUT THE PAGE? One reticle_snapshot answers them all at once — a run of queries costs a round trip each and returns what the snapshot already held.`,
222
248
  inputSchema: {
223
249
  // Constrained to the enum, NOT z.string(). A free string let `by:'css'` through to the
224
250
  // browser's `default: return []`, so an unsupported strategy answered "0 matches" — which
@@ -245,9 +271,7 @@ const RAW_TOOLS = [
245
271
  .array(z.string())
246
272
  .optional()
247
273
  .describe("Attribute names to return per match, e.g. ['href'] to inventory links or ['src'] for images. Absent attributes are omitted; credential-bearing names are redacted."),
248
- limit: z
249
- .number()
250
- .nonnegative()
274
+ limit: countSchema
251
275
  .optional()
252
276
  .describe('Cap the returned descriptors to the first N (cuts tokens on broad queries). If more matched, the result carries total + truncated:true so the trim is never silent — narrow with name/scope.'),
253
277
  count_only: z
@@ -322,6 +346,15 @@ const RAW_TOOLS = [
322
346
  .describe('Structural clusters on the page — what IS here, to diagnose the miss.'),
323
347
  presentTestids: z.array(z.string()).optional(),
324
348
  knownEmptyState: z.boolean(),
349
+ splitText: z
350
+ .object({
351
+ ref: z.string().optional(),
352
+ role: z.string().optional(),
353
+ name: z.string().optional(),
354
+ })
355
+ .passthrough()
356
+ .optional()
357
+ .describe("Present when a TEXT search missed but the string IS on the page, split across this container's children. Retry as { scope: <ref>, self: true } — no text query can match a string no single element owns."),
325
358
  })
326
359
  .optional()
327
360
  .describe('Present only on zero matches — tells you what IS on the page so you can diagnose the miss.'),
@@ -446,11 +479,14 @@ const RAW_TOOLS = [
446
479
  // reticle_capabilities (live | fromDisk) + reticle_contract_save. See contract-tools.ts.
447
480
  ...RECONCILE_TOOLS,
448
481
  ...CONTRACT_TOOLS,
482
+ ...INTENT_TOOLS,
483
+ ...CONTEXT_TOOLS,
449
484
  ...DOMAIN_TOOLS,
450
485
  // reticle_flow_save / reticle_flow_list / reticle_flow_load. See flow-tools.ts.
451
486
  ...FLOW_TOOLS,
452
487
  // reticle_project (read history + diff-vs-last) / reticle_run_record. See project-tools.ts.
453
488
  ...PROJECT_TOOLS,
489
+ ...MEMORY_TOOLS,
454
490
  // reticle_run_export — export the verification-run verdict artifact (.reticle/runs/). See run-tools.ts.
455
491
  ...RUN_TOOLS,
456
492
  // reticle_screenshot / reticle_visual_diff — opt-in, CDP-driven. See visual-tools.ts.
@@ -469,7 +505,9 @@ const RAW_TOOLS = [
469
505
  // reachable through reticle_run. See affected-tools.ts.
470
506
  ...AFFECTED_TOOLS,
471
507
  // reticle_coverage — which controls were driven vs never touched. Unadvertised; via reticle_run.
472
- ...COVERAGE_TOOLS,
508
+ // The table is passed as a thunk so the coverage tool can report which of it was called without
509
+ // importing it back — see buildCoverageTools. Called from the handler, long after TOOLS exists.
510
+ ...buildCoverageTools(() => TOOLS.map((t) => t.name)),
473
511
  // reticle_verify_change — "did my change break anything" in one call. See verify-change-tools.ts.
474
512
  ...VERIFY_CHANGE_TOOLS,
475
513
  // Live-control: reticle_end_session / reticle_resume / reticle_messages. See live-control-tools.ts.
@@ -561,4 +599,32 @@ export const RETIRED_FROM_SURFACE = [
561
599
  ReticleTool.REFRESH, // absorbed into reticle_navigate { reload: true }
562
600
  ReticleTool.WAIT_READY, // server-internal: the first live call already blocks for the session
563
601
  ];
602
+ /**
603
+ * An empty `interactive` tree is a claim, and it is usually the wrong one.
604
+ *
605
+ * `mode:"interactive"` filters on ARIA role, and a large share of production UI carries none. On
606
+ * MarkText — a shipped Electron editor — it returns NOTHING while `mode:"full"` returns 47 nodes,
607
+ * because its whole block picker is `<div>`s with no role, no testid and no pointer cursor. This
608
+ * tool's own description recommends the lean mode, so an agent takes the cheap look, is handed `""`,
609
+ * and reads it as an empty page. It is the one shape of answer this product must never invent.
610
+ *
611
+ * The browser counts what leanness passed over, so the tool can say which of the two it is.
612
+ */
613
+ function noteEmptyLeanTree(result, mode) {
614
+ if (SnapshotMode.INTERACTIVE !== mode)
615
+ return result;
616
+ const row = asRecord(result);
617
+ if (0 !== asNumber(row['nodes']))
618
+ return result;
619
+ const skipped = asNumber(row['leanSkipped']) ?? 0;
620
+ if (0 === skipped)
621
+ return result;
622
+ return {
623
+ ...row,
624
+ note: `no element on this page carries an interactive ARIA role, so this mode found nothing — ` +
625
+ `${String(skipped)} element(s) were passed over for leanness and this is NOT an empty page. ` +
626
+ `Take reticle_snapshot { mode: "full" } instead; the controls here are addressed by text or ` +
627
+ `by testid rather than by role.`,
628
+ };
629
+ }
564
630
  export const TOOLS = applyMerges(RAW_TOOLS, MERGE_PLANS, RETIRED_FROM_SURFACE);
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * What to say when an agent calls a real Reticle tool that this profile does not advertise.
3
3
  *
4
- * The default surface advertises 18 of 48 tools, and the extended one 30. That is deliberate — every
5
- * advertised tool's schema is re-sent on every turn, and editors budget MCP tools as a COUNT shared
6
- * across every connected server — and everything omitted stays fully callable through `reticle_run`,
7
- * which `surface-reachability.test.ts` guards.
4
+ * The default surface is the verify loop plus the two meta-tools; the extended one is larger but
5
+ * still capped. Counts live in `surface-sizes.test.ts` — restating them here is how they drift.
6
+ * Everything omitted stays fully callable through `reticle_run`, which `surface-reachability.test.ts`
7
+ * guards.
8
8
  *
9
9
  * The gap was in the ERROR. The MCP SDK answers `Tool <name> not found`, which is indistinguishable
10
10
  * from "this tool does not exist", so an agent that trusts it stops trying. Reported from a real
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The verdict nudge, as a call the agent can make rather than a sentence it has to translate.
3
+ *
4
+ * `verify_next` already fires when an agent has driven the page several times and asked for no
5
+ * verdict, which is the commonest shape of a wasted session: almost every verdict-less session in
6
+ * the field never called a verdict-producing tool once. What it carried was prose. Prose has to be
7
+ * turned back into a call, and the translation is exactly where the agent was already going wrong —
8
+ * `until` omitted, arguments flat instead of nested under `args`, a predicate written as a bare
9
+ * array.
10
+ *
11
+ * So it carries the call. `ref` and `action` come from the act that actually dispatched, so the
12
+ * suggestion is about the element the agent really touched rather than a worked example from a
13
+ * document. `until` is deliberately left as a placeholder the agent must replace: naming the
14
+ * consequence is the one part nothing but the agent can know, and filling it in with a guess would
15
+ * be Reticle inventing the assertion — the failure `no-fault` exists to prevent.
16
+ *
17
+ * Emitted only when there is a real call to suggest. A baton with nothing behind it is the router
18
+ * failure in miniature: an agent that follows a fabricated next step follows it confidently.
19
+ */
20
+ /**
21
+ * Set to `1` to withhold the baton from tool results — the control arm of its A/B, and nothing else.
22
+ *
23
+ * A measurement flag, not a product setting: it is read at one call site, documented here, and named
24
+ * loudly enough that nobody sets it by accident. It exists because this feature has shipped, been
25
+ * declared the largest lever on whether a session verifies at all, and never been measured — and a
26
+ * control arm is the only way to tell "agents that see it verify" from "agents that were going to
27
+ * verify anyway also saw it".
28
+ */
29
+ export declare const SUPPRESS_VERIFY_NEXT_ENV = "RETICLE_SUPPRESS_VERIFY_NEXT";
30
+ /** What the agent must supply itself. Phrased as an instruction so it cannot be sent verbatim. */
31
+ export declare const UNTIL_PLACEHOLDER = "<name the consequence this action causes>";
32
+ export interface VerifyNextBaton {
33
+ /** The fact that produced this, in the agent's own terms. */
34
+ why: string;
35
+ /** A call, ready to make once `until` is filled in. */
36
+ call?: {
37
+ tool: string;
38
+ args: Record<string, unknown>;
39
+ };
40
+ /** Where the argument shapes are stated, on disk and version-exact rather than on the web. */
41
+ docs?: string;
42
+ }
43
+ /**
44
+ * Build the baton from what the session actually did.
45
+ *
46
+ * `ref` absent means no act dispatched under a ref this session — a navigation, or a run that only
47
+ * read. There is then no honest call to name, so the prose stands alone rather than pointing at an
48
+ * element nobody touched.
49
+ */
50
+ export declare function verifyNextBaton(prose: string, lastAct: {
51
+ action?: string | undefined;
52
+ ref?: string | undefined;
53
+ }): VerifyNextBaton;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The verdict nudge, as a call the agent can make rather than a sentence it has to translate.
3
+ *
4
+ * `verify_next` already fires when an agent has driven the page several times and asked for no
5
+ * verdict, which is the commonest shape of a wasted session: almost every verdict-less session in
6
+ * the field never called a verdict-producing tool once. What it carried was prose. Prose has to be
7
+ * turned back into a call, and the translation is exactly where the agent was already going wrong —
8
+ * `until` omitted, arguments flat instead of nested under `args`, a predicate written as a bare
9
+ * array.
10
+ *
11
+ * So it carries the call. `ref` and `action` come from the act that actually dispatched, so the
12
+ * suggestion is about the element the agent really touched rather than a worked example from a
13
+ * document. `until` is deliberately left as a placeholder the agent must replace: naming the
14
+ * consequence is the one part nothing but the agent can know, and filling it in with a guess would
15
+ * be Reticle inventing the assertion — the failure `no-fault` exists to prevent.
16
+ *
17
+ * Emitted only when there is a real call to suggest. A baton with nothing behind it is the router
18
+ * failure in miniature: an agent that follows a fabricated next step follows it confidently.
19
+ */
20
+ import { ReticleTool } from './tool-names.js';
21
+ /**
22
+ * Set to `1` to withhold the baton from tool results — the control arm of its A/B, and nothing else.
23
+ *
24
+ * A measurement flag, not a product setting: it is read at one call site, documented here, and named
25
+ * loudly enough that nobody sets it by accident. It exists because this feature has shipped, been
26
+ * declared the largest lever on whether a session verifies at all, and never been measured — and a
27
+ * control arm is the only way to tell "agents that see it verify" from "agents that were going to
28
+ * verify anyway also saw it".
29
+ */
30
+ export const SUPPRESS_VERIFY_NEXT_ENV = 'RETICLE_SUPPRESS_VERIFY_NEXT';
31
+ /** What the agent must supply itself. Phrased as an instruction so it cannot be sent verbatim. */
32
+ export const UNTIL_PLACEHOLDER = '<name the consequence this action causes>';
33
+ /**
34
+ * Build the baton from what the session actually did.
35
+ *
36
+ * `ref` absent means no act dispatched under a ref this session — a navigation, or a run that only
37
+ * read. There is then no honest call to name, so the prose stands alone rather than pointing at an
38
+ * element nobody touched.
39
+ */
40
+ export function verifyNextBaton(prose, lastAct) {
41
+ const { ref, action } = lastAct;
42
+ if (ref === undefined || action === undefined)
43
+ return { why: prose };
44
+ return {
45
+ why: prose,
46
+ call: {
47
+ tool: ReticleTool.ACT_AND_WAIT,
48
+ args: { ref, action, until: { kind: 'text', value: UNTIL_PLACEHOLDER } },
49
+ },
50
+ docs: `reticle_tools { names: ["${ReticleTool.ACT_AND_WAIT}"] }`,
51
+ };
52
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The `@reticlehq/*` packages a project actually declares.
3
+ *
4
+ * Shared by `reticle update` (which syncs them) and the version-skew remedy (which names them).
5
+ * Lives here, not in `init/`, so the daemon library path can read a package.json without pulling
6
+ * the installer in behind it.
7
+ */
8
+ /** The Reticle packages this project declares, from either dependency section. */
9
+ export declare function reticleDepsOf(pkgJson: unknown): string[];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The `@reticlehq/*` packages a project actually declares.
3
+ *
4
+ * Shared by `reticle update` (which syncs them) and the version-skew remedy (which names them).
5
+ * Lives here, not in `init/`, so the daemon library path can read a package.json without pulling
6
+ * the installer in behind it.
7
+ */
8
+ /** Everything we publish is scoped here. */
9
+ const RETICLE_SCOPE = '@reticlehq/';
10
+ /**
11
+ * The CLI. Never an app dependency: it carries the Node MCP server and `ws`, and putting it in a
12
+ * browser app's tree is what the retired `@reticlehq/core` umbrella got wrong.
13
+ */
14
+ const SERVER_PACKAGE = '@reticlehq/server';
15
+ function namesIn(section) {
16
+ if ('object' !== typeof section || null === section)
17
+ return [];
18
+ return Object.keys(section);
19
+ }
20
+ /** The Reticle packages this project declares, from either dependency section. */
21
+ export function reticleDepsOf(pkgJson) {
22
+ if ('object' !== typeof pkgJson || null === pkgJson)
23
+ return [];
24
+ const manifest = pkgJson;
25
+ const declared = [...namesIn(manifest['dependencies']), ...namesIn(manifest['devDependencies'])];
26
+ return [...new Set(declared)].filter((name) => name.startsWith(RETICLE_SCOPE) && name !== SERVER_PACKAGE);
27
+ }
@@ -12,8 +12,7 @@
12
12
  * npm took 2.3.0 in the next project over.
13
13
  */
14
14
  import { type PackageManager } from '../init/detect.js';
15
- /** The Reticle packages this project declares, from either dependency section. */
16
- export declare function reticleDepsOf(pkgJson: unknown): string[];
15
+ export { reticleDepsOf } from './reticle-deps.js';
17
16
  /** The install to run, or null when this project has nothing of ours to sync. */
18
17
  export declare function sdkSyncCommand(pm: PackageManager, packages: readonly string[], version: string): {
19
18
  command: string;