@reticlehq/server 2.13.1 → 2.14.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 (449) hide show
  1. package/SKILL.md +8 -18
  2. package/bin/reticle.js +3 -0
  3. package/dist/bridge/auth-failure-reason.js +12 -1
  4. package/dist/bridge/bridge-security.d.ts +8 -0
  5. package/dist/bridge/bridge-security.js +6 -1
  6. package/dist/bridge/bridge.d.ts +3 -0
  7. package/dist/bridge/bridge.js +23 -1
  8. package/dist/bridge/bridge.test-harness.d.ts +10 -1
  9. package/dist/bridge/bridge.test-harness.js +7 -1
  10. package/dist/bridge/pairing-token.d.ts +17 -0
  11. package/dist/bridge/pairing-token.js +26 -0
  12. package/dist/bridge/token-auth.d.ts +7 -0
  13. package/dist/bridge/token-auth.js +7 -1
  14. package/dist/capsule/capsule-store.d.ts +4 -4
  15. package/dist/capsule/capsule.d.ts +1 -1
  16. package/dist/capsule/capsule.js +3 -3
  17. package/dist/capsule/causal-summary.d.ts +21 -1
  18. package/dist/capsule/causal-summary.js +8 -6
  19. package/dist/capsule/divergence.d.ts +1 -1
  20. package/dist/capsule/divergence.js +26 -10
  21. package/dist/chromium-launch-options.d.ts +2 -1
  22. package/dist/cli/adhoc-verdict.d.ts +58 -0
  23. package/dist/cli/adhoc-verdict.js +115 -0
  24. package/dist/cli/chromium-hint.d.ts +18 -4
  25. package/dist/cli/chromium-hint.js +54 -6
  26. package/dist/cli/cli-doctor.js +1 -2
  27. package/dist/cli/cli-flow-commands.d.ts +16 -2
  28. package/dist/cli/cli-flow-commands.js +28 -9
  29. package/dist/cli/cli-parse-feedback.js +1 -1
  30. package/dist/cli/cli-parse.d.ts +2 -1
  31. package/dist/cli/cli-parse.js +38 -0
  32. package/dist/cli/cli-port.d.ts +5 -13
  33. package/dist/cli/cli-port.js +5 -38
  34. package/dist/cli/cli-update-commands.js +4 -4
  35. package/dist/cli/cli-verify.d.ts +24 -7
  36. package/dist/cli/cli-verify.js +87 -13
  37. package/dist/cli/cloud-keystore.d.ts +2 -1
  38. package/dist/cli/cloud-login.d.ts +2 -1
  39. package/dist/cli/cloud-session.d.ts +2 -1
  40. package/dist/cli/cloud-session.js +1 -1
  41. package/dist/cli/daemon-start-options.d.ts +2 -1
  42. package/dist/cli/device-flow.d.ts +2 -2
  43. package/dist/cli/doctor-daemon-line.d.ts +2 -1
  44. package/dist/cli/doctor-project-line.d.ts +2 -1
  45. package/dist/cli/doctor-rows.d.ts +2 -1
  46. package/dist/cli/drive-attach.d.ts +4 -3
  47. package/dist/cli/gate-hook-message.d.ts +2 -1
  48. package/dist/cli/status-next-action.js +10 -11
  49. package/dist/cli.d.ts +1 -0
  50. package/dist/cli.js +21 -9
  51. package/dist/cloud/account-state.d.ts +20 -0
  52. package/dist/cloud/account-state.js +65 -0
  53. package/dist/cloud/cloud-sync.d.ts +46 -3
  54. package/dist/cloud/cloud-sync.js +116 -0
  55. package/dist/cloud/sync-cycle.d.ts +5 -4
  56. package/dist/cloud/sync-cycle.js +1 -1
  57. package/dist/cloud/sync-daemon.d.ts +3 -19
  58. package/dist/cloud/sync-daemon.js +2 -2
  59. package/dist/crawl/crawl-tools.js +1 -1
  60. package/dist/crawl/crawl.d.ts +5 -5
  61. package/dist/crawl/crawl.js +138 -4
  62. package/dist/daemon/daemon-resilience.d.ts +3 -2
  63. package/dist/daemon/daemon-resilience.js +43 -4
  64. package/dist/daemon/daemon-resolve.d.ts +0 -9
  65. package/dist/daemon/daemon-resolve.js +2 -2
  66. package/dist/daemon/dev-servers.d.ts +1 -1
  67. package/dist/daemon/dev-servers.js +1 -1
  68. package/dist/daemon/loopback-alias.d.ts +2 -1
  69. package/dist/daemon/startup-failure.d.ts +11 -0
  70. package/dist/daemon/startup-failure.js +46 -0
  71. package/dist/events/contradictions.d.ts +10 -16
  72. package/dist/events/contradictions.js +149 -17
  73. package/dist/events/declared.d.ts +13 -1
  74. package/dist/events/declared.js +59 -3
  75. package/dist/events/echo-mismatch.js +75 -6
  76. package/dist/events/lineage.d.ts +52 -0
  77. package/dist/events/lineage.js +122 -0
  78. package/dist/events/net-evidence.d.ts +21 -0
  79. package/dist/events/net-evidence.js +81 -0
  80. package/dist/events/predicate-console.d.ts +13 -0
  81. package/dist/events/predicate-console.js +138 -0
  82. package/dist/events/predicate-element.d.ts +13 -0
  83. package/dist/events/predicate-element.js +214 -0
  84. package/dist/events/predicate-eval.d.ts +15 -3
  85. package/dist/events/predicate-eval.js +128 -110
  86. package/dist/events/predicate-parse.js +34 -1
  87. package/dist/events/predicate-request-body.d.ts +50 -0
  88. package/dist/events/predicate-request-body.js +120 -0
  89. package/dist/events/predicate-route.d.ts +21 -1
  90. package/dist/events/predicate-route.js +149 -21
  91. package/dist/events/predicate-schema.d.ts +8 -1
  92. package/dist/events/predicate-schema.js +34 -0
  93. package/dist/events/predicate.d.ts +2 -0
  94. package/dist/events/predicate.js +52 -159
  95. package/dist/events/split-text-miss.d.ts +6 -4
  96. package/dist/events/split-text-miss.js +12 -5
  97. package/dist/flows/affected-tools.js +22 -9
  98. package/dist/flows/annotate.d.ts +2 -1
  99. package/dist/flows/annotate.js +19 -1
  100. package/dist/flows/coverage.d.ts +2 -2
  101. package/dist/flows/flake.d.ts +3 -3
  102. package/dist/flows/flow-expect-grammar.d.ts +33 -0
  103. package/dist/flows/flow-expect-grammar.js +155 -0
  104. package/dist/flows/flow-replay-run.d.ts +1 -1
  105. package/dist/flows/flow-replay-run.js +28 -15
  106. package/dist/flows/flow-replay.d.ts +10 -0
  107. package/dist/flows/flow-replay.js +57 -22
  108. package/dist/flows/flow-secret-field.d.ts +14 -0
  109. package/dist/flows/flow-secret-field.js +22 -0
  110. package/dist/flows/flow-step-runners.d.ts +1 -0
  111. package/dist/flows/flow-step-runners.js +91 -34
  112. package/dist/flows/flow-success.js +22 -0
  113. package/dist/flows/flow-tools.js +27 -8
  114. package/dist/flows/flow-upload-resolve.d.ts +23 -0
  115. package/dist/flows/flow-upload-resolve.js +46 -0
  116. package/dist/flows/flows.d.ts +15 -0
  117. package/dist/flows/flows.js +17 -14
  118. package/dist/flows/git-changed.d.ts +23 -4
  119. package/dist/flows/git-changed.js +32 -6
  120. package/dist/flows/heal-run.js +2 -2
  121. package/dist/flows/predicate-to-expect.d.ts +3 -2
  122. package/dist/flows/predicate-to-expect.js +11 -5
  123. package/dist/flows/recording-backtrack.d.ts +24 -0
  124. package/dist/flows/recording-backtrack.js +73 -0
  125. package/dist/flows/recordings.d.ts +6 -0
  126. package/dist/flows/replay-halt.d.ts +26 -0
  127. package/dist/flows/replay-halt.js +30 -0
  128. package/dist/flows/replay.d.ts +0 -8
  129. package/dist/flows/replay.js +15 -3
  130. package/dist/flows/suite-flakes.d.ts +2 -1
  131. package/dist/flows/verify-change-tools.js +16 -4
  132. package/dist/honesty/already-true.d.ts +14 -0
  133. package/dist/honesty/already-true.js +47 -4
  134. package/dist/honesty/blind-spots.d.ts +3 -1
  135. package/dist/honesty/blind-spots.js +24 -1
  136. package/dist/honesty/body-capture-remedy.d.ts +42 -0
  137. package/dist/honesty/body-capture-remedy.js +95 -0
  138. package/dist/honesty/feature-capture.d.ts +3 -2
  139. package/dist/honesty/feature-capture.js +1 -1
  140. package/dist/honesty/gap-ledger.d.ts +1 -1
  141. package/dist/honesty/gap-ledger.js +1 -1
  142. package/dist/honesty/instrumentation-gaps.d.ts +8 -1
  143. package/dist/honesty/instrumentation-gaps.js +12 -2
  144. package/dist/honesty/observability.d.ts +4 -3
  145. package/dist/honesty/tool-hit-rate.d.ts +3 -2
  146. package/dist/honesty/uncaptured-bodies.d.ts +3 -1
  147. package/dist/honesty/uncaptured-bodies.js +6 -2
  148. package/dist/honesty/unsettled.d.ts +9 -0
  149. package/dist/honesty/unsettled.js +45 -0
  150. package/dist/honesty/verified.d.ts +32 -1
  151. package/dist/honesty/verified.js +37 -10
  152. package/dist/impact/impact-store.d.ts +5 -14
  153. package/dist/impact/impact-store.js +49 -6
  154. package/dist/index.js +1 -1
  155. package/dist/input/network-detail.d.ts +26 -1
  156. package/dist/input/network-detail.js +44 -12
  157. package/dist/input/network-mock-tools.js +24 -17
  158. package/dist/input/real-input.js +1 -1
  159. package/dist/input/viewport-tools.js +25 -13
  160. package/dist/intent/inline-intent.d.ts +0 -10
  161. package/dist/intent/inline-intent.js +1 -1
  162. package/dist/intent/intent-shard-store.d.ts +3 -2
  163. package/dist/intent/intent-shard-store.js +1 -1
  164. package/dist/intent/intent-shard.d.ts +14 -14
  165. package/dist/intent/intent-shard.js +4 -4
  166. package/dist/intent/intent-store.d.ts +1 -1
  167. package/dist/intent/intent-store.js +1 -1
  168. package/dist/intent/intent-subject.d.ts +2 -1
  169. package/dist/intent/open-intents.d.ts +3 -2
  170. package/dist/license/license.d.ts +4 -4
  171. package/dist/license/license.js +1 -1
  172. package/dist/mcp/attach-memory.d.ts +2 -1
  173. package/dist/mcp/client-identity.d.ts +2 -1
  174. package/dist/mcp/mcp-outage.d.ts +1 -1
  175. package/dist/mcp/mcp-outage.js +1 -1
  176. package/dist/mcp/mcp-proxy.d.ts +3 -1
  177. package/dist/mcp/mcp-proxy.js +32 -7
  178. package/dist/mcp/mcp.js +3 -1
  179. package/dist/mcp/proxy-handshake.d.ts +2 -1
  180. package/dist/mcp/proxy-idle-exit.d.ts +45 -0
  181. package/dist/mcp/proxy-idle-exit.js +94 -0
  182. package/dist/mcp/server-instructions.d.ts +2 -1
  183. package/dist/memory/project-memory.d.ts +2 -3
  184. package/dist/memory/project-memory.js +1 -1
  185. package/dist/oracles/propose-consequences.js +5 -5
  186. package/dist/oracles/self-instrument.d.ts +2 -2
  187. package/dist/oracles/self-instrument.js +1 -1
  188. package/dist/platform.d.ts +3 -5
  189. package/dist/platform.js +3 -5
  190. package/dist/pool/browser-pool.d.ts +92 -0
  191. package/dist/pool/browser-pool.js +119 -5
  192. package/dist/pool/playwright-launcher.js +29 -2
  193. package/dist/pool/storage-seed.d.ts +23 -0
  194. package/dist/pool/storage-seed.js +198 -0
  195. package/dist/project/artifact-root.d.ts +2 -1
  196. package/dist/project/memory-fs.d.ts +2 -1
  197. package/dist/project/reticle-dir.js +1 -1
  198. package/dist/project/session-root.d.ts +8 -0
  199. package/dist/project/session-root.js +9 -2
  200. package/dist/runs/reticle-runner.d.ts +14 -1
  201. package/dist/runs/reticle-runner.js +39 -2
  202. package/dist/session/attachment-history.d.ts +2 -1
  203. package/dist/session/fake-session.d.ts +37 -0
  204. package/dist/session/fake-session.js +81 -0
  205. package/dist/session/lease-visibility.d.ts +2 -1
  206. package/dist/session/live-control-tools.js +6 -0
  207. package/dist/session/no-session-diagnosis.d.ts +17 -1
  208. package/dist/session/no-session-diagnosis.js +32 -6
  209. package/dist/session/no-session-next-action.d.ts +14 -0
  210. package/dist/session/no-session-next-action.js +18 -0
  211. package/dist/session/no-session-watch.js +46 -3
  212. package/dist/session/registered-projects.d.ts +54 -0
  213. package/dist/session/registered-projects.js +73 -0
  214. package/dist/session/review-store.d.ts +2 -1
  215. package/dist/session/session-health.d.ts +62 -1
  216. package/dist/session/session-health.js +82 -2
  217. package/dist/session/session-manager.d.ts +11 -1
  218. package/dist/session/session-manager.js +18 -3
  219. package/dist/session/session-replaced.d.ts +24 -0
  220. package/dist/session/session-replaced.js +29 -0
  221. package/dist/session/session-successor.js +20 -4
  222. package/dist/session/session.d.ts +13 -5
  223. package/dist/session/session.js +31 -23
  224. package/dist/setup/agent-configs.d.ts +3 -2
  225. package/dist/setup/agent-writer.d.ts +3 -2
  226. package/dist/setup/approval-migration.d.ts +2 -1
  227. package/dist/setup/approval-migration.js +1 -1
  228. package/dist/setup/auto-approve.d.ts +11 -19
  229. package/dist/setup/auto-approve.js +15 -12
  230. package/dist/{init → setup}/confirm.js +1 -1
  231. package/dist/setup/desktop-shape.d.ts +3 -2
  232. package/dist/setup/drive-agent.d.ts +2 -3
  233. package/dist/setup/drive-agent.js +1 -1
  234. package/dist/setup/drive-plan.d.ts +3 -2
  235. package/dist/setup/ensure-daemon.d.ts +2 -1
  236. package/dist/setup/existing-app.d.ts +12 -0
  237. package/dist/setup/existing-app.js +13 -0
  238. package/dist/setup/init-host.d.ts +11 -0
  239. package/dist/setup/init-host.js +26 -0
  240. package/dist/setup/init-runtime.d.ts +4 -10
  241. package/dist/setup/init-runtime.js +23 -16
  242. package/dist/setup/license-key.d.ts +2 -1
  243. package/dist/setup/listeners.d.ts +2 -1
  244. package/dist/setup/loopback-probe-urls.d.ts +18 -0
  245. package/dist/setup/loopback-probe-urls.js +52 -0
  246. package/dist/setup/node-effects.d.ts +3 -0
  247. package/dist/setup/node-effects.js +26 -11
  248. package/dist/setup/page-probe.d.ts +5 -0
  249. package/dist/setup/relaunch.d.ts +2 -1
  250. package/dist/setup/run-setup.d.ts +5 -1
  251. package/dist/setup/run-setup.js +141 -50
  252. package/dist/setup/setup-command.d.ts +3 -2
  253. package/dist/setup/setup-command.js +8 -0
  254. package/dist/setup/setup-options.d.ts +5 -3
  255. package/dist/setup/setup-options.js +3 -2
  256. package/dist/setup/wait-progress.d.ts +28 -0
  257. package/dist/setup/wait-progress.js +43 -0
  258. package/dist/telemetry/app-instrumented.d.ts +2 -1
  259. package/dist/telemetry/app-instrumented.js +1 -1
  260. package/dist/telemetry/automation-hint.d.ts +1 -1
  261. package/dist/telemetry/automation-hint.js +1 -1
  262. package/dist/telemetry/cli-telemetry.js +1 -1
  263. package/dist/telemetry/connect-failure.d.ts +1 -1
  264. package/dist/telemetry/connect-failure.js +1 -1
  265. package/dist/telemetry/crash-cause.d.ts +3 -2
  266. package/dist/telemetry/crash-cause.js +1 -1
  267. package/dist/telemetry/daemon-telemetry.d.ts +3 -2
  268. package/dist/telemetry/daemon-telemetry.js +1 -1
  269. package/dist/telemetry/error-class.d.ts +3 -2
  270. package/dist/telemetry/error-class.js +1 -1
  271. package/dist/telemetry/feedback-cli.js +1 -1
  272. package/dist/telemetry/feedback-context.d.ts +3 -2
  273. package/dist/telemetry/feedback-context.js +5 -4
  274. package/dist/telemetry/feedback-local.d.ts +3 -2
  275. package/dist/telemetry/feedback.d.ts +4 -3
  276. package/dist/telemetry/feedback.js +1 -1
  277. package/dist/telemetry/git-facts.d.ts +2 -2
  278. package/dist/telemetry/git-facts.js +1 -1
  279. package/dist/telemetry/identify.d.ts +1 -1
  280. package/dist/telemetry/identify.js +1 -1
  281. package/dist/telemetry/init-telemetry.d.ts +2 -14
  282. package/dist/telemetry/init-telemetry.js +4 -13
  283. package/dist/telemetry/install-source.d.ts +7 -13
  284. package/dist/telemetry/install-source.js +7 -29
  285. package/dist/telemetry/license-activation.d.ts +3 -2
  286. package/dist/telemetry/license-activation.js +1 -1
  287. package/dist/telemetry/machine-snapshot.d.ts +1 -1
  288. package/dist/telemetry/mcp-connection.js +1 -1
  289. package/dist/telemetry/project-profile.d.ts +0 -14
  290. package/dist/telemetry/project-profile.js +1 -1
  291. package/dist/telemetry/proxy-telemetry.js +1 -1
  292. package/dist/telemetry/session-metrics.d.ts +1 -1
  293. package/dist/telemetry/session-metrics.js +1 -1
  294. package/dist/telemetry/telemetry.d.ts +1 -17
  295. package/dist/telemetry/telemetry.js +4 -4
  296. package/dist/telemetry/tool-refused.d.ts +1 -1
  297. package/dist/telemetry/tool-refused.js +1 -1
  298. package/dist/tools/act-observation.d.ts +3 -2
  299. package/dist/tools/act-preflight.js +8 -3
  300. package/dist/tools/act-target.d.ts +4 -0
  301. package/dist/tools/act-target.js +14 -5
  302. package/dist/tools/act-tools.d.ts +0 -2
  303. package/dist/tools/act-tools.js +45 -15
  304. package/dist/tools/assert-source.d.ts +30 -0
  305. package/dist/tools/assert-source.js +21 -0
  306. package/dist/tools/assert-verdict.d.ts +1 -1
  307. package/dist/tools/assert-verdict.js +14 -4
  308. package/dist/tools/browser-tools.js +28 -8
  309. package/dist/tools/complete-snapshot.d.ts +3 -2
  310. package/dist/tools/dynamic-tools.js +8 -0
  311. package/dist/tools/error-recovery.d.ts +10 -0
  312. package/dist/tools/error-recovery.js +23 -0
  313. package/dist/tools/feedback-tools.js +1 -1
  314. package/dist/tools/invoke-tool.js +2 -0
  315. package/dist/tools/lease-tools.d.ts +48 -20
  316. package/dist/tools/lease-tools.js +311 -76
  317. package/dist/tools/lineage-tools.d.ts +14 -0
  318. package/dist/tools/lineage-tools.js +64 -0
  319. package/dist/tools/merge-tools.js +1 -3
  320. package/dist/tools/navigate-arrival.d.ts +45 -1
  321. package/dist/tools/navigate-arrival.js +39 -6
  322. package/dist/tools/navigate-result.d.ts +8 -1
  323. package/dist/tools/navigate-result.js +14 -4
  324. package/dist/tools/numeric-bounds.d.ts +0 -11
  325. package/dist/tools/numeric-bounds.js +4 -4
  326. package/dist/tools/observe-tools.js +22 -26
  327. package/dist/tools/observed-nothing.d.ts +9 -0
  328. package/dist/tools/observed-nothing.js +2 -1
  329. package/dist/tools/read-tools.js +12 -17
  330. package/dist/tools/real-input-attempt.d.ts +14 -6
  331. package/dist/tools/real-input-attempt.js +75 -18
  332. package/dist/tools/reconcile-tools.js +2 -1
  333. package/dist/tools/reload-result.d.ts +6 -1
  334. package/dist/tools/reload-result.js +7 -2
  335. package/dist/tools/resolve-target.d.ts +7 -1
  336. package/dist/tools/resolve-target.js +72 -9
  337. package/dist/tools/settle-in-flight.d.ts +1 -1
  338. package/dist/tools/settle-in-flight.js +9 -2
  339. package/dist/tools/snapshot-delta.d.ts +24 -1
  340. package/dist/tools/snapshot-delta.js +66 -7
  341. package/dist/tools/tool-names.d.ts +1 -0
  342. package/dist/tools/tool-names.js +1 -0
  343. package/dist/tools/tool-surface.js +20 -2
  344. package/dist/tools/tools.js +120 -11
  345. package/dist/tools/verify-next-baton.d.ts +2 -1
  346. package/dist/update/sdk-sync.d.ts +1 -1
  347. package/dist/update/sdk-sync.js +1 -1
  348. package/dist/update/updater.js +1 -1
  349. package/dist/version/sdk-fix.d.ts +2 -1
  350. package/dist/version/version-skew.d.ts +0 -8
  351. package/dist/version/version-skew.js +1 -1
  352. package/docs/README.md +8 -6
  353. package/docs/actions.mdx +1 -1
  354. package/docs/agent-cheatsheet.md +4 -2
  355. package/docs/architecture.md +1 -1
  356. package/docs/cli/mcp.mdx +3 -1
  357. package/docs/cli/watch.mdx +1 -1
  358. package/docs/cli.mdx +1 -1
  359. package/docs/desktop.mdx +1 -1
  360. package/docs/docs.json +8 -3
  361. package/docs/faq.mdx +9 -0
  362. package/docs/first-drive.md +136 -0
  363. package/docs/frameworks.mdx +29 -7
  364. package/docs/gate-plan.md +2 -2
  365. package/docs/gates.md +19 -11
  366. package/docs/getting-started.md +7 -1
  367. package/docs/http-transport.md +164 -0
  368. package/docs/index.mdx +5 -3
  369. package/docs/install-manual.mdx +1 -1
  370. package/docs/packages/tauri.mdx +1 -1
  371. package/docs/packages.mdx +15 -3
  372. package/docs/platform-integration.md +1 -1
  373. package/docs/predicates.mdx +2 -0
  374. package/docs/system-map.md +2 -2
  375. package/docs/telemetry-contract.md +4 -4
  376. package/docs/telemetry-events.mdx +1 -1
  377. package/docs/telemetry.md +3 -3
  378. package/docs/tools-navigate.mdx +14 -6
  379. package/docs/usage.md +4 -4
  380. package/package.json +7 -4
  381. package/dist/init/agent-rules.d.ts +0 -116
  382. package/dist/init/agent-rules.js +0 -279
  383. package/dist/init/app-choice.d.ts +0 -20
  384. package/dist/init/app-choice.js +0 -25
  385. package/dist/init/astro-host.d.ts +0 -21
  386. package/dist/init/astro-host.js +0 -27
  387. package/dist/init/astro-patch.d.ts +0 -33
  388. package/dist/init/astro-patch.js +0 -300
  389. package/dist/init/capabilities.d.ts +0 -40
  390. package/dist/init/capabilities.js +0 -150
  391. package/dist/init/closing-hint.d.ts +0 -36
  392. package/dist/init/closing-hint.js +0 -120
  393. package/dist/init/connect-steps.d.ts +0 -2
  394. package/dist/init/connect-steps.js +0 -50
  395. package/dist/init/cra.d.ts +0 -79
  396. package/dist/init/cra.js +0 -178
  397. package/dist/init/csp-check.d.ts +0 -38
  398. package/dist/init/csp-check.js +0 -107
  399. package/dist/init/csp-doctor.d.ts +0 -32
  400. package/dist/init/csp-doctor.js +0 -54
  401. package/dist/init/desktop-doctor.d.ts +0 -41
  402. package/dist/init/desktop-doctor.js +0 -198
  403. package/dist/init/detect.d.ts +0 -96
  404. package/dist/init/detect.js +0 -209
  405. package/dist/init/dev-script.d.ts +0 -50
  406. package/dist/init/dev-script.js +0 -66
  407. package/dist/init/format-generated.d.ts +0 -18
  408. package/dist/init/format-generated.js +0 -39
  409. package/dist/init/install-hint.d.ts +0 -9
  410. package/dist/init/install-hint.js +0 -29
  411. package/dist/init/mcp-clients.d.ts +0 -89
  412. package/dist/init/mcp-clients.js +0 -299
  413. package/dist/init/mcp-registered.d.ts +0 -12
  414. package/dist/init/mcp-registered.js +0 -14
  415. package/dist/init/mcp.d.ts +0 -89
  416. package/dist/init/mcp.js +0 -129
  417. package/dist/init/next-patch.d.ts +0 -39
  418. package/dist/init/next-patch.js +0 -196
  419. package/dist/init/node-io.d.ts +0 -7
  420. package/dist/init/node-io.js +0 -117
  421. package/dist/init/non-js-project.d.ts +0 -27
  422. package/dist/init/non-js-project.js +0 -84
  423. package/dist/init/patch-kind.d.ts +0 -20
  424. package/dist/init/patch-kind.js +0 -10
  425. package/dist/init/plan-framework.d.ts +0 -64
  426. package/dist/init/plan-framework.js +0 -565
  427. package/dist/init/plan.d.ts +0 -242
  428. package/dist/init/plan.js +0 -703
  429. package/dist/init/preflight.d.ts +0 -28
  430. package/dist/init/preflight.js +0 -38
  431. package/dist/init/project-id.d.ts +0 -12
  432. package/dist/init/project-id.js +0 -25
  433. package/dist/init/refresh-rules.d.ts +0 -39
  434. package/dist/init/refresh-rules.js +0 -51
  435. package/dist/init/run.d.ts +0 -117
  436. package/dist/init/run.js +0 -806
  437. package/dist/init/slash-command.d.ts +0 -27
  438. package/dist/init/slash-command.js +0 -132
  439. package/dist/init/snippets.d.ts +0 -134
  440. package/dist/init/snippets.js +0 -572
  441. package/dist/init/vite-config.d.ts +0 -18
  442. package/dist/init/vite-config.js +0 -114
  443. package/dist/init/windows-quote.d.ts +0 -38
  444. package/dist/init/windows-quote.js +0 -70
  445. package/dist/init/workspace-apps.d.ts +0 -30
  446. package/dist/init/workspace-apps.js +0 -178
  447. package/dist/project/remember-project.d.ts +0 -24
  448. package/dist/project/remember-project.js +0 -40
  449. /package/dist/{init → setup}/confirm.d.ts +0 -0
@@ -10,6 +10,7 @@ import { leanActResult, mutatedWithin } from './act-view.js';
10
10
  import { ReticleTool } from './tool-names.js';
11
11
  import { buildReactionReport, summarizeReaction } from '../events/reaction.js';
12
12
  import { parsePredicate } from '../events/predicate-parse.js';
13
+ import { bodyClauseRefusal } from '../honesty/body-capture-remedy.js';
13
14
  import { causalSummary } from '../capsule/causal-summary.js';
14
15
  import { findContradictions } from '../events/contradictions.js';
15
16
  import { gapsForAction } from '../honesty/instrumentation-gaps.js';
@@ -24,8 +25,8 @@ import { waitForReaction } from './react-grace.js';
24
25
  import { decideVerified } from '../honesty/verified.js';
25
26
  import { honestyForVerdict } from '../honesty/honesty.js';
26
27
  import { declaredExpectations, declaresBodyIndependentChannel } from '../events/declared.js';
27
- import { readsDomState } from '../honesty/already-true.js';
28
- import { describeWaitTarget } from '../honesty/unsettled.js';
28
+ import { readsDomState, alreadyTrueHiddenMatch as alreadyTrueHiddenMatchOf, } from '../honesty/already-true.js';
29
+ import { describeWaitTarget, namedNetIsInFlight } from '../honesty/unsettled.js';
29
30
  import { saveFailedAssertCapsule } from './act-capsule.js';
30
31
  import { buildDivergenceCapsule } from '../capsule/capsule.js';
31
32
  import { predicateToExpectedLinks } from '../capsule/predicate-to-links.js';
@@ -97,8 +98,7 @@ export async function actCommand(deps, session, actArgs, timeoutMs) {
97
98
  * one layer earlier, before any session is resolved or any work is done.
98
99
  */
99
100
  const ACTION_TYPE_VALUES = Object.values(ActionType);
100
- const ACTION_TYPE_LIST = ACTION_TYPE_VALUES.join(' | ');
101
- export const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
101
+ const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
102
102
  export const ACT_TOOLS = [
103
103
  {
104
104
  name: ReticleTool.ACT,
@@ -108,12 +108,12 @@ export const ACT_TOOLS = [
108
108
  ref: z
109
109
  .string()
110
110
  .optional()
111
- .describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`.`),
111
+ .describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
112
112
  target: z
113
113
  .record(z.unknown())
114
114
  .optional()
115
115
  .describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
116
- action: actionTypeEnum.describe(`Action to perform: ${ACTION_TYPE_LIST}`),
116
+ action: actionTypeEnum.describe('Action to perform.'),
117
117
  args: z
118
118
  .record(z.unknown())
119
119
  .optional()
@@ -248,12 +248,12 @@ export const ACT_TOOLS = [
248
248
  ref: z
249
249
  .string()
250
250
  .optional()
251
- .describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`.`),
251
+ .describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
252
252
  target: z
253
253
  .record(z.unknown())
254
254
  .optional()
255
255
  .describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
256
- action: actionTypeEnum.describe(`Action to perform: ${ACTION_TYPE_LIST}`),
256
+ action: actionTypeEnum.describe('Action to perform.'),
257
257
  args: z
258
258
  .record(z.unknown())
259
259
  .optional()
@@ -369,6 +369,11 @@ export const ACT_TOOLS = [
369
369
  const until = withUntil['until'] !== undefined
370
370
  ? parsePredicate(withUntil['until'])
371
371
  : { kind: PredicateKind.SETTLED };
372
+ // BEFORE the action. A body clause this session cannot answer would fail whatever the app
373
+ // did, and on a drive that mutates state the action is not always repeatable. See #801(C).
374
+ const bodyRefusal = bodyClauseRefusal(until, session);
375
+ if (bodyRefusal !== undefined)
376
+ throw new Error(bodyRefusal);
372
377
  const timeout = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
373
378
  // An intent declared here lands in the ledger BEFORE the verdict is drawn, which is what makes
374
379
  // the undeclared-change gap silent on THIS verdict rather than the next one: it reads the
@@ -396,8 +401,15 @@ export const ACT_TOOLS = [
396
401
  // state — event-based ones are floored at this act's cursor and cannot be satisfied by the
397
402
  // past, so they need no pre-check and pay nothing. One extra query, on the path where a green
398
403
  // is otherwise unfalsifiable. See honesty/already-true.
399
- const alreadyTrue = until !== undefined && readsDomState(until)
400
- ? (await evaluatePredicate(session, until, since, false)).pass
404
+ const alreadyTruePrecheck = until !== undefined && readsDomState(until)
405
+ ? await evaluatePredicate(session, until, since, false)
406
+ : undefined;
407
+ const alreadyTrue = alreadyTruePrecheck?.pass ?? false;
408
+ // #889: the pre-check evidence is already in hand — cheap to also ask whether that match was
409
+ // against something hidden, so the already_true message can name it instead of leaving the
410
+ // agent to re-derive "was this actually showing?" from nothing.
411
+ const alreadyTrueHiddenMatch = alreadyTrue && until !== undefined
412
+ ? alreadyTrueHiddenMatchOf(until, alreadyTruePrecheck?.evidence)
401
413
  : false;
402
414
  try {
403
415
  // actCommand is the single interception point for upload+path rewrite.
@@ -488,7 +500,12 @@ export const ACT_TOOLS = [
488
500
  // On RED only, attach the Tier-2 divergence capsule (first-divergence + blast radius). Red-only,
489
501
  // so the common green path — what the loop optimizes — is unchanged; on red, diagnosis is the point.
490
502
  const links = predicateToExpectedLinks(until);
491
- const capsule = verdict.pass ? undefined : buildDivergenceCapsule(links, windowEvents);
503
+ // Read before the capsule, which needs it: a window the buffer trimmed cannot state an
504
+ // absolute about what did NOT happen. See CausalSummary.truncated.
505
+ const bufferLost = session.lostSince(since);
506
+ const capsule = verdict.pass
507
+ ? undefined
508
+ : buildDivergenceCapsule(links, windowEvents, bufferLost);
492
509
  // Grade from what the verdict PROVED, not what it declared. A green anyOf holds on one branch, so
493
510
  // grading off `links` (every branch) would let a presence-only OR report grade `signal` — a false
494
511
  // green in the gate itself. `provenExpectedLinks` narrows a green to the branch that actually held;
@@ -515,7 +532,6 @@ export const ACT_TOOLS = [
515
532
  // whose own words were "over a clean capture".
516
533
  const gapNote = transportGapNote(windowEvents);
517
534
  const impeachingNotes = [impeaching.note, gapNote].filter((n) => n !== undefined);
518
- const bufferLost = session.lostSince(since);
519
535
  // Which loss, as an enum, beside the prose that describes it. Classified here because this is
520
536
  // the only place that knows the three apart: our buffer, our transport, and the page's own
521
537
  // boundaries. See `CaptureLoss`.
@@ -594,8 +610,12 @@ export const ACT_TOOLS = [
594
610
  // this is the only one that has to be interpreted, and now it interprets itself.
595
611
  const outcomePending = hasAcceptedWrite(windowEvents);
596
612
  const outcomeUnread = unreadWriteLabels(windowEvents);
613
+ const stillInFlight = inFlightRequestLabels(windowEvents);
597
614
  const decision = decideVerified({
598
615
  pass: verdict.pass,
616
+ // So the unread-body remedy can check it applies to THIS page. Threaded rather than
617
+ // looked up inside decideVerified, which is pure and has no session.
618
+ ...(session.sdkVersion === undefined ? {} : { sdkVersion: session.sdkVersion }),
599
619
  // The caller NAMED the consequence rather than defaulting to "wait for idle". A
600
620
  // declaration made before the action is what this tool sells, and idle-settlement was
601
621
  // overriding it — see `declaredConsequence`. An explicit `{ kind: "settled" }` is not a
@@ -605,12 +625,15 @@ export const ACT_TOOLS = [
605
625
  // Omit when false: a net-only `until` must still hit `outcome_unread`.
606
626
  ...(declaresBodyIndependentChannel(until) ? { independentOfBody: true } : {}),
607
627
  ...(alreadyTrue ? { alreadyTrue } : {}),
628
+ ...(alreadyTrueHiddenMatch ? { alreadyTrueHiddenMatch } : {}),
608
629
  // An assertion nobody could evaluate must not be reported as one the app failed.
609
630
  ...(verdict.inconclusive === undefined ? {} : { inconclusive: verdict.inconclusive }),
610
631
  // Nor must one nobody could OBSERVE. This is the act path, so it is the one that produced
611
632
  // the measured false red: a reload mid-wait, graded assertion_failed at the clicked
612
633
  // component's own file and line.
613
- ...(true === verdict.observationLost ? { observationLost: true } : {}),
634
+ ...(true === verdict.observationLost
635
+ ? { observationLost: true, lastUrl: session.url }
636
+ : {}),
614
637
  ...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
615
638
  honesty,
616
639
  contradictions,
@@ -624,14 +647,18 @@ export const ACT_TOOLS = [
624
647
  // window is already in hand.
625
648
  unsettled: {
626
649
  waitedFor: describeWaitTarget(until),
627
- stillInFlight: inFlightRequestLabels(windowEvents),
650
+ stillInFlight,
628
651
  // The retry loop that leaves nothing outstanding — see repeatedRequestLabels.
629
652
  repeated: repeatedRequestLabels(windowEvents),
630
653
  },
654
+ ...(namedNetIsInFlight(until, stillInFlight) ? { namedRequestInFlight: true } : {}),
631
655
  });
632
656
  // Computed once: the verdict block reports it, and the instrumentation gaps are a second
633
657
  // reading of the same evidence rather than a new observation.
634
- const actionSummary = causalSummary(windowEvents, { stateUnwatched });
658
+ const actionSummary = causalSummary(windowEvents, {
659
+ stateUnwatched,
660
+ truncated: bufferLost,
661
+ });
635
662
  // Asked of every verdict drawn after an observed edit, not once per edit — see
636
663
  // isChangeUndeclared for why repeating it is disclosure rather than nagging.
637
664
  // Read ONCE and used twice: `changeUndeclared` asks whether the ledger is empty, and the
@@ -649,6 +676,9 @@ export const ACT_TOOLS = [
649
676
  stateUnwatched,
650
677
  // What the app DECLARED, so an under-instrumented one is told without having to be asked.
651
678
  hasCapabilities: session.hasCapabilities,
679
+ // Whether the build TURNED the source stamp off, so a red with no file:line prescribes the
680
+ // right fix. `false` from the page is the only value that means anything; absent is unknown.
681
+ ...(false === session.sourceMapping ? { sourceMappingDisabled: true } : {}),
652
682
  // What the run still owes. A green that leaves this above zero is not the same as done.
653
683
  // MINUS the one this verdict is about to discharge.
654
684
  //
@@ -1,4 +1,5 @@
1
1
  import type { Predicate } from '../events/predicate-schema.js';
2
+ import type { Session } from '../session/session.js';
2
3
  /**
3
4
  * The `file:line` an ASSERTION is entitled to report — its own evidence, or nothing.
4
5
  *
@@ -19,4 +20,33 @@ export declare function assertSource(facts: {
19
20
  evidence: unknown;
20
21
  pass: boolean;
21
22
  lastActSource: string | undefined;
23
+ /**
24
+ * Set when the verdict could not be EVALUATED rather than evaluated and found false.
25
+ *
26
+ * A file:line reads as a precise, well-attributed finding about that file. Attaching one to a
27
+ * reading that proved nothing sends the investigation into correct code: reported against a
28
+ * wedged Next.js dev server, where a route verdict named `components/.../header.tsx:53` and the
29
+ * reporter nearly filed "the header Sign Up link is broken" — the server was answering nothing at
30
+ * all, on every route.
31
+ *
32
+ * Gated here rather than in the route oracle, because every producer of an inconclusive verdict
33
+ * has the same problem: a throttled tab, a superseded window, an unreadable locator. One guard
34
+ * where all of them route through.
35
+ */
36
+ inconclusive?: string | undefined;
22
37
  }): string | undefined;
38
+ /**
39
+ * The file:line an assertion may report — see `assertSource`.
40
+ *
41
+ * Neither `reticle_assert` nor `reticle_wait_for` drives anything, so the last act's source is about
42
+ * some earlier action and not about this verdict. The pointer comes from the assertion's own matched
43
+ * evidence; the last driven control is borrowed only for a RED whose predicate has no DOM clause at
44
+ * all, which is the failure that genuinely has no element to point at.
45
+ */
46
+ export declare function assertionSource(session: Session, predicate: Predicate, verdict: {
47
+ pass: boolean;
48
+ evidence?: unknown;
49
+ inconclusive?: string;
50
+ }): {
51
+ source?: string;
52
+ };
@@ -49,5 +49,26 @@ export function assertSource(facts) {
49
49
  return own;
50
50
  if (facts.pass || declaresDom(facts.predicate))
51
51
  return undefined;
52
+ // Nothing was proven and nobody could have proven it — so there is nothing to point at.
53
+ if (facts.inconclusive !== undefined)
54
+ return undefined;
52
55
  return facts.lastActSource;
53
56
  }
57
+ /**
58
+ * The file:line an assertion may report — see `assertSource`.
59
+ *
60
+ * Neither `reticle_assert` nor `reticle_wait_for` drives anything, so the last act's source is about
61
+ * some earlier action and not about this verdict. The pointer comes from the assertion's own matched
62
+ * evidence; the last driven control is borrowed only for a RED whose predicate has no DOM clause at
63
+ * all, which is the failure that genuinely has no element to point at.
64
+ */
65
+ export function assertionSource(session, predicate, verdict) {
66
+ const source = assertSource({
67
+ predicate,
68
+ evidence: verdict.evidence,
69
+ pass: verdict.pass,
70
+ lastActSource: session.lastAct.source(),
71
+ ...(verdict.inconclusive === undefined ? {} : { inconclusive: verdict.inconclusive }),
72
+ });
73
+ return source === undefined ? {} : { source };
74
+ }
@@ -1,4 +1,4 @@
1
- import type { InstrumentationGap, JournalVerdictEffect } from '@reticlehq/core';
1
+ import type { InstrumentationGap, JournalVerdictEffect } from '@reticlehq/core/artifacts';
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';
@@ -10,7 +10,7 @@ import { buildHonestyBlock } from '../honesty/honesty.js';
10
10
  import { hasAcceptedWrite } from '../honesty/accepted-write.js';
11
11
  import { unreadWriteLabels } from '../honesty/unread-outcome.js';
12
12
  import { decideVerified } from '../honesty/verified.js';
13
- import { describeWaitTarget } from '../honesty/unsettled.js';
13
+ import { describeWaitTarget, namedNetIsInFlight } from '../honesty/unsettled.js';
14
14
  import { inFlightRequestLabels, repeatedRequestLabels } from './settle-in-flight.js';
15
15
  import { gradeOfPredicate } from './assert-grade.js';
16
16
  import { assertSource } from './assert-source.js';
@@ -85,6 +85,7 @@ changeUndeclared) {
85
85
  currentEditEpoch: session.currentEditEpoch,
86
86
  appOrigin: session.url,
87
87
  expectedFailures: declared.netFailures,
88
+ namedNetUrls: declared.netUrls,
88
89
  renderProved: pass && declared.rendersContent,
89
90
  ...(actCursor !== undefined && actCursor >= since ? { actionSince: actCursor } : {}),
90
91
  });
@@ -98,16 +99,22 @@ changeUndeclared) {
98
99
  const impeachingNotes = [impeaching.note, gap].filter((n) => n !== undefined);
99
100
  const outcomePending = hasAcceptedWrite(windowEvents);
100
101
  const outcomeUnread = unreadWriteLabels(windowEvents);
102
+ const stillInFlight = inFlightRequestLabels(windowEvents);
103
+ const effectiveInconclusive = inconclusive ?? (!pass ? session.preconditionFailure?.() : undefined);
101
104
  const decision = decideVerified({
102
105
  pass,
106
+ // So the unread-body remedy can check it applies to THIS page. Threaded rather than
107
+ // looked up inside decideVerified, which is pure and has no session.
108
+ ...(session.sdkVersion === undefined ? {} : { sdkVersion: session.sdkVersion }),
103
109
  // Same rule as the act path: the caller named a consequence, so a settlement-only finding must
104
110
  // not override it. A fix that lived on one half of the verdict surface would leave the other
105
111
  // half broken, and this is the tool agents call most.
106
112
  declaredConsequence: predicate.kind !== PredicateKind.SETTLED,
107
113
  ...(declaresBodyIndependentChannel(predicate) ? { independentOfBody: true } : {}),
108
- ...(inconclusive === undefined ? {} : { inconclusive }),
109
- ...(true === observationLost ? { observationLost: true } : {}),
114
+ ...(effectiveInconclusive === undefined ? {} : { inconclusive: effectiveInconclusive }),
115
+ ...(true === observationLost ? { observationLost: true, lastUrl: session.url } : {}),
110
116
  ...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
117
+ ...(namedNetIsInFlight(predicate, stillInFlight) ? { namedRequestInFlight: true } : {}),
111
118
  honesty: buildHonestyBlock({
112
119
  grade: gradeOfPredicate(predicate),
113
120
  attribution: 'window',
@@ -143,7 +150,7 @@ changeUndeclared) {
143
150
  // contradiction, and "the window closed before the app finished" is no more actionable here.
144
151
  unsettled: {
145
152
  waitedFor: describeWaitTarget(predicate),
146
- stillInFlight: inFlightRequestLabels(windowEvents),
153
+ stillInFlight,
147
154
  repeated: repeatedRequestLabels(windowEvents),
148
155
  },
149
156
  });
@@ -158,6 +165,9 @@ changeUndeclared) {
158
165
  stateUnwatched: isStateUnwatched(spots),
159
166
  // What the app DECLARED, so an under-instrumented one is told without having to be asked.
160
167
  hasCapabilities: session.hasCapabilities,
168
+ // Whether the build TURNED the source stamp off, so a red with no file:line prescribes the
169
+ // right fix. `false` from the page is the only value that means anything; absent is unknown.
170
+ ...(false === session.sourceMapping ? { sourceMappingDisabled: true } : {}),
161
171
  domMutated: false,
162
172
  signalsFired: 0,
163
173
  routeChanged: false,
@@ -1,18 +1,19 @@
1
1
  import { carryReticleIdentity } from './lease-tools.js';
2
2
  import { z } from 'zod';
3
3
  import { navigateResult } from './navigate-result.js';
4
- import { awaitArrival } from './navigate-arrival.js';
4
+ import { awaitArrival, idsAtTarget, ARRIVAL_TIMEOUT_MS } from './navigate-arrival.js';
5
5
  import { reloadResult } from './reload-result.js';
6
6
  import { waitForReconnect, RELOAD_RECONNECT_TIMEOUT_MS } from '../session/session-reconnect.js';
7
7
  import { ReticleCommand } from '@reticlehq/core';
8
8
  import { ReticleTool } from './tool-names.js';
9
- import { asString } from './tools-helpers.js';
9
+ import { asNumber, asString } from './tools-helpers.js';
10
10
  import { sessionIdShape, commandOrThrow } from './tool-kit.js';
11
+ import { timeoutMsSchema } from './numeric-bounds.js';
11
12
  export const BROWSER_TOOLS = [
12
13
  {
13
14
  name: ReticleTool.NAVIGATE,
14
15
  example: { url: '/settings' },
15
- description: 'Navigate the connected browser tab to a URL, or reload it in place with { reload: true } (add { hard: true } to bypass the cache). `ok` means the navigation was DISPATCHED — the SDK is torn down by the navigation, so the page itself cannot report on it. The daemon then waits briefly for the SDK to reconnect: `confirmed:true` with a new `sessionId` means the page arrived and you can act immediately. `confirmed:false` means it did not arrive within the window — the page may be slow, uninstrumented, or not there; check reticle_sessions before acting.',
16
+ description: 'Navigate the connected browser tab to a URL, or reload it in place with { reload: true } (add { hard: true } to bypass the cache). `ok` means the navigation was DISPATCHED — the SDK is torn down by the navigation, so the page itself cannot report on it. The daemon then waits up to `timeout_ms` (default 5000) for the SDK to reconnect: `confirmed:true` with a new `sessionId` means the page arrived and you can act immediately. `confirmed:false` means it did not arrive within that window (reported as `waitedMs`) — the page may be slow, uninstrumented, or not there. A slow SPA can take 30-60s to reattach: raise `timeout_ms` rather than polling reticle_sessions.',
16
17
  inputSchema: {
17
18
  url: z.string().optional().describe('The URL to navigate to. Omit when using reload.'),
18
19
  reload: z
@@ -23,6 +24,9 @@ export const BROWSER_TOOLS = [
23
24
  .boolean()
24
25
  .optional()
25
26
  .describe('With reload:true, bypass the browser cache (Cmd+Shift+R). Default: false.'),
27
+ timeout_ms: timeoutMsSchema
28
+ .optional()
29
+ .describe('How long to wait for the page to come back (the SDK reconnecting at the new URL, or under the same id on a reload) before answering confirmed:false. Default 5000. 0 looks once without waiting. An SPA reattaching under HMR has been measured at 30-60s — say so here instead of polling reticle_sessions.'),
26
30
  ...sessionIdShape,
27
31
  },
28
32
  outputSchema: {
@@ -34,11 +38,19 @@ export const BROWSER_TOOLS = [
34
38
  confirmed: z.boolean().optional(),
35
39
  /** The session the SDK reconnected as, when arrival was confirmed — it is a NEW id. */
36
40
  sessionId: z.string().optional(),
41
+ /**
42
+ * On confirmed:false — the budget (ms) that expired without the page coming back. Says which
43
+ * of "Reticle stopped waiting" and "the page never came back" you are looking at.
44
+ */
45
+ waitedMs: z.number().optional(),
37
46
  note: z.string().optional(),
38
47
  },
39
48
  handler: async (deps, args) => {
40
49
  // reload:true is the absorbed reticle_refresh — same command, one fewer advertised tool.
41
50
  if (true === args['reload']) {
51
+ // The reload branch has its own default, sized for a cold dev-server rebuild; the caller's
52
+ // budget overrides it for the same reason it overrides the arrival wait below.
53
+ const timeoutMs = asNumber(args['timeout_ms']) ?? RELOAD_RECONNECT_TIMEOUT_MS;
42
54
  const before = deps.sessions.resolve(asString(args['sessionId']));
43
55
  // The verdict floor moves HERE, before the page goes away. A reload destroys the document,
44
56
  // so every request that failed under the old one belongs to a page that no longer exists —
@@ -56,14 +68,14 @@ export const BROWSER_TOOLS = [
56
68
  const back = await waitForReconnect({
57
69
  current: () => deps.sessions.get(before.id),
58
70
  previous: before,
59
- timeoutMs: RELOAD_RECONNECT_TIMEOUT_MS,
71
+ timeoutMs,
60
72
  now: deps.now,
61
73
  sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
62
74
  });
63
75
  // Not a bare `{ ok: true }`. The URL branch below already discloses that `ok` means
64
76
  // DISPATCHED — the reload branch had identical semantics and said nothing, on the path most
65
77
  // likely to need it. See reload-result.
66
- return reloadResult(back);
78
+ return reloadResult(back, timeoutMs);
67
79
  }
68
80
  const requested = asString(args['url']);
69
81
  if (requested === undefined || 0 === requested.length)
@@ -74,6 +86,10 @@ export const BROWSER_TOOLS = [
74
86
  // A leased tab is addressed by a URL param, so navigating away from it used to strand the
75
87
  // lease — see carryReticleIdentity. A tab that claims no identity is untouched.
76
88
  const url = carryReticleIdentity(session.url, requested);
89
+ // Sampled BEFORE dispatch, because that is the only moment it can be known. A session already
90
+ // sitting on the target is not evidence that THIS navigation arrived — and the arrival scan,
91
+ // which reads whatever is at the target afterwards, cannot tell the two apart on its own.
92
+ const priorIds = idsAtTarget(deps.sessions, url);
77
93
  session.beginAction(ReticleTool.NAVIGATE, { url });
78
94
  // Same floor as the reload path above, for the same reason: going to a new URL replaces the
79
95
  // document just as thoroughly. `beginAction` attributes events to this action; it does not move
@@ -83,9 +99,13 @@ export const BROWSER_TOOLS = [
83
99
  const result = (await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.NAVIGATE, { url }));
84
100
  // `ok` is the browser accepting the instruction, not the page arriving — see navigate-result.
85
101
  // The daemon is the only party that CAN see arrival (the SDK reconnects to it), so it looks,
86
- // briefly, instead of telling the agent to go poll reticle_sessions itself.
87
- const arrival = true === result.ok ? await awaitArrival(deps.sessions, url) : null;
88
- return navigateResult(result, arrival);
102
+ // for as long as the caller said to, instead of telling the agent to go poll
103
+ // reticle_sessions itself. A refusal skips the wait: there is nothing to wait FOR.
104
+ const timeoutMs = asNumber(args['timeout_ms']) ?? ARRIVAL_TIMEOUT_MS;
105
+ const arrival = true === result.ok
106
+ ? await awaitArrival(deps.sessions, url, { navigatedId: session.id, priorIds }, timeoutMs)
107
+ : null;
108
+ return navigateResult(result, arrival, timeoutMs);
89
109
  }
90
110
  finally {
91
111
  session.finishAction();
@@ -35,8 +35,8 @@ export declare const MAX_COMPLETION_READS = 12;
35
35
  */
36
36
  export declare const MAX_COMPLETION_DEPTH = 4;
37
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 {
38
+ type SnapshotReader = (scope: string | undefined) => Promise<unknown>;
39
+ interface CompletedRead {
40
40
  /** The union of every subtree that was read. Never a lie about what it contains — only about how much. */
41
41
  tree: string;
42
42
  /** True only when every branch the page cut was read back. A negative conclusion needs this. */
@@ -46,3 +46,4 @@ export interface CompletedRead {
46
46
  incompleteBecause?: string;
47
47
  }
48
48
  export declare function readCompleteTree(read: SnapshotReader): Promise<CompletedRead>;
49
+ export {};
@@ -245,5 +245,13 @@ export function buildDynamicTools(allTools, profile) {
245
245
  }
246
246
  },
247
247
  };
248
+ // The server instructions say, verbatim, "reticle_tools lists it, reticle_run calls it" — naming
249
+ // these two meta-tools as reachable through EACH OTHER, same as everything else on the surface.
250
+ // `byName` was built from `allTools` before either was constructed, so it never held them:
251
+ // `reticle_run { tool: "reticle_tools" }` — the exact discovery path the instructions document —
252
+ // answered "unknown tool 'reticle_tools'" (#876). Registered here, after both exist, so the
253
+ // dispatch this closure reads from (`byName.get`, evaluated lazily on each call) can find them.
254
+ byName.set(ReticleTool.TOOLS, reticleTools);
255
+ byName.set(ReticleTool.RUN, reticleRun);
248
256
  return [reticleTools, reticleRun];
249
257
  }
@@ -29,6 +29,16 @@ export declare const RECOVERY: {
29
29
  * carry: which of them to reach for, and that nothing was acted on.
30
30
  */
31
31
  readonly TARGET_MISSED: string;
32
+ /**
33
+ * The selector was underspecified, which is the caller's to fix and the same class as a miss.
34
+ *
35
+ * It reached the feedback ask for a punctuation reason: the text ends "pass an explicit `ref` from
36
+ * reticle_query.", and the catch-all excludes a `reticle_*` name followed by `.` so a module path
37
+ * in a stack trace stays an unanticipated crash. A tool named at the END of a sentence is
38
+ * indistinguishable from one under that rule, so the whole message fell through and told the
39
+ * caller their own ambiguous query might be a defect worth a root-cause report.
40
+ */
41
+ readonly AMBIGUOUS_TARGET: string;
32
42
  readonly NO_SUCH_OPTION: string;
33
43
  readonly BAD_ARGUMENTS: string;
34
44
  readonly WRONG_TARGET: string;
@@ -103,6 +103,20 @@ export const RECOVERY = {
103
103
  'acted on. Take a reticle_snapshot to see what is actually there (a view may still be ' +
104
104
  'rendering, or the control may be named differently), then retry with what it shows. This is ' +
105
105
  'a miss, not a Reticle defect: there is nothing to report.',
106
+ /**
107
+ * The selector was underspecified, which is the caller's to fix and the same class as a miss.
108
+ *
109
+ * It reached the feedback ask for a punctuation reason: the text ends "pass an explicit `ref` from
110
+ * reticle_query.", and the catch-all excludes a `reticle_*` name followed by `.` so a module path
111
+ * in a stack trace stays an unanticipated crash. A tool named at the END of a sentence is
112
+ * indistinguishable from one under that rule, so the whole message fell through and told the
113
+ * caller their own ambiguous query might be a defect worth a root-cause report.
114
+ */
115
+ AMBIGUOUS_TARGET: 'The call was valid and the selector matched SEVERAL elements, so nothing was acted on. Acting ' +
116
+ 'on one of them would report a verdict about an element you did not choose, which is the false ' +
117
+ 'green Reticle refuses to produce. The message above names each match: narrow the query with a ' +
118
+ 'role, name, testid or scope, or pass an explicit `ref` from reticle_query. This is an ' +
119
+ 'underspecified selector, not a Reticle defect: there is nothing to report.',
106
120
  NO_SUCH_OPTION: 'That <select> has no option with the value you asked for, and the message above lists the ones ' +
107
121
  'it does have. Reticle refuses rather than assigning it: an unmatched value deselects everything, ' +
108
122
  'and the change event that follows has been observed persisting an empty setting into the app. ' +
@@ -206,6 +220,9 @@ const REASON_OF = {
206
220
  STALE_REF_AFTER_EDIT: RefusalReason.NO_MATCH,
207
221
  NO_SUCH_OPTION: RefusalReason.NO_MATCH,
208
222
  TARGET_MISSED: RefusalReason.NO_MATCH,
223
+ // Target resolution failed to name one element. NO_MATCH rather than BAD_ARGS: the arguments were
224
+ // well-formed and the query simply did not identify a single node, same as a miss.
225
+ AMBIGUOUS_TARGET: RefusalReason.NO_MATCH,
209
226
  FLOW_STEP_MISSING: RefusalReason.NO_MATCH,
210
227
  UNSUPPORTED_SURFACE: RefusalReason.UNSUPPORTED,
211
228
  HOVER_NEEDS_POINTER: RefusalReason.UNSUPPORTED,
@@ -279,6 +296,12 @@ const RULES = [
279
296
  // agent to re-read arguments that were already correct costs it a turn, and this is the commonest
280
297
  // refusal there is.
281
298
  { match: /target matched no element/i, hint: RECOVERY.TARGET_MISSED },
299
+ // Also BEFORE the catch-all, and for the same reason the line above is: the caller's query is the
300
+ // thing to fix, so the answer must not be "re-read the tool's parameters" or a bug-report nudge.
301
+ {
302
+ match: /target matched \d+ elements and an action must not guess/i,
303
+ hint: RECOVERY.AMBIGUOUS_TARGET,
304
+ },
282
305
  // Authored by Reticle, about the caller's arguments: the message already names the valid answers.
283
306
  { match: /^unknown action '/i, hint: RECOVERY.BAD_ARGUMENTS },
284
307
  { match: /^unsupported query strategy '/i, hint: RECOVERY.BAD_ARGUMENTS },
@@ -12,7 +12,7 @@
12
12
  * tokens on that and not on politeness.
13
13
  */
14
14
  import { z } from 'zod';
15
- import { FeedbackKind, FeedbackSource, FEEDBACK_RATING_MAX, FEEDBACK_RATING_MIN, } from '@reticlehq/core';
15
+ import { FeedbackKind, FeedbackSource, FEEDBACK_RATING_MAX, FEEDBACK_RATING_MIN, } from '@reticlehq/core/telemetry';
16
16
  import { ReticleTool } from './tool-names.js';
17
17
  import { asNumber, asString } from './tools-helpers.js';
18
18
  import { submitFeedback, feedbackDisabled } from '../telemetry/feedback.js';
@@ -69,6 +69,8 @@ const REF_MINTING_TOOLS = new Set([
69
69
  ReticleTool.VERIFY,
70
70
  ]);
71
71
  export const SESSION_BOUND_TOOLS = new Set([
72
+ // Resolves a session and reads its event window (`session.eventsSince`), exactly as OBSERVE and
73
+ // NETWORK do. Without this it runs with no session and answers from nothing.
72
74
  ReticleTool.SNAPSHOT,
73
75
  ReticleTool.QUERY,
74
76
  ReticleTool.INSPECT,
@@ -9,6 +9,7 @@
9
9
  *
10
10
  * Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
11
11
  */
12
+ import { type SeedStorage } from '@reticlehq/core';
12
13
  import type { ToolDef } from './tool-kit.js';
13
14
  /** The origin of a URL, or undefined when it does not parse. */
14
15
  export declare function originOf(url: string): string | undefined;
@@ -17,12 +18,28 @@ export declare function originOf(url: string): string | undefined;
17
18
  * adopts them on connect. Pure; falls back to plain concatenation if the URL can't be parsed.
18
19
  */
19
20
  export declare function appendReticleParams(url: string, session: string, projectId?: string): string;
21
+ /**
22
+ * Scrub known secret shapes and raw seedStorage values (cookies, localStorage, sessionStorage)
23
+ * from an error string before it reaches daemon logs, metrics, or MCP error responses.
24
+ */
25
+ export declare function scrubSeedFromError(text: string, seed?: unknown): string;
20
26
  /**
21
27
  * Turn a raw navigation failure (Playwright's `page.goto: net::ERR_… at <url>\nCall log:…`, often
22
28
  * with ANSI codes) into a short, clean reason — so the agent/user sees "is the app running?" instead
23
29
  * of an internals-leaking wall of text.
24
30
  */
25
- export declare function cleanNavError(err: unknown): string;
31
+ export declare function cleanNavError(err: unknown, seed?: SeedStorage): string;
32
+ /**
33
+ * Determine if a required seedStorage application precondition failed.
34
+ *
35
+ * Checks strong signals:
36
+ * 1. HTTP 401/403 status on the initial navigation.
37
+ * 2. Cross-origin redirect when localStorage or sessionStorage was requested (skipped by origin-scoping).
38
+ * 3. Clear redirect to an authentication/login endpoint when the requested URL was not a login page.
39
+ *
40
+ * Normal app redirects (e.g. / → /dashboard) are valid and return undefined.
41
+ */
42
+ export declare function evaluateSeedPrecondition(requestedUrl: string, actualUrl: string | undefined, seed: SeedStorage, navStatus?: number): string | undefined;
26
43
  /**
27
44
  * The session a lease's tab actually registered as, or undefined while nothing has.
28
45
  *
@@ -57,6 +74,31 @@ export declare function resolveLeasedSessionId(sessions: {
57
74
  * a human's own URL.
58
75
  */
59
76
  export declare function carryReticleIdentity(fromUrl: string | undefined, toUrl: string): string;
77
+ /** The narrow slice of a session the probe needs. Anything that quacks like this works. */
78
+ interface ProbeableSession {
79
+ command?: (name: string, args: Record<string, unknown>, timeoutMs: number) => Promise<unknown>;
80
+ }
81
+ /**
82
+ * Does this tab still answer?
83
+ *
84
+ * `ready: true` used to mean "a row is in the sessions map", which is how a lease came back ready
85
+ * and was then rejected by `snapshot`, `state` and `console`. Presence is not liveness: the map
86
+ * still holds a tab that is attached, streaming events, and answering nothing (#692).
87
+ *
88
+ * ANY reply counts, including one that reports the command failed. The question is whether the SDK
89
+ * answers at all, not what it says — so an SDK too old to know the command replies
90
+ * `unknown command '…'`, and that is proof. Only the absence of a reply is evidence of absence:
91
+ * `PendingCommands.track` REJECTS on timeout and on a dropped socket, and resolves on every real
92
+ * answer, so the two cases are already separated for us.
93
+ *
94
+ * `CAPABILITIES` is the probe because it takes no arguments and returns a small fixed list. No new
95
+ * wire command is introduced: this rides an existing round trip.
96
+ *
97
+ * Fails OPEN. A registry entry with no `command` is a shape this code did not put there, and
98
+ * turning a lease that works into a refusal over a probe that could not run would be a worse
99
+ * failure than the one being fixed.
100
+ */
101
+ export declare function probeLeaseAlive(session: ProbeableSession | undefined, timeoutMs?: number): Promise<boolean>;
60
102
  /**
61
103
  * Poll until the leased tab's SDK has actually registered on the bridge, so the sessionId we return
62
104
  * is immediately usable (the page navigates first, then connects a moment later — without this wait
@@ -71,9 +113,11 @@ export declare function carryReticleIdentity(fromUrl: string | undefined, toUrl:
71
113
  export declare function acquireLeasedSession(pool: {
72
114
  acquire: (url: string, opts: {
73
115
  sessionId: string;
116
+ seedStorage?: SeedStorage;
74
117
  }) => Promise<{
75
118
  sessionId: string;
76
119
  release: () => Promise<void>;
120
+ navStatus?: number;
77
121
  }>;
78
122
  /**
79
123
  * The address this lease's page said it could not reach. Optional so a test double need not
@@ -88,28 +132,12 @@ export declare function acquireLeasedSession(pool: {
88
132
  id: string;
89
133
  url?: string;
90
134
  }[];
91
- }, url: string, projectId?: string): Promise<{
135
+ }, url: string, projectId?: string, seedStorage?: SeedStorage): Promise<{
92
136
  sessionId: string;
93
137
  release: () => Promise<void>;
94
138
  }>;
95
139
  export declare function waitForLeasedSession(isConnected: () => boolean, sleeper?: (ms: number) => Promise<void>, attempts?: number, pollMs?: number): Promise<boolean>;
96
- /**
97
- * Named on its own because `reticle drive <url>` runs it too.
98
- *
99
- * When a daemon already owns the bridge port, `drive` asks that daemon for a browser instead of
100
- * competing for the port (see cli/drive-attach.ts), and the browser it should get is exactly the one
101
- * an agent gets: same pool, same isolation, same reporting. Sharing the ToolDef rather than the
102
- * handler keeps that literal — the drive route dispatches through `runTool`, so it is counted like
103
- * any other call instead of being a second, invisible dispatch path.
104
- */
140
+ export declare function hasOriginLock(origin: string): boolean;
105
141
  export declare const LEASE_ACQUIRE_TOOL: ToolDef;
106
- /**
107
- * What to say when a lease was taken while a real tab was already open.
108
- *
109
- * Not a refusal. Leases are the highest-value path for autonomous work and an agent that genuinely
110
- * needs isolation must still get one — but a human watching their own tab cannot see a lease, so
111
- * when both exist the visible one is the better default and the agent should hear that here, where
112
- * it is choosing, rather than discover it when somebody asks why nothing is happening.
113
- */
114
- export declare const PREFER_EXISTING_NOTE = "a non-leased tab for this app was already connected \u2014 that is the one a human can see, and this lease is not. Unless you need an isolated context (a second identity, a clean profile, parallel flows), release this lease and drive that sessionId instead.";
115
142
  export declare const LEASE_TOOLS: ToolDef[];
143
+ export {};