@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
@@ -1,23 +1,26 @@
1
1
  import { healthEnvelope } from '../session/session-health.js';
2
+ import { verifyNextBaton, SUPPRESS_VERIFY_NEXT_ENV } from './verify-next-baton.js';
2
3
  import { TelemetryActor, TelemetryEventKind, TRANSPORT_LIMITS, fingerprintFinding, } from '@reticlehq/core';
3
4
  import { getSessionMetrics } from '../telemetry/session-metrics.js';
4
5
  import { getTelemetry } from '../telemetry/telemetry.js';
5
6
  import { takeUpdateNudge } from '../update/update-nudge.js';
6
7
  import { takeVersionSkew } from '../version/version-nudge.js';
8
+ import { rewriteClosedAsSkew } from '../version/version-skew.js';
7
9
  import { noteToolCall } from '../daemon/daemon-usefulness.js';
8
10
  import { bugsInResult, routeOf } from '../telemetry/bug-found.js';
9
11
  import { noteToolServed, reportToolRefused } from '../telemetry/tool-refused.js';
10
12
  import { buildErrorPayload, refusalReasonFor } from './error-recovery.js';
11
13
  import { resultIsError } from '../mcp/mcp-is-error.js';
12
14
  import { verificationOf } from '../telemetry/verification-of.js';
13
- import { asString } from './tools-helpers.js';
15
+ import { asString, sessionIdFromArgs, spentRefFromArgs } from './tools-helpers.js';
14
16
  import { EnvelopeKey } from './tool-kit.js';
15
17
  import { ReticleTool } from './tool-names.js';
16
18
  import { takeFeedbackPrompt } from './feedback-tools.js';
17
19
  import { takeFeedbackUndelivered } from '../telemetry/feedback-delivery.js';
18
20
  import { noteRefsMinted, wrongTabRefusal } from '../session/ref-provenance.js';
21
+ import { CAPTURED_TOOLS, noteCapturedCall, noteToolDispatched, } from '../honesty/feature-capture.js';
19
22
  import { span } from '../trace.js';
20
- import { deltaForToolResult, impactSnapshot, initImpact, recordImpact, } from '../impact/impact-recorder.js';
23
+ import { defectForToolResult, deltaForToolResult, impactSnapshot, initImpact, recordImpact, } from '../impact/impact-recorder.js';
21
24
  import { frictionOf, inviteFor } from './feedback-invite.js';
22
25
  /**
23
26
  * The live-session tools whose result MUST carry the
@@ -35,6 +38,20 @@ const ACTION_TOOLS = new Set([
35
38
  ReticleTool.ACT_SEQUENCE,
36
39
  ReticleTool.ACT_AND_WAIT,
37
40
  ]);
41
+ /**
42
+ * Tools that go through Playwright CDP rather than the page SDK.
43
+ *
44
+ * Under version skew these fail with "Target page, context or browser has been closed" while every
45
+ * DOM tool against the same tab still works (#688). They are session-EXEMPT (own result contracts),
46
+ * so the bound-tool resolve above never runs for them — resolve again here so we can refuse with
47
+ * the skew sentence before Playwright lies about a closed page.
48
+ */
49
+ const CDP_TOOLS = new Set([
50
+ ReticleTool.SCREENSHOT,
51
+ ReticleTool.VISUAL_DIFF,
52
+ ReticleTool.NETWORK_MOCK,
53
+ ReticleTool.VIEWPORT,
54
+ ]);
38
55
  /**
39
56
  * Tools whose result hands the agent refs. The tab they were minted in is remembered, so the call
40
57
  * that spends one cannot be routed to a different tab without saying so — see ref-provenance.ts.
@@ -98,7 +115,13 @@ export const SESSION_EXEMPT_TOOLS = new Set([
98
115
  ReticleTool.FLOW_REPLAY, // returns its own FlowReplayResult contract (+ auto-records a run)
99
116
  ReticleTool.FLOW_SAVE_RECORDED, // reads the recording buffer, writes disk
100
117
  ReticleTool.FLOW_HEAL, // returns its own FlowHealResult contract
118
+ ReticleTool.INTENT, // reads/writes .reticle/intent.json; sessionId only picks the project
119
+ ReticleTool.CONTEXT, // folds the journal + intent ledger; must still answer when nothing is connected
101
120
  ReticleTool.PROJECT, // reads .reticle/project.json
121
+ // Reads the team's shared memory over HTTP; sessionId only resolves WHICH project's link file to
122
+ // use. It must answer with no tab connected — "what does this project know?" is a question an
123
+ // agent asks before it has opened anything.
124
+ ReticleTool.MEMORY,
102
125
  ReticleTool.RUN_EXPORT, // reads .reticle/runs/<id>.json (verification-run artifact)
103
126
  ReticleTool.SESSION, // merged lifecycle/human-channel family (tune/yield/end/resume/messages/review/narrate)
104
127
  ReticleTool.SCREENSHOT, // own contract; provider-driven, not a live-DOM-health read
@@ -283,7 +306,7 @@ export async function runTool(tool, deps, args) {
283
306
  getSessionMetrics().recordAction();
284
307
  const settleTiming = getSessionMetrics().startToolCall(tool.name, args);
285
308
  const startedAt = Date.now();
286
- const rawSessionId = asString(args['sessionId']);
309
+ const rawSessionId = sessionIdFromArgs(args);
287
310
  const bound = SESSION_BOUND_TOOLS.has(tool.name);
288
311
  // Resolve the session identity ONCE, up front, for a live-session tool. The lease heartbeat must
289
312
  // target the session the handler will ACTUALLY drive — which, when the agent omits sessionId, is the
@@ -292,7 +315,7 @@ export async function runTool(tool, deps, args) {
292
315
  // before the handler so a long ACT_AND_WAIT is protected for its whole duration; on failure leave it
293
316
  // to the handler to throw the canonical no-session error.
294
317
  let session;
295
- if (bound) {
318
+ if (bound || CDP_TOOLS.has(tool.name)) {
296
319
  try {
297
320
  session = deps.sessions.resolve(rawSessionId);
298
321
  }
@@ -300,6 +323,50 @@ export async function runTool(tool, deps, args) {
300
323
  session = undefined;
301
324
  }
302
325
  }
326
+ // CDP tools against a skewed session: refuse with the sentence reticle_sessions already knows,
327
+ // before Playwright invents a closed page. ready:true leases still hit this path.
328
+ if (session?.versionSkew !== undefined && CDP_TOOLS.has(tool.name)) {
329
+ const message = session.versionSkew;
330
+ reportRefusal(tool.name, message);
331
+ throw new Error(message);
332
+ }
333
+ // The read-only calls the journal never keeps, recorded HERE because this is the one dispatch
334
+ // point every call routes through — a second recording site is a second thing to forget, and this
335
+ // instrument exists precisely because nothing was recorded before. Recorded before the handler
336
+ // runs: a read dispatches no action, so the counter reads the same either side.
337
+ //
338
+ // `reticle_context` is session-EXEMPT, so `session` above is undefined for it and it needs its own
339
+ // lenient resolve. Failing that resolve is silent by design: a call made with nothing connected
340
+ // has no per-session ledger to land in, and an instrument must never be why a tool call fails.
341
+ //
342
+ // EVERY tool is counted here, not just the read set: which of the 70-odd names in the table an
343
+ // agent actually reaches for is the question a decision about cutting or consolidating the surface
344
+ // turns on, and it had no answer. `reticle_run` is the one exclusion, for the same reason
345
+ // `reportRefusal` and `bugsInResult` exclude it — its handler calls `runTool` on the real tool, so
346
+ // the inner call is already counted under the name that RAN, and counting the wrapper too would
347
+ // both double the total and hide the run-only tier behind a single wrapper name. That tier is
348
+ // precisely the one the decision hinges on. See honesty/tool-hit-rate.ts.
349
+ if (ReticleTool.RUN !== tool.name) {
350
+ let target = session;
351
+ if (target === undefined) {
352
+ try {
353
+ target = deps.sessions.resolve(rawSessionId);
354
+ }
355
+ catch {
356
+ target = undefined;
357
+ }
358
+ }
359
+ if (target !== undefined) {
360
+ noteToolDispatched(target, tool.name);
361
+ if (CAPTURED_TOOLS.has(tool.name)) {
362
+ const subject = asString(args['ref']) ?? asString(args['target']);
363
+ noteCapturedCall(target, {
364
+ tool: tool.name,
365
+ ...(subject === undefined ? {} : { subject }),
366
+ });
367
+ }
368
+ }
369
+ }
303
370
  // A ref that was handed out by a DIFFERENT tab, on a call that named no session. Refused here, at
304
371
  // the one point that knows both the ref and the tab resolution picked — the handler only learns
305
372
  // that the ref missed, and answers that with "the DOM re-rendered", which is a confident diagnosis
@@ -307,7 +374,7 @@ export async function runTool(tool, deps, args) {
307
374
  // the guessed tab and return a green about a page nobody asked about.
308
375
  if (session !== undefined) {
309
376
  const wrongTab = wrongTabRefusal({
310
- ref: asString(args['ref']),
377
+ ref: spentRefFromArgs(args),
311
378
  explicitSessionId: rawSessionId,
312
379
  chosenSessionId: session.id,
313
380
  connected: () => deps.sessions.list(),
@@ -334,7 +401,22 @@ export async function runTool(tool, deps, args) {
334
401
  // to the agent by the MCP boundary, and discarded. Reported here rather than at that boundary
335
402
  // because there are two of them (mcp.ts and the reticle_run hatch) and this is the one place both
336
403
  // go through — a third would otherwise be invisible from the day it was added.
337
- const message = error instanceof Error ? error.message : String(error);
404
+ //
405
+ // Under version skew, Playwright's "Target page has been closed" is the wrong cause (#688): the
406
+ // page is still dialled in. Prefer the session's skew sentence when we already know the pair is
407
+ // mismatched — including for tools that are not in CDP_TOOLS (real-input fallbacks that throw).
408
+ let skewText = session?.versionSkew;
409
+ if (skewText === undefined) {
410
+ try {
411
+ skewText = deps.sessions.resolve(rawSessionId).versionSkew;
412
+ }
413
+ catch {
414
+ skewText = undefined;
415
+ }
416
+ }
417
+ const rewritten = rewriteClosedAsSkew(error, skewText);
418
+ const toThrow = rewritten ?? error;
419
+ const message = toThrow instanceof Error ? toThrow.message : String(toThrow);
338
420
  reportRefusal(tool.name, message);
339
421
  // The invitation on THIS path is the one `buildErrorPayload` attaches when it does not recognise
340
422
  // the error, and it was never counted — so the denominator excluded the commonest friction there
@@ -343,7 +425,7 @@ export async function runTool(tool, deps, args) {
343
425
  if (tool.name !== ReticleTool.RUN && buildErrorPayload(message).feedback !== undefined) {
344
426
  getSessionMetrics().recordFeedbackPrompt();
345
427
  }
346
- throw error;
428
+ throw toThrow;
347
429
  }
348
430
  finally {
349
431
  // In a `finally` so a THROWN call still settles: otherwise every failing tool would leak a
@@ -369,11 +451,20 @@ export async function runTool(tool, deps, args) {
369
451
  // The user's own record of what Reticle did for them. Same chokepoint as everything else that
370
452
  // counts, for the same reason: a second recording site is a second thing to forget. Separate
371
453
  // store from telemetry - this one never leaves the machine.
372
- recordImpact(deltaForToolResult(raw, Date.now() - startedAt, resultIsError(raw)));
454
+ const finishedAt = Date.now();
455
+ const defect = defectForToolResult(raw, finishedAt);
456
+ // Which project's ledger this call belongs to. Resolved from the SESSION being driven, not from
457
+ // wherever the daemon happens to stand: one daemon serves many projects, and recording every
458
+ // call against its own cwd is how one app's verdicts ended up on another account's dashboard.
459
+ // Falls back to the daemon root when no session can be named, which is the old behaviour.
460
+ const artifactRoot = session?.artifactRoot ?? deps.reticleRoot;
461
+ recordImpact(deltaForToolResult(raw, finishedAt - startedAt, resultIsError(raw)), { ...(defect === undefined ? {} : { defect }) }, artifactRoot);
373
462
  // ...and the tab being driven is told, so the report is live rather than a thing you reload.
374
463
  // Optional-call, not optional-chain-on-the-object: a test double is a partial Session, and a
375
464
  // courtesy push must never be the reason a tool call throws.
376
- session?.pushImpact?.(impactSnapshot);
465
+ // Bound to THIS session's root: a tab must be shown its own project's numbers, not whichever
466
+ // project the daemon was started in.
467
+ session?.pushImpact?.(() => impactSnapshot(artifactRoot));
377
468
  if (resultIsError(raw))
378
469
  reportRefusal(tool.name, raw.error);
379
470
  else {
@@ -450,8 +541,27 @@ export async function runTool(tool, deps, args) {
450
541
  // verdict-less session in the field never called a verdict-producing tool ONCE;
451
542
  // the counter behind this already existed and was reported only to us. One-shot per abandoned
452
543
  // run, same discipline as the pool lease — a hint on every call is noise that gets tuned out.
544
+ // The A/B control, and the reason it exists as an env flag rather than a code edit.
545
+ //
546
+ // `verify_next` is described in this repo's own changelog as "the largest known lever on whether a
547
+ // session produces a verdict at all", and it has never been measured — it was once built, fired
548
+ // and silently dropped by schema-strict clients for a whole release, which is exactly what an
549
+ // unmeasured lever looks like from the inside. "The payload now arrives" and "the agent acts on
550
+ // it" are different claims and only the first was ever verified.
551
+ //
552
+ // Suppressing it for a control arm has to leave the ONLY difference being the baton: same build,
553
+ // same surface, same counters. So the nudge is still TAKEN (the counter still resets, so the
554
+ // one-shot cadence is identical) and only the envelope key is withheld.
555
+ const suppressBaton = '1' === process.env[SUPPRESS_VERIFY_NEXT_ENV];
453
556
  const unverified = getSessionMetrics().takeUnverifiedNudge();
454
- if (unverified !== undefined)
455
- envelope[EnvelopeKey.VERIFY_NEXT] = unverified;
557
+ // Carry the CALL, not just the sentence. The prose has to be translated back into arguments, and
558
+ // that translation is where agents were already going wrong — `until` omitted, action arguments
559
+ // flat instead of nested under `args`. `ref` and `action` come from the act that actually
560
+ // dispatched, so the suggestion is about the element the agent touched. See verify-next-baton.
561
+ if (unverified !== undefined && !suppressBaton)
562
+ // `lastAct` read defensively: this envelope is built on EVERY tool call, so a session shape
563
+ // without it would turn a missing field into a crash on the whole surface rather than a missing
564
+ // suggestion. The baton degrades to prose, which is what it carried before.
565
+ envelope[EnvelopeKey.VERIFY_NEXT] = verifyNextBaton(unverified, resolved.lastAct?.effect() ?? {});
456
566
  return Object.keys(envelope).length > 0 ? { ...result, ...envelope } : result;
457
567
  }
@@ -35,5 +35,15 @@ export interface LeaseEvidence {
35
35
  * reported as a marker that was not found.
36
36
  */
37
37
  sdkMarker?: boolean;
38
+ /**
39
+ * The websocket URL the leased page actually tried, read from its own console.
40
+ *
41
+ * The only per-page proof there is about where the dial WENT. `refusal` proves a dial arrived
42
+ * HERE; this proves where one was aimed, which is the strictly more useful fact when it was aimed
43
+ * somewhere else — the case in which no refusal exists to be recorded, because nothing arrived.
44
+ *
45
+ * Absent means the page said nothing, never that it dialled correctly.
46
+ */
47
+ dialledUrl?: string;
38
48
  }
39
49
  export declare function leaseNotConnectedHint(url: string, port: number, evidence?: LeaseEvidence): string;
@@ -45,9 +45,45 @@ function markerClause(sdkMarker) {
45
45
  'document, so a lazily-imported SDK can still be missed — but combined with the rest it ' +
46
46
  'points at a bundle that carries no Reticle at all, i.e. wiring that never took effect.';
47
47
  }
48
+ /**
49
+ * The port a websocket URL names, or undefined when it names none we can read.
50
+ *
51
+ * `ws://host/path` with no explicit port is deliberately undefined rather than defaulted to 80: a
52
+ * guessed port compared against the daemon's would manufacture a mismatch out of nothing, and this
53
+ * branch outranks every other cause. No answer is correct here; a plausible one is not.
54
+ */
55
+ function dialledPort(url) {
56
+ if (url === undefined)
57
+ return undefined;
58
+ try {
59
+ const port = new URL(url).port;
60
+ return '' === port ? undefined : Number(port);
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ }
48
66
  export function leaseNotConnectedHint(url, port, evidence = {}) {
49
67
  const opening = `the leased tab loaded ${url} but never dialled this daemon (port ${String(port)}).`;
50
68
  const marker = markerClause(evidence.sdkMarker);
69
+ // 0. The page told us where it dialled, and it was not here. Proof, and it outranks the refusal
70
+ // branch below: a refusal proves a dial reached THIS daemon, which is a fact about some page;
71
+ // this is a fact about the page in hand. When they disagree, the specific one wins.
72
+ //
73
+ // Neither side can reach this conclusion alone, which is why it went unsaid for so long. The
74
+ // page's own warning deliberately refuses to diagnose the daemon — from inside a browser a
75
+ // daemon that is absent and one that is unreachable are the same observation. The daemon cannot
76
+ // see a dial that never arrived. Put the address the page names beside the port the daemon is
77
+ // bound to and the ambiguity disappears.
78
+ const dialled = dialledPort(evidence.dialledUrl);
79
+ if (dialled !== undefined && dialled !== port) {
80
+ return (`${opening} The page dialled ${String(evidence.dialledUrl)} (port ${String(dialled)}) and ` +
81
+ `this daemon is on ${String(port)}, so the dial never reached it. Nothing about the app's ` +
82
+ `wiring is in question. Either start the daemon on ${String(dialled)}, or point the app at ` +
83
+ `${String(port)} — the app's port comes from its build config (\`.reticle.json\`, ` +
84
+ `RETICLE_PORT, or the build plugin's \`port\`), and \`VITE_RETICLE_WS_URL\` overrides it ` +
85
+ `outright.${marker} ${RELEASE}`);
86
+ }
51
87
  // 1. A recorded refusal. The only cause with proof behind it, so nothing outranks it.
52
88
  if (evidence.refusal !== undefined) {
53
89
  return `${opening} A dial DID arrive and was refused: ${evidence.refusal}${marker} ${RELEASE}`;
@@ -55,11 +91,24 @@ export function leaseNotConnectedHint(url, port, evidence = {}) {
55
91
  // 2. Nuxt, whose most likely cause differs from every other framework's and which `init` warns
56
92
  // about at install time — while this hint never mentioned it.
57
93
  const nuxt = evidence.framework?.toLowerCase() === NUXT ? ` ${NUXT_FIRST}` : '';
58
- // 3. Proven wiring. Blaming the port here is the self-contradiction this rewrite exists to end.
94
+ // 3. Proven PORT. Blaming the port here is the self-contradiction this rewrite exists to end —
95
+ // but "the wiring is correct" was a second claim, and it was not proven at all.
96
+ //
97
+ // `previouslyConnected` is scoped to project + port, never to the app. In a monorepo, or for
98
+ // anyone adding a second app, the thing that connected yesterday is a DIFFERENT app. Measured:
99
+ // an uninstrumented app driven in exactly that situation was told its wiring was correct, and
100
+ // handed four causes — a dev-mode guard, a stale dev server, a missing peer dependency, a
101
+ // non-localhost page — every one of which presupposes the SDK is already installed. It was
102
+ // not. That is the commonest failure there is, and `reticle init` appeared nowhere in the
103
+ // answer, because the only branch that mentions it is the one reached when nothing is known.
59
104
  if (true === evidence.previouslyConnected) {
60
- return (`${opening} An app for this project HAS connected on this port before, so the port and the ` +
61
- `wiring are both correct — what is failing is the SDK reaching initialise on the page.${nuxt}` +
62
- `${marker} ${REAL_CAUSES} ${RELEASE}`);
105
+ const notThisApp = true === evidence.sdkMarker
106
+ ? ''
107
+ : ' That may have been a DIFFERENT app, though: this one may carry no Reticle SDK at all, ' +
108
+ 'in which case run `reticle init` in ITS directory first — every cause below assumes the ' +
109
+ 'SDK is already installed.';
110
+ return (`${opening} An app for this project HAS connected on this port before, so the port is ` +
111
+ `proven.${notThisApp}${nuxt}${marker} ${REAL_CAUSES} ${RELEASE}`);
63
112
  }
64
113
  // 4. Wired, but never seen connect. Rank the real causes; keep the port differential last, where
65
114
  // the evidence for it actually sits.
@@ -1,14 +1,17 @@
1
1
  /**
2
2
  * Lease tools — the agent-facing surface of the BrowserPool.
3
3
  *
4
- * `reticle_lease_acquire` opens a fresh isolated headless context navigated to the app URL and returns
5
- * the sessionId the app's SDK will register (stamped via __reticle_session so the lease and the session
6
- * correlate 1:1). This is the "one of 10 flows" entry point: 10 agents acquire 10 leases, the pool
7
- * keeps them in ONE browser, capped and queued. `reticle_lease_release` frees the slot.
4
+ * `reticle_lease_acquire` opens an isolated headless context navigated to the app URL and returns
5
+ * the sessionId the app's SDK will register. A second acquire on the same origin reuses the live
6
+ * lease rather than minting another tab — that second tab used to poison default session resolution
7
+ * for the rest of the run. The parallel suite still mints via `acquireLeasedSession`, because ten
8
+ * flows on one origin need isolation on purpose.
8
9
  *
9
10
  * Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
10
11
  */
11
12
  import type { ToolDef } from './tool-kit.js';
13
+ /** The origin of a URL, or undefined when it does not parse. */
14
+ export declare function originOf(url: string): string | undefined;
12
15
  /**
13
16
  * Append Reticle identity params (__reticle_session, optional __reticle_project) to a URL so the app's own SDK
14
17
  * adopts them on connect. Pure; falls back to plain concatenation if the URL can't be parsed.
@@ -40,6 +43,20 @@ export declare function resolveLeasedSessionId(sessions: {
40
43
  url?: string;
41
44
  }[];
42
45
  }, leaseId: string): string | undefined;
46
+ /**
47
+ * Carry a claimed identity across a navigation.
48
+ *
49
+ * A LEASED tab is addressed by `__reticle_session` in its URL: that param is how the pool finds the
50
+ * context it opened, and — since succession was tightened — it is also the ONLY thing that lets the
51
+ * reconnecting document inherit the lease. `reticle_navigate` sent the caller's raw URL, so the very
52
+ * first navigation stripped the marker, the tab re-announced as an ordinary anonymous session, and
53
+ * the lease was orphaned: "no sessions are connected at all", with a browser window still open on
54
+ * screen. A leased browser that cannot survive being navigated is not a usable one.
55
+ *
56
+ * A tab that claims nothing is left exactly as it was — this must never bolt Reticle's params onto
57
+ * a human's own URL.
58
+ */
59
+ export declare function carryReticleIdentity(fromUrl: string | undefined, toUrl: string): string;
43
60
  /**
44
61
  * Poll until the leased tab's SDK has actually registered on the bridge, so the sessionId we return
45
62
  * is immediately usable (the page navigates first, then connects a moment later — without this wait
@@ -58,6 +75,11 @@ export declare function acquireLeasedSession(pool: {
58
75
  sessionId: string;
59
76
  release: () => Promise<void>;
60
77
  }>;
78
+ /**
79
+ * The address this lease's page said it could not reach. Optional so a test double need not
80
+ * implement it; the real pool always does.
81
+ */
82
+ dialFailureUrl?: (sessionId: string) => string | undefined;
61
83
  /** Optional so a test double need not implement it; the real pool always does. */
62
84
  alias?: (registeredId: string, leaseId: string) => void;
63
85
  }, sessions: {
@@ -81,5 +103,13 @@ export declare function waitForLeasedSession(isConnected: () => boolean, sleeper
81
103
  * any other call instead of being a second, invisible dispatch path.
82
104
  */
83
105
  export declare const LEASE_ACQUIRE_TOOL: ToolDef;
84
- export declare const LEASE_RELEASE_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.";
85
115
  export declare const LEASE_TOOLS: ToolDef[];