@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
@@ -0,0 +1,22 @@
1
+ import type { Predicate } from '../events/predicate-schema.js';
2
+ /**
3
+ * The `file:line` an ASSERTION is entitled to report — its own evidence, or nothing.
4
+ *
5
+ * `reticle_assert` and `reticle_wait_for` drive nothing, so the last act's source is whatever
6
+ * unrelated action ran before them. Journaling it made an assert on one component claim it had
7
+ * proven something about another, and an assert that matched nothing claim a location at all — a
8
+ * wrong file:line in front of an agent, persisted, and read back by `reticle_context` long after
9
+ * the turn that produced it.
10
+ *
11
+ * The one borrow that survives is the documented one, and only on a failure: a predicate with no DOM
12
+ * clause has no element to point at, and the handler that should have fired the missing signal or
13
+ * made the missing request lives with the control that was last driven. That is what the tools'
14
+ * output schemas describe, and it is a pointer to the code under test rather than a guess about
15
+ * which code this verdict was about.
16
+ */
17
+ export declare function assertSource(facts: {
18
+ predicate: Predicate;
19
+ evidence: unknown;
20
+ pass: boolean;
21
+ lastActSource: string | undefined;
22
+ }): string | undefined;
@@ -0,0 +1,53 @@
1
+ import { declaresDom } from '../events/predicate-asks.js';
2
+ /**
3
+ * Where an assertion's OWN evidence is written, as `file:line`.
4
+ *
5
+ * The element descriptors an oracle returns already carry the nearest `data-reticle-source` the build
6
+ * plugin stamped, so a predicate that matched an element knows exactly where that element lives. It
7
+ * is only reported when every matched descriptor agrees: two loci and no way to choose is the same
8
+ * problem as no locus at all, and a guessed pointer costs the agent the trip AND leaves it further
9
+ * from the code.
10
+ *
11
+ * Near-miss evidence is deliberately NOT read. A near miss is a DIFFERENT element than the one the
12
+ * caller asked about, so its line is a suggestion dressed as a fact.
13
+ */
14
+ function evidenceSource(evidence) {
15
+ if (!Array.isArray(evidence) || 0 === evidence.length)
16
+ return undefined;
17
+ let agreed;
18
+ for (const entry of evidence) {
19
+ if ('object' !== typeof entry || null === entry)
20
+ return undefined;
21
+ const found = entry.source;
22
+ if ('string' !== typeof found || 0 === found.length)
23
+ return undefined;
24
+ if (agreed === undefined)
25
+ agreed = found;
26
+ else if (agreed !== found)
27
+ return undefined;
28
+ }
29
+ return agreed;
30
+ }
31
+ /**
32
+ * The `file:line` an ASSERTION is entitled to report — its own evidence, or nothing.
33
+ *
34
+ * `reticle_assert` and `reticle_wait_for` drive nothing, so the last act's source is whatever
35
+ * unrelated action ran before them. Journaling it made an assert on one component claim it had
36
+ * proven something about another, and an assert that matched nothing claim a location at all — a
37
+ * wrong file:line in front of an agent, persisted, and read back by `reticle_context` long after
38
+ * the turn that produced it.
39
+ *
40
+ * The one borrow that survives is the documented one, and only on a failure: a predicate with no DOM
41
+ * clause has no element to point at, and the handler that should have fired the missing signal or
42
+ * made the missing request lives with the control that was last driven. That is what the tools'
43
+ * output schemas describe, and it is a pointer to the code under test rather than a guess about
44
+ * which code this verdict was about.
45
+ */
46
+ export function assertSource(facts) {
47
+ const own = evidenceSource(facts.evidence);
48
+ if (own !== undefined)
49
+ return own;
50
+ if (facts.pass || declaresDom(facts.predicate))
51
+ return undefined;
52
+ return facts.lastActSource;
53
+ }
@@ -1,4 +1,4 @@
1
- import type { InstrumentationGap } from '@reticlehq/core';
1
+ import type { InstrumentationGap, JournalVerdictEffect } from '@reticlehq/core';
2
2
  import type { Predicate } from '../events/predicate.js';
3
3
  import type { Session } from '../session/session.js';
4
4
  import { type Contradiction } from '../events/contradictions.js';
@@ -15,7 +15,12 @@ import { type Contradiction } from '../events/contradictions.js';
15
15
  * consult it. Asserting a moment earlier — while the POST was still open — is the same story with a
16
16
  * different name: `request-never-settled`, also unreported.
17
17
  */
18
- export declare function assertVerdict(session: Session, predicate: Predicate, pass: boolean, since: number,
18
+ export declare function assertVerdict(session: Session, predicate: Predicate, pass: boolean,
19
+ /**
20
+ * What the oracle actually looked at. The only thing this verdict is entitled to point at — see
21
+ * `assertSource`, which reads the matched element descriptors' own `file:line`.
22
+ */
23
+ evidence: unknown, since: number,
19
24
  /** Set when the assertion was never evaluated — see honesty/verified.ts. */
20
25
  inconclusive?: string,
21
26
  /**
@@ -23,9 +28,21 @@ inconclusive?: string,
23
28
  * `reticle_wait_for` reach the same disconnect path as the act tools, and a verdict that blames
24
29
  * the app for a lost connection is no more honest on this route than on that one.
25
30
  */
26
- observationLost?: boolean): Promise<{
31
+ observationLost?: boolean,
32
+ /**
33
+ * Set when code changed since the last verdict with nothing declaring what it was for. Decided by
34
+ * `isChangeUndeclared` at the call site, which is the only place that can reach the intent ledger —
35
+ * this path takes a session and no `deps`.
36
+ */
37
+ changeUndeclared?: boolean): Promise<{
27
38
  decision: Record<string, unknown>;
28
39
  contradictions: Contradiction[];
29
40
  coverage: Record<string, unknown>;
30
41
  gaps: InstrumentationGap[];
42
+ /**
43
+ * The bounded verdict, in the SAME shape `act_and_wait` writes into its journal action — so the
44
+ * journal holds one verdict shape rather than two and the run fold that reads it needs no second
45
+ * case. Built here because this is the one place that holds the typed decision and the predicate.
46
+ */
47
+ verdictEffect: JournalVerdictEffect;
31
48
  }>;
@@ -1,11 +1,11 @@
1
- import { BlindSpotKind, CaptureLoss, PredicateKind } from '@reticlehq/core';
1
+ import { CaptureLoss, PredicateKind } from '@reticlehq/core';
2
2
  import { gapsForAction } from '../honesty/instrumentation-gaps.js';
3
3
  import { noteSessionGaps } from '../honesty/gap-ledger.js';
4
4
  import { declaresState } from '../events/predicate-asks.js';
5
5
  import { isStateUnwatched } from '../honesty/blind-spots.js';
6
6
  import { findContradictions } from '../events/contradictions.js';
7
- import { declaredExpectations } from '../events/declared.js';
8
- import { blindSpotsFromState, buildCoverageStatement, Coverage, impeachesCapture, transportGapNote, } from '../honesty/blind-spots.js';
7
+ import { declaredExpectations, declaresBodyIndependentChannel } from '../events/declared.js';
8
+ import { absenceBlindSpotNote, blindSpotsFromState, buildCoverageStatement, restsOnCompleteWindow, Coverage, impeachesCapture, transportGapNote, } from '../honesty/blind-spots.js';
9
9
  import { buildHonestyBlock } from '../honesty/honesty.js';
10
10
  import { hasAcceptedWrite } from '../honesty/accepted-write.js';
11
11
  import { unreadWriteLabels } from '../honesty/unread-outcome.js';
@@ -13,17 +13,7 @@ import { decideVerified } from '../honesty/verified.js';
13
13
  import { describeWaitTarget } from '../honesty/unsettled.js';
14
14
  import { inFlightRequestLabels, repeatedRequestLabels } from './settle-in-flight.js';
15
15
  import { gradeOfPredicate } from './assert-grade.js';
16
- function absenceBlindSpotNote(predicate, spots) {
17
- if (predicate.kind !== 'element' || predicate.absent !== true)
18
- return undefined;
19
- const relevant = spots.filter((spot) => spot.count > 0 &&
20
- spot.kind === BlindSpotKind.CROSS_ORIGIN_IFRAME &&
21
- undefined !== predicate.query.scope);
22
- if (0 === relevant.length)
23
- return undefined;
24
- const statement = buildCoverageStatement(relevant);
25
- return `the absence assertion targeted a region Reticle could not observe (${statement.note ?? 'partial coverage'}), so a passing DOM check cannot prove absence`;
26
- }
16
+ import { assertSource } from './assert-source.js';
27
17
  /**
28
18
  * The honesty verdict for a plain `reticle_assert`.
29
19
  *
@@ -37,7 +27,12 @@ function absenceBlindSpotNote(predicate, spots) {
37
27
  * consult it. Asserting a moment earlier — while the POST was still open — is the same story with a
38
28
  * different name: `request-never-settled`, also unreported.
39
29
  */
40
- export async function assertVerdict(session, predicate, pass, since,
30
+ export async function assertVerdict(session, predicate, pass,
31
+ /**
32
+ * What the oracle actually looked at. The only thing this verdict is entitled to point at — see
33
+ * `assertSource`, which reads the matched element descriptors' own `file:line`.
34
+ */
35
+ evidence, since,
41
36
  /** Set when the assertion was never evaluated — see honesty/verified.ts. */
42
37
  inconclusive,
43
38
  /**
@@ -45,13 +40,19 @@ inconclusive,
45
40
  * `reticle_wait_for` reach the same disconnect path as the act tools, and a verdict that blames
46
41
  * the app for a lost connection is no more honest on this route than on that one.
47
42
  */
48
- observationLost) {
43
+ observationLost,
44
+ /**
45
+ * Set when code changed since the last verdict with nothing declaring what it was for. Decided by
46
+ * `isChangeUndeclared` at the call site, which is the only place that can reach the intent ledger —
47
+ * this path takes a session and no `deps`.
48
+ */
49
+ changeUndeclared) {
49
50
  // Scope caveat, stated because it is a real limitation and not a bug: blind spots are tracked per
50
51
  // SESSION, not per assertion window, so a cross-origin iframe seen once marks every later verdict
51
52
  // in that session partial — including ones about a region it cannot affect. That errs toward
52
53
  // over-warning, which is the correct direction here: the failure this guards against is a green
53
54
  // that implies coverage it never had, and a needless caveat costs the agent a sentence.
54
- const spots = blindSpotsFromState(session.blindSpots());
55
+ const spots = blindSpotsFromState(session.blindSpots(), session.runtime);
55
56
  const statement = buildCoverageStatement(spots);
56
57
  const absenceBlindSpot = absenceBlindSpotNote(predicate, spots);
57
58
  // Omitted entirely when coverage is full, so an intact page pays nothing and the field's PRESENCE
@@ -80,6 +81,9 @@ observationLost) {
80
81
  const declared = declaredExpectations(predicate);
81
82
  const contradictions = findContradictions(windowEvents, {
82
83
  prior,
84
+ currentDocumentId: session.currentDocumentId,
85
+ currentEditEpoch: session.currentEditEpoch,
86
+ appOrigin: session.url,
83
87
  expectedFailures: declared.netFailures,
84
88
  renderProved: pass && declared.rendersContent,
85
89
  ...(actCursor !== undefined && actCursor >= since ? { actionSince: actCursor } : {}),
@@ -100,17 +104,34 @@ observationLost) {
100
104
  // not override it. A fix that lived on one half of the verdict surface would leave the other
101
105
  // half broken, and this is the tool agents call most.
102
106
  declaredConsequence: predicate.kind !== PredicateKind.SETTLED,
107
+ ...(declaresBodyIndependentChannel(predicate) ? { independentOfBody: true } : {}),
103
108
  ...(inconclusive === undefined ? {} : { inconclusive }),
104
109
  ...(true === observationLost ? { observationLost: true } : {}),
105
110
  ...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
106
111
  honesty: buildHonestyBlock({
107
112
  grade: gradeOfPredicate(predicate),
108
113
  attribution: 'window',
114
+ // Did the buffer evict SCARCE evidence belonging to this window, AND does a green here rest on
115
+ // the window being complete. assert never consulted the buffer at all, on the reasoning that it
116
+ // "observes an already-open window" — but eviction happens on push regardless of who opened the
117
+ // window, so `{ console, absent: true }` returned `yes` over a window whose evidence was gone,
118
+ // which is absence of evidence read as evidence of absence.
119
+ //
120
+ // The second half of the condition is not a refinement, it is what keeps this usable. Scarce
121
+ // loss is recorded for AGE eviction too, so `lostSince(0)` is true on any session past the 60s
122
+ // cutoff, and assert takes a caller-chosen `since` that is often 0. Impeaching every verdict
123
+ // over a wide window would make `unknown` the answer to everything — the failure this repo has
124
+ // already paid for once, when `unclean_capture` became the dominant cause of `unknown` in the
125
+ // field. The act path needs no such guard: its cursor is the action's own.
126
+ truncated: session.lostSince(since) && restsOnCompleteWindow(predicate),
109
127
  coveragePartial: Coverage.PARTIAL === statement.coverage,
128
+ ...(statement.note === undefined ? {} : { coverageNote: statement.note }),
110
129
  ...(0 === impeachingNotes.length ? {} : { blindSpots: impeachingNotes }),
111
- // Which loss, as an enum, beside the prose. `assert` observes an already-open window and never
112
- // consults the ring buffer's health, so `buffer_loss` is not one of its answers.
130
+ // Which loss, as an enum, beside the prose.
113
131
  losses: [
132
+ ...(session.lostSince(since) && restsOnCompleteWindow(predicate)
133
+ ? [CaptureLoss.BUFFER_LOSS]
134
+ : []),
114
135
  ...(gap === undefined ? [] : [CaptureLoss.TRANSPORT_GAP]),
115
136
  ...(impeaching.note === undefined ? [] : [CaptureLoss.BLIND_SPOT]),
116
137
  ],
@@ -131,19 +152,36 @@ observationLost) {
131
152
  // state assertion against an app that registers no store.
132
153
  const gaps = gapsForAction({
133
154
  pass,
134
- sourceKnown: session.lastAct.source() !== undefined,
155
+ ...(changeUndeclared === undefined ? {} : { changeUndeclared }),
156
+ source: session.lastAct.source(),
135
157
  stateAsked: declaresState(predicate),
136
158
  stateUnwatched: isStateUnwatched(spots),
159
+ // What the app DECLARED, so an under-instrumented one is told without having to be asked.
160
+ hasCapabilities: session.hasCapabilities,
137
161
  domMutated: false,
138
162
  signalsFired: 0,
139
163
  routeChanged: false,
140
164
  routeSignalFired: false,
141
165
  });
142
166
  noteSessionGaps(session, gaps);
167
+ // The one file:line this verdict is entitled to: its own evidence, or — for a failure with no DOM
168
+ // clause to point at — the control last driven. Returned so the RESPONSE can echo the same value
169
+ // the journal keeps; one verdict must never carry two different pointers.
170
+ const source = assertSource({
171
+ predicate,
172
+ evidence,
173
+ pass,
174
+ lastActSource: session.lastAct.source(),
175
+ });
143
176
  return {
144
177
  decision: decision,
145
178
  contradictions,
146
179
  coverage,
147
180
  gaps,
181
+ verdictEffect: {
182
+ claim: describeWaitTarget(predicate),
183
+ verified: decision.verified,
184
+ ...(source === undefined ? {} : { source }),
185
+ },
148
186
  };
149
187
  }
@@ -1,3 +1,4 @@
1
+ import { carryReticleIdentity } from './lease-tools.js';
1
2
  import { z } from 'zod';
2
3
  import { navigateResult } from './navigate-result.js';
3
4
  import { awaitArrival } from './navigate-arrival.js';
@@ -64,12 +65,15 @@ export const BROWSER_TOOLS = [
64
65
  // likely to need it. See reload-result.
65
66
  return reloadResult(back);
66
67
  }
67
- const url = asString(args['url']);
68
- if (url === undefined || 0 === url.length)
68
+ const requested = asString(args['url']);
69
+ if (requested === undefined || 0 === requested.length)
69
70
  return { ok: false, reason: 'url required' };
70
71
  // Record navigate as an action. Its window is usually empty (the page unloads and the SDK
71
72
  // reconnects), but the action record itself — "navigated to X" — is the causal fact worth keeping.
72
73
  const session = deps.sessions.resolve(asString(args['sessionId']));
74
+ // A leased tab is addressed by a URL param, so navigating away from it used to strand the
75
+ // lease — see carryReticleIdentity. A tab that claims no identity is untouched.
76
+ const url = carryReticleIdentity(session.url, requested);
73
77
  session.beginAction(ReticleTool.NAVIGATE, { url });
74
78
  // Same floor as the reload path above, for the same reason: going to a new URL replaces the
75
79
  // document just as thoroughly. `beginAction` attributes events to this action; it does not move
@@ -88,24 +92,4 @@ export const BROWSER_TOOLS = [
88
92
  }
89
93
  },
90
94
  },
91
- {
92
- name: ReticleTool.REFRESH,
93
- description: 'Reload the connected browser tab. Pass { hard: true } to bypass the browser cache (equivalent to Cmd+Shift+R). The SDK reconnects automatically after the reload.',
94
- inputSchema: {
95
- hard: z
96
- .boolean()
97
- .optional()
98
- .describe('Set true to bypass the browser cache. Default: false (normal reload).'),
99
- ...sessionIdShape,
100
- },
101
- outputSchema: {
102
- ok: z.boolean(),
103
- },
104
- handler: async (deps, args) => {
105
- await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.REFRESH, {
106
- hard: true === args['hard'],
107
- });
108
- return { ok: true };
109
- },
110
- },
111
95
  ];
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Finish a truncated snapshot, or say it could not be finished.
3
+ *
4
+ * The snapshot walk stops at its node cap and returns a document-order PREFIX with `truncated:true`.
5
+ * That flag has always been honest and has never been actionable: it says the read stopped, not
6
+ * where, so a caller could receive half a page and draw a NEGATIVE conclusion from it — "no error is
7
+ * shown", "the row is gone" — when the thing was simply past the cut. A read that under-reports is a
8
+ * verification result that is quietly wrong.
9
+ *
10
+ * The walk now names its own frontier (`unread`: refs of the subtrees it never entered), so the cut
11
+ * is recoverable: re-read each branch at its own path and the union is the whole tree. This is that
12
+ * loop, plus the half that matters — when the union CANNOT be assembled it says so, and the caller
13
+ * must not turn an empty result over it into an absence.
14
+ *
15
+ * The assembled tree is a UNION of subtrees, not a re-render: each appended chunk is indented from
16
+ * its own root. Callers scan it line by line (that is what every consumer of `tree` does), so the
17
+ * indentation restart costs nothing and re-walking the whole page from scratch would cost a lot.
18
+ */
19
+ /**
20
+ * How many snapshot round-trips one completion may spend.
21
+ *
22
+ * Each is a real command to the page, so this is the cost ceiling of a completed read, not a safety
23
+ * net. Twelve covers a page whose cut frontier is a handful of branches a couple of levels deep —
24
+ * the shape a node cap actually produces — while keeping the worst case near a dozen round-trips
25
+ * rather than a walk of the DOM one subtree at a time.
26
+ */
27
+ export declare const MAX_COMPLETION_READS = 12;
28
+ /**
29
+ * How many times the completion may follow a frontier into a new one.
30
+ *
31
+ * A branch re-read can itself truncate and name further branches, so this recursion needs a floor
32
+ * under it independent of the read budget: a hostile or pathologically deep DOM can hand back a new
33
+ * frontier every round forever. Four rounds (the first read plus three levels of re-reads) is deeper
34
+ * than a node cap reaches on a real page, and terminates on one that is not real.
35
+ */
36
+ export declare const MAX_COMPLETION_DEPTH = 4;
37
+ /** Reads one snapshot — whole page when `scope` is undefined, that branch when it is not. */
38
+ export type SnapshotReader = (scope: string | undefined) => Promise<unknown>;
39
+ export interface CompletedRead {
40
+ /** The union of every subtree that was read. Never a lie about what it contains — only about how much. */
41
+ tree: string;
42
+ /** True only when every branch the page cut was read back. A negative conclusion needs this. */
43
+ complete: boolean;
44
+ reads: number;
45
+ /** Why completion stopped short, for the caller to quote. Present ONLY when `complete` is false. */
46
+ incompleteBecause?: string;
47
+ }
48
+ export declare function readCompleteTree(read: SnapshotReader): Promise<CompletedRead>;
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Finish a truncated snapshot, or say it could not be finished.
4
+ *
5
+ * The snapshot walk stops at its node cap and returns a document-order PREFIX with `truncated:true`.
6
+ * That flag has always been honest and has never been actionable: it says the read stopped, not
7
+ * where, so a caller could receive half a page and draw a NEGATIVE conclusion from it — "no error is
8
+ * shown", "the row is gone" — when the thing was simply past the cut. A read that under-reports is a
9
+ * verification result that is quietly wrong.
10
+ *
11
+ * The walk now names its own frontier (`unread`: refs of the subtrees it never entered), so the cut
12
+ * is recoverable: re-read each branch at its own path and the union is the whole tree. This is that
13
+ * loop, plus the half that matters — when the union CANNOT be assembled it says so, and the caller
14
+ * must not turn an empty result over it into an absence.
15
+ *
16
+ * The assembled tree is a UNION of subtrees, not a re-render: each appended chunk is indented from
17
+ * its own root. Callers scan it line by line (that is what every consumer of `tree` does), so the
18
+ * indentation restart costs nothing and re-walking the whole page from scratch would cost a lot.
19
+ */
20
+ /**
21
+ * How many snapshot round-trips one completion may spend.
22
+ *
23
+ * Each is a real command to the page, so this is the cost ceiling of a completed read, not a safety
24
+ * net. Twelve covers a page whose cut frontier is a handful of branches a couple of levels deep —
25
+ * the shape a node cap actually produces — while keeping the worst case near a dozen round-trips
26
+ * rather than a walk of the DOM one subtree at a time.
27
+ */
28
+ export const MAX_COMPLETION_READS = 12;
29
+ /**
30
+ * How many times the completion may follow a frontier into a new one.
31
+ *
32
+ * A branch re-read can itself truncate and name further branches, so this recursion needs a floor
33
+ * under it independent of the read budget: a hostile or pathologically deep DOM can hand back a new
34
+ * frontier every round forever. Four rounds (the first read plus three levels of re-reads) is deeper
35
+ * than a node cap reaches on a real page, and terminates on one that is not real.
36
+ */
37
+ export const MAX_COMPLETION_DEPTH = 4;
38
+ const SnapshotShape = z.object({
39
+ tree: z.string().optional(),
40
+ truncated: z.boolean().optional(),
41
+ unread: z.array(z.string()).optional(),
42
+ unreadOverflow: z.literal(true).optional(),
43
+ });
44
+ export async function readCompleteTree(read) {
45
+ const parts = [];
46
+ let frontier = [undefined];
47
+ let reads = 0;
48
+ const stop = (because) => ({
49
+ tree: parts.join('\n'),
50
+ complete: false,
51
+ reads,
52
+ incompleteBecause: because,
53
+ });
54
+ for (let round = 0; round < MAX_COMPLETION_DEPTH; round += 1) {
55
+ const next = [];
56
+ for (const scope of frontier) {
57
+ if (reads >= MAX_COMPLETION_READS) {
58
+ return stop(`the page kept naming unread branches past ${String(MAX_COMPLETION_READS)} reads, so part of it was never seen`);
59
+ }
60
+ const parsed = SnapshotShape.safeParse(await read(scope));
61
+ reads += 1;
62
+ if (!parsed.success)
63
+ return stop('a snapshot came back in a shape this read cannot trust');
64
+ parts.push(parsed.data.tree ?? '');
65
+ if (true === parsed.data.unreadOverflow) {
66
+ return stop('the cut named more branches than one snapshot can carry, so the frontier itself is incomplete and no sequence of re-reads can finish this page');
67
+ }
68
+ next.push(...(parsed.data.unread ?? []));
69
+ }
70
+ if (0 === next.length)
71
+ return { tree: parts.join('\n'), complete: true, reads };
72
+ frontier = next;
73
+ }
74
+ return stop(`re-reads kept cutting after ${String(MAX_COMPLETION_DEPTH)} rounds, so part of the page was never seen`);
75
+ }
@@ -5,5 +5,14 @@ interface Control {
5
5
  }
6
6
  /** Parse the interactive snapshot into {ref,label} controls, preserving document order. */
7
7
  export declare function parseControls(tree: string): Control[];
8
- export declare const COVERAGE_TOOLS: ToolDef[];
8
+ /**
9
+ * Build the coverage tool over the dispatchable tool table.
10
+ *
11
+ * The table arrives as a thunk rather than an import: `tools.ts` assembles it FROM this module, so
12
+ * importing it back would close a cycle whose failure mode is a load-order-dependent crash rather
13
+ * than an error anyone sees while writing it. The thunk is called inside the handler, long after the
14
+ * table exists. It carries the merged names — the ones `reticle_run` will actually accept — because
15
+ * a tool that merged into a parent is not something an agent can call or a maintainer can cut.
16
+ */
17
+ export declare function buildCoverageTools(toolNames: () => readonly string[]): ToolDef[];
9
18
  export {};