@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
@@ -2,7 +2,7 @@
2
2
  * Generated file contents and copy-paste snippets for `reticle init`. Kept as named constants/builders
3
3
  * so the runner never inlines free strings.
4
4
  */
5
- import { RETICLE_DEFAULT_PORT, ReticleDir, bridgeWsUrl } from '@reticlehq/core';
5
+ import { RETICLE_DEFAULT_PORT, ReticleDir, bridgeWsUrl, RETICLE_CLIENT_HOST, RETICLE_WS_PATH, } from '@reticlehq/core';
6
6
  import { UiLibrary } from './detect.js';
7
7
  import { SERVER_VERSION } from '../version/server-version.js';
8
8
  /**
@@ -17,9 +17,9 @@ import { SERVER_VERSION } from '../version/server-version.js';
17
17
  *
18
18
  * jsDelivr rather than esm.sh, measured: a third of the requests and a third of the bytes for the
19
19
  * same result. `/+esm` is what makes it work, and the bare package URL does NOT: every file in
20
- * `dist` carries bare specifiers for `@reticlehq/core` and `@testing-library/dom`, so an unbundled
21
- * entry point dies on the first import. That is also why adding `unpkg`/`jsdelivr` fields to
22
- * package.json would not help.
20
+ * `dist` still carries bare workspace specifiers such as `@reticlehq/core`, so an unbundled entry
21
+ * point dies on the first import. That is also why adding `unpkg`/`jsdelivr` fields to package.json
22
+ * would not help.
23
23
  *
24
24
  * PINNED to this server's version on purpose. A floating import upgrades the page SDK underneath a
25
25
  * daemon that did not move, which is `version_skew` arriving by a route nothing checks.
@@ -132,38 +132,51 @@ export function nextReticleDevFile(port, projectId, testids = [], stores = [], f
132
132
  // Same rule as the Vite module: a store we found is registered outright, and the commented hint
133
133
  // survives only for the libraries we can name but not wire.
134
134
  const storeImports = found.map((s) => `import { ${s.ident} } from '${s.importPath}';`).join('\n');
135
+ // Eight spaces: nested inside useEffect → .then callback (see multiline shape below for #684).
135
136
  const storeBlock = found.length > 0
136
- ? found.map((s) => ` registerStore('${s.key}', ${s.ident});`).join('\n')
137
+ ? found.map((s) => ` registerStore('${s.key}', ${s.ident});`).join('\n')
137
138
  : 0 === stores.length
138
- ? ' // No state library detected. If you add one, register it here — see node_modules/@reticlehq/server/docs/usage.md.'
139
- : stores.map((h) => ` // import your store, then: ${h}`).join('\n');
139
+ ? ' // No state library detected. If you add one, register it here — see node_modules/@reticlehq/server/docs/usage.md.'
140
+ : stores.map((h) => ` // import your store, then: ${h}`).join('\n');
141
+ const registerNames = found.length > 0 ? ', registerStore' : '';
142
+ // Multiline connect + single blank after imports (#684): the one-line connect and the double blank
143
+ // both fail Prettier on a clean Next install.
140
144
  return `'use client';
141
145
  import { useEffect } from 'react';
142
- ${storeImports.length > 0 ? storeImports : ''}
143
-
146
+ ${storeImports.length > 0 ? `${storeImports}\n` : ''}
144
147
  /** Dev-only: connect Reticle + install the React adapter, after hydration. */
145
148
  export function ReticleDev() {
146
149
  useEffect(() => {
147
150
  if (process.env.NODE_ENV !== 'development') return;
148
- void import('@reticlehq/react').then(({ reticle, install, registerCapabilities${found.length > 0 ? ', registerStore' : ''} }) => {
149
- install();
150
- // Both provided by withReticle() in next.config. The bridge rejects a connect with no token;
151
- // the root makes source paths repo-relative instead of absolute.
152
- const token = process.env.NEXT_PUBLIC_RETICLE_TOKEN;
153
- const root = process.env.NEXT_PUBLIC_RETICLE_ROOT;
154
- reticle.connect({ ${fields}...(token ? { token } : {}), ...(root ? { root } : {}) });
151
+ void import('@reticlehq/react').then(
152
+ ({ reticle, install, registerCapabilities${registerNames} }) => {
153
+ install();
154
+ // Both provided by withReticle() in next.config. The bridge rejects a connect with no token;
155
+ // the root makes source paths repo-relative instead of absolute.
156
+ const token = process.env.NEXT_PUBLIC_RETICLE_TOKEN;
157
+ const root = process.env.NEXT_PUBLIC_RETICLE_ROOT;
158
+ // withReticle() finds the daemon serving this project on every dev-server start. It wins over
159
+ // any port written into this file at install time, so moving the daemon needs no edit here.
160
+ const url = process.env.NEXT_PUBLIC_RETICLE_URL;
161
+ reticle.connect({
162
+ ${fields}...(url ? { url } : {}),
163
+ ...(token ? { token } : {}),
164
+ ...(root ? { root } : {}),
165
+ });
155
166
 
156
- // ── Start with ONE flow. ──────────────────────────────────────────────────────────────────
157
- // Registering a store is the highest-value line here: it lets the agent check what the app
158
- // BELIEVES, not just what it rendered. Pass the STORE, not \`() => store.getState()\` — the store
159
- // form wires \`subscribe\` too, so every mutation emits a diff; the getter form is read-only.
167
+ // ── Start with ONE flow. ────────────────────────────────────────────────────────────────
168
+ // Registering a store is the highest-value line here: it lets the agent check what the app
169
+ // BELIEVES, not just what it rendered. Pass the STORE, not \`() => store.getState()\` — the
170
+ // store form wires \`subscribe\` too, so every mutation emits a diff; the getter form is
171
+ // read-only.
160
172
  ${storeBlock}
161
- registerCapabilities({
162
- testids: [${ids}],${0 === testids.length ? ' // none found; add data-testid to your key elements' : ''}
163
- signals: [], // names you pass to reticle.signal()
164
- stores: [${found.map((s) => `'${s.key}'`).join(', ')}], // the keys you registered above
165
- });
166
- });
173
+ registerCapabilities({
174
+ testids: [${ids}],${0 === testids.length ? ' // none found; add data-testid to your key elements' : ''}
175
+ signals: [], // names you pass to reticle.signal()
176
+ stores: [${found.map((s) => `'${s.key}'`).join(', ')}], // the keys you registered above
177
+ });
178
+ },
179
+ );
167
180
  }, []);
168
181
  return null;
169
182
  }
@@ -204,11 +217,51 @@ layoutPath) {
204
217
  ? `\n url: '${bridgeWsUrl(port)}',`
205
218
  : '';
206
219
  const id = projectId !== undefined && projectId.length > 0 ? `\n projectId: '${projectId}',` : '';
220
+ // Astro owns its Vite instance, so it has a build-time channel of its own: the same `define` that
221
+ // already inlines the token can inline the daemon URL, resolved every time the config is read —
222
+ // that is, on every `astro dev`. The port above is written once at install time and goes stale the
223
+ // moment the daemon moves; this does not.
224
+ //
225
+ // Needs the projectId to know WHICH daemon is ours. Without one there is nothing to match on, and
226
+ // adopting a daemon serving another project would report its state as this app's, so the whole
227
+ // block is omitted rather than made to guess.
228
+ const canDiscover = projectId !== undefined && projectId.length > 0;
229
+ // Interpolated from core rather than typed into the template: this is the same wire string
230
+ // `bridgeWsUrl` builds, and a generator that spells it out by hand is exactly how the four call
231
+ // sites that constant exists to unify drifted apart in the first place.
232
+ const RETICLE_CLIENT_HOST_LITERAL = `ws://${RETICLE_CLIENT_HOST}:`;
233
+ const urlHelper = canDiscover
234
+ ? `
235
+ // The live daemon serving THIS project, re-read on every \`astro dev\`. Same rule as the Vite and
236
+ // Next plugins: skip dead daemons, match on projectId, lowest port wins, '' when none matches.
237
+ function reticleUrl() {
238
+ const dir = process.env['RETICLE_PAIRING_TOKEN_DIR'] || join(homedir(), '.reticle');
239
+ let best;
240
+ try {
241
+ for (const file of readdirSync(dir)) {
242
+ if (!file.startsWith('daemon-') || !file.endsWith('.json')) continue;
243
+ let entry;
244
+ try { entry = JSON.parse(readFileSync(join(dir, file), 'utf8')); } catch { continue; }
245
+ if (entry.projectId !== '${projectId}') continue;
246
+ try { process.kill(entry.pid, 0); } catch { continue; }
247
+ if (best === undefined || entry.port < best) best = entry.port;
248
+ }
249
+ } catch { return ''; }
250
+ return best === undefined ? '' : '${RETICLE_CLIENT_HOST_LITERAL}' + best + '${RETICLE_WS_PATH}';
251
+ }
252
+ `
253
+ : '';
254
+ const urlDefine = canDiscover ? `\n __RETICLE_URL__: JSON.stringify(reticleUrl()),` : '';
255
+ const urlRead = canDiscover
256
+ ? `\n const url = typeof __RETICLE_URL__ !== 'undefined' ? __RETICLE_URL__ : '';`
257
+ : '';
258
+ // After the baked port, so the discovered one wins: later key in an object literal.
259
+ const urlSpread = canDiscover ? `\n ...(url.length > 0 ? { url } : {}),` : '';
207
260
  return `Astro renders its own HTML, so the connect goes in a page <script> and the pairing token is inlined by the config.
208
261
 
209
262
  1. In astro.config.mjs — inline the daemon's token and raise the build target:
210
263
 
211
- import { readFileSync } from 'node:fs';
264
+ import { readFileSync, readdirSync } from 'node:fs';
212
265
  import { homedir } from 'node:os';
213
266
  import { join } from 'node:path';
214
267
 
@@ -216,14 +269,14 @@ layoutPath) {
216
269
  const dir = process.env['RETICLE_PAIRING_TOKEN_DIR'] || join(homedir(), '.reticle');
217
270
  try { return readFileSync(join(dir, 'pairing-token'), 'utf8').trim(); } catch { return ''; }
218
271
  }
219
-
272
+ ${urlHelper}
220
273
  export default defineConfig({
221
274
  vite: {
222
275
  // Astro's default target down-levels the modern SDK bundle and fails on a destructuring transform.
223
276
  build: { target: 'es2022' },
224
277
  optimizeDeps: { esbuildOptions: { target: 'es2022' } },
225
278
  define: {
226
- __RETICLE_TOKEN__: JSON.stringify(reticleToken()),
279
+ __RETICLE_TOKEN__: JSON.stringify(reticleToken()),${urlDefine}
227
280
  // Without this, source pointers come back as absolute paths from YOUR machine — useless in a
228
281
  // report. Every other framework gets it from its build plugin; Astro owns its Vite instance.
229
282
  __RETICLE_ROOT__: JSON.stringify(process.cwd()),
@@ -236,16 +289,22 @@ ${layoutHost(layoutPath)}
236
289
  <script>
237
290
  if (import.meta.env.DEV) {
238
291
  const token = typeof __RETICLE_TOKEN__ !== 'undefined' ? __RETICLE_TOKEN__ : '';
239
- const root = typeof __RETICLE_ROOT__ !== 'undefined' ? __RETICLE_ROOT__ : '';
292
+ const root = typeof __RETICLE_ROOT__ !== 'undefined' ? __RETICLE_ROOT__ : '';${urlRead}
240
293
  const { reticle, install } = await import('@reticlehq/react');
241
294
  install();
242
- reticle.connect({${id}${extra}
295
+ reticle.connect({${id}${extra}${urlSpread}
243
296
  ...(token.length > 0 ? { token } : {}),
244
297
  ...(root.length > 0 ? { root } : {}),
245
298
  });
246
299
  }
247
300
  </script>
248
301
 
302
+ 3. In src/env.d.ts — declare the Vite define names so \`astro check\` can see them (create-astro's
303
+ default build runs check first, and without this it fails with Cannot find name '__RETICLE_TOKEN__'):
304
+
305
+ declare const __RETICLE_TOKEN__: string | undefined;
306
+ declare const __RETICLE_ROOT__: string | undefined;
307
+
249
308
  Start the daemon BEFORE \`astro dev\`, so the token file exists when the config is read. Until it does the token is empty and the page reloads once the daemon is up.`;
250
309
  }
251
310
  /**
@@ -14,5 +14,5 @@ export declare const VitePatchKind: {
14
14
  };
15
15
  export type VitePatchKind = PatchKind;
16
16
  type VitePatch = SourcePatch;
17
- export declare function patchViteConfig(source: string, port?: number): VitePatch;
17
+ export declare function patchViteConfig(source: string, port?: number, captureBodies?: boolean): VitePatch;
18
18
  export {};
@@ -8,30 +8,38 @@ import { PatchKind } from './patch-kind.js';
8
8
  export const VITE_IMPORT = "import { reticle } from '@reticlehq/vite-plugin';";
9
9
  const RETICLE_MARKER = '@reticlehq/vite-plugin';
10
10
  /**
11
- * The `reticle(...)` call — the bridge port so the injected connect targets it, and body capture.
11
+ * The `reticle(...)` call — the bridge port so the injected connect targets it.
12
12
  *
13
- * `captureNetworkBodies` is here rather than in the SDK's defaults, deliberately. Without it a write
14
- * that answers 2xx with a body nobody recorded grades `unknown / outcome_unread`, because a 200
15
- * describes the transport and not the result — so the single bug class this product exists to catch is
16
- * unreachable on a default install. Measured on a real payments UI: a refund posted rupees into a
17
- * paise field, the server answered 200 having refunded a hundredth of it, the page rendered the amount
18
- * the user had typed rather than the amount that came back, and every DOM-level check passed. An agent
19
- * asked to verify that flow had to edit the app's own vite config mid-task to see the payload, and
20
- * then tell its human to undo the edit.
13
+ * **`captureNetworkBodies` is OPT-IN.** It was written in by default, and the argument for that was
14
+ * a good one: without a body, a write that answers 2xx grades `unknown / outcome_unread`, because a
15
+ * 200 describes the transport and not the result. Measured on a real payments UI — a refund posted
16
+ * rupees into a paise field, the server answered 200 having refunded a hundredth of it, the page
17
+ * rendered the amount the user had typed, and every DOM-level check passed.
21
18
  *
22
- * Written into the USER'S config, not switched on inside the SDK, and the difference is the point. A
23
- * body is the one part of a request that routinely carries personal data: the credential classes are
24
- * redacted before anything is journalled — tokens, cookies, card numbers, cvv, ssn — but an address or
25
- * an email is not, and nothing here should decide that for someone silently. In the config it is one
26
- * visible line they can read, keep, or delete, and an SDK that updates underneath them never starts
27
- * recording more than it did yesterday.
19
+ * That argument justifies the CAPABILITY. It does not justify the default, and the distinction is
20
+ * what #705 is about. A healthcare workspace proxying authenticated API traffic through Vite ran
21
+ * `init`, and on the first drive their login tokens and patient payloads were in the daemon's
22
+ * buffer. The old comment here conceded the exact gap — "the credential classes are redacted ... but
23
+ * an address or an email is not, and nothing here should decide that for someone silently" — and
24
+ * then decided it for them, because writing the line into their config IS deciding. `init` is run
25
+ * unattended by an agent; the person who knows the data is sensitive is not in the room.
26
+ *
27
+ * So the default is off and the ways in are all deliberate:
28
+ * - `reticle init --capture-bodies` writes the line, for someone who has decided
29
+ * - `VITE_RETICLE_CAPTURE_BODIES=1` turns it on for ONE dev-server run, no config edit
30
+ * - adding the option by hand, which is what the tools tell you to do
31
+ *
32
+ * Nothing goes quiet in exchange. Every tool that needs a body already says so when it is missing
33
+ * and names the option — see honesty/uncaptured-bodies.ts, honesty/verified.ts, predicate-eval.ts
34
+ * and reconcile-tools.ts — so the capability is discovered at the moment it is wanted, by the person
35
+ * who wanted it, instead of being switched on before anyone has asked.
28
36
  */
29
- function reticlePluginCall(port) {
37
+ function reticlePluginCall(port, captureBodies) {
30
38
  const options = [
31
39
  ...(port === undefined ? [] : [`port: ${String(port)}`]),
32
- 'captureNetworkBodies: true',
40
+ ...(captureBodies ? ['captureNetworkBodies: true'] : []),
33
41
  ];
34
- return `reticle({ ${options.join(', ')} })`;
42
+ return 0 === options.length ? 'reticle()' : `reticle({ ${options.join(', ')} })`;
35
43
  }
36
44
  /** Matches the start of a `plugins: [` array literal. */
37
45
  const PLUGINS_ARRAY = /plugins\s*:\s*\[/;
@@ -66,35 +74,41 @@ function insertImport(source) {
66
74
  * what a formatter rewrites, turning a one-line install into a diff against the user's own style. A
67
75
  * single-line array needs the space, or the result reads `[reticle(),react()]`.
68
76
  */
69
- function insertPlugin(source, port) {
77
+ function insertPlugin(source, port, captureBodies) {
70
78
  return source.replace(PLUGINS_ARRAY, (match, _g, offset) => {
71
79
  const next = source[offset + match.length] ?? '';
72
80
  const separator = '' === next || /\s/.test(next) ? '' : ' ';
73
- return `${match}${reticlePluginCall(port)},${separator}`;
81
+ return `${match}${reticlePluginCall(port, captureBodies)},${separator}`;
74
82
  });
75
83
  }
76
84
  /**
77
85
  * Add a whole `plugins: [reticle()]` key to a config object that has none, matching the layout of
78
86
  * the object it lands in: a multi-line object gets its own indented line, a one-liner stays inline.
79
87
  */
80
- function insertPluginsKey(source, port) {
88
+ function insertPluginsKey(source, port, captureBodies) {
81
89
  return source.replace(CONFIG_OBJECT, (_match, prefix, offset) => {
82
90
  const rest = source.slice(offset + _match.length);
83
91
  const multiline = /^\s*\n/.test(rest);
84
92
  const indent = /^\s*\n(\s*)\S/.exec(rest)?.[1] ?? ' ';
85
- const key = `plugins: [${reticlePluginCall(port)}],`;
93
+ const key = `plugins: [${reticlePluginCall(port, captureBodies)}],`;
86
94
  return multiline ? `${prefix}{\n${indent}${key}` : `${prefix}{ ${key}`;
87
95
  });
88
96
  }
89
- export function patchViteConfig(source, port) {
97
+ export function patchViteConfig(source, port, captureBodies = false) {
90
98
  if (source.includes(RETICLE_MARKER)) {
91
99
  return { kind: VitePatchKind.ALREADY };
92
100
  }
93
101
  if (PLUGINS_ARRAY.test(source)) {
94
- return { kind: VitePatchKind.APPLY, code: insertImport(insertPlugin(source, port)) };
102
+ return {
103
+ kind: VitePatchKind.APPLY,
104
+ code: insertImport(insertPlugin(source, port, captureBodies)),
105
+ };
95
106
  }
96
107
  if (CONFIG_OBJECT.test(source)) {
97
- return { kind: VitePatchKind.APPLY, code: insertImport(insertPluginsKey(source, port)) };
108
+ return {
109
+ kind: VitePatchKind.APPLY,
110
+ code: insertImport(insertPluginsKey(source, port, captureBodies)),
111
+ };
98
112
  }
99
113
  return { kind: VitePatchKind.MANUAL, reason: NO_PLUGINS_REASON };
100
114
  }
@@ -1,16 +1,14 @@
1
+ import type { InitIo } from './run.js';
1
2
  /**
2
- * Which directories to look in for the app, when `reticle init` runs at a monorepo root.
3
+ * The file names that say what a directory IS, shared by everything that has to ask.
3
4
  *
4
- * This used to be the literal list `['apps', 'packages']`. Measured on a real repo with three Next
5
- * apps at `web/`, `admin/` and `space/`, it found none — so the redirect never fired, init ran
6
- * against the root, and it reported ✓ for writing `app/reticle-dev.tsx` into a directory Next never
7
- * compiles. A ⚠ tells a human to act; a ✓ tells them it is handled.
8
- *
9
- * A workspace DECLARES its packages, so that declaration is used first and directory names are not
10
- * guessed at all. Where nothing is declared, every top-level directory is a better candidate than two
11
- * hardcoded ones — filtered by the usual non-source suspects, and still subject to the `looksLikeApp`
12
- * check that follows, so a wrong guess here costs a `package.json` read.
5
+ * They lived in run.ts and are read from here now because `findWorkspaceApps` moved and needs them —
6
+ * one definition, imported in both directions of the question ("is this an app?" and "which app?").
13
7
  */
8
+ export declare const PACKAGE_JSON = "package.json";
9
+ export declare const PNPM_WORKSPACE = "pnpm-workspace.yaml";
10
+ export declare const VITE_CONFIG_CANDIDATES: string[];
11
+ export declare const NEXT_CONFIG_CANDIDATES: string[];
14
12
  interface WorkspaceSources {
15
13
  /** Raw contents of pnpm-workspace.yaml, when present. */
16
14
  pnpmWorkspace?: string;
@@ -20,4 +18,13 @@ interface WorkspaceSources {
20
18
  topLevelDirs?: readonly string[];
21
19
  }
22
20
  export declare function workspaceParents(sources: WorkspaceSources): string[];
21
+ /**
22
+ * App directories under a workspace root.
23
+ *
24
+ * Running `reticle init` at the repo root is what people actually do, and in a monorepo the app is a
25
+ * directory down — so init detected "no framework", printed a wall of manual HTML instructions, and
26
+ * would have installed the SDK into the ROOT package.json. It already walks UP for the lockfile, so
27
+ * it knows it is in a workspace; this is the matching walk DOWN.
28
+ */
29
+ export declare function findWorkspaceApps(io: Pick<InitIo, 'exists' | 'readFile' | 'listDirs'>): string[];
23
30
  export {};
@@ -1,3 +1,24 @@
1
+ import { DEV_SCRIPT_NAMES } from './dev-script.js';
2
+ /**
3
+ * The file names that say what a directory IS, shared by everything that has to ask.
4
+ *
5
+ * They lived in run.ts and are read from here now because `findWorkspaceApps` moved and needs them —
6
+ * one definition, imported in both directions of the question ("is this an app?" and "which app?").
7
+ */
8
+ export const PACKAGE_JSON = 'package.json';
9
+ export const PNPM_WORKSPACE = 'pnpm-workspace.yaml';
10
+ export const VITE_CONFIG_CANDIDATES = [
11
+ 'vite.config.ts',
12
+ 'vite.config.js',
13
+ 'vite.config.mjs',
14
+ 'vite.config.mts',
15
+ ];
16
+ export const NEXT_CONFIG_CANDIDATES = [
17
+ 'next.config.mjs',
18
+ 'next.config.js',
19
+ 'next.config.ts',
20
+ 'next.config.cjs',
21
+ ];
1
22
  /**
2
23
  * Which directories to look in for the app, when `reticle init` runs at a monorepo root.
3
24
  *
@@ -66,3 +87,92 @@ export function workspaceParents(sources) {
66
87
  : (sources.topLevelDirs ?? []).filter((d) => !d.startsWith('.') && !NEVER_A_PACKAGE.has(d));
67
88
  return [...new Set(candidates)];
68
89
  }
90
+ /**
91
+ * Which directories under this workspace are runnable apps.
92
+ *
93
+ * Moved here from run.ts, which was over the 1000-line cap and had carried a note saying it was at
94
+ * its cohesion limit. `library-path-boundary.test.ts` had already written down that this function
95
+ * "squats in init/ for historical reasons" — it is a general-purpose question about a repository's
96
+ * shape, next to `workspaceParents`, which answers the other half of it.
97
+ */
98
+ /** Deps that mark a directory as a runnable web app even when it has no bundler config file. */
99
+ const APP_DEPS = ['next', 'vite'];
100
+ function hasDevScript(pkgRaw) {
101
+ try {
102
+ const parsed = JSON.parse(pkgRaw);
103
+ const scripts = 'object' === typeof parsed && parsed !== null
104
+ ? parsed.scripts
105
+ : undefined;
106
+ if ('object' !== typeof scripts || null === scripts)
107
+ return false;
108
+ const named = scripts;
109
+ return DEV_SCRIPT_NAMES.some((n) => 'string' === typeof named[n] && '' !== named[n]);
110
+ }
111
+ catch {
112
+ // A manifest that will not parse says nothing either way, and this is a filter, not a verdict.
113
+ return false;
114
+ }
115
+ }
116
+ function looksLikeApp(dir, io) {
117
+ const pkgRaw = io.readFile(`${dir}/${PACKAGE_JSON}`);
118
+ if (null === pkgRaw)
119
+ return false;
120
+ const configs = [...VITE_CONFIG_CANDIDATES, ...NEXT_CONFIG_CANDIDATES];
121
+ if (configs.some((c) => io.exists(`${dir}/${c}`)))
122
+ return true;
123
+ // `next.config` is optional in Next, so the dependency list is the other half of the signal.
124
+ if (APP_DEPS.some((d) => pkgRaw.includes(`"${d}"`)))
125
+ return true;
126
+ // And the honest third: an app somebody can SERVE. Asking only for a bundler missed every app
127
+ // built on anything else — Remix, Astro, a plain node server — and in a monorepo missing it means
128
+ // init never redirects, wires the ROOT, and reports ✓ for files nothing compiles.
129
+ //
130
+ // A monorepo root has no dev script by design, and a package that can only be BUILT is not the app
131
+ // somebody is working in, so this stays a filter rather than matching every directory.
132
+ return hasDevScript(pkgRaw);
133
+ }
134
+ /**
135
+ * App directories under a workspace root.
136
+ *
137
+ * Running `reticle init` at the repo root is what people actually do, and in a monorepo the app is a
138
+ * directory down — so init detected "no framework", printed a wall of manual HTML instructions, and
139
+ * would have installed the SDK into the ROOT package.json. It already walks UP for the lockfile, so
140
+ * it knows it is in a workspace; this is the matching walk DOWN.
141
+ */
142
+ export function findWorkspaceApps(io) {
143
+ const found = [];
144
+ // A workspace DECLARES its packages; `['apps','packages']` was a guess that missed a real repo
145
+ // with three Next apps at web/, admin/ and space/ — and missing them meant init ran against the
146
+ // root and reported ✓ for a file Next never compiles. See workspace-apps.
147
+ const pkgRaw = io.readFile(PACKAGE_JSON);
148
+ let pkgWorkspaces;
149
+ try {
150
+ const parsed = null === pkgRaw ? undefined : JSON.parse(pkgRaw);
151
+ pkgWorkspaces =
152
+ 'object' === typeof parsed && parsed !== null
153
+ ? parsed.workspaces
154
+ : undefined;
155
+ }
156
+ catch {
157
+ pkgWorkspaces = undefined;
158
+ }
159
+ const parents = workspaceParents({
160
+ ...(null === io.readFile(PNPM_WORKSPACE)
161
+ ? {}
162
+ : { pnpmWorkspace: io.readFile(PNPM_WORKSPACE) ?? '' }),
163
+ ...(pkgWorkspaces === undefined ? {} : { pkgWorkspaces }),
164
+ topLevelDirs: io.listDirs('.'),
165
+ });
166
+ // A declared parent can itself BE the app (`workspaces: ["web"]`), so check both the directory and
167
+ // its children rather than assuming one level of nesting.
168
+ for (const parent of parents) {
169
+ if (looksLikeApp(parent, io))
170
+ found.push(parent);
171
+ for (const name of io.listDirs(parent)) {
172
+ const dir = `${parent}/${name}`;
173
+ if (looksLikeApp(dir, io))
174
+ found.push(dir);
175
+ }
176
+ }
177
+ return [...new Set(found)];
178
+ }
@@ -2,6 +2,7 @@ import { z } from 'zod';
2
2
  import { CDP_NO_PROVIDER_REASON, CDP_NO_PROVIDER_RECOMMENDATION } from '@reticlehq/core';
3
3
  import { ReticleTool } from '../tools/tool-names.js';
4
4
  import { sessionIdShape } from '../tools/tool-kit.js';
5
+ import { delayMsSchema, httpStatusSchema } from '../tools/numeric-bounds.js';
5
6
  import { asString } from '../tools/tools-helpers.js';
6
7
  function mockProvider(deps) {
7
8
  const p = deps.realInput;
@@ -13,14 +14,10 @@ const ruleShape = z.object({
13
14
  .min(1)
14
15
  .describe('Substring the request URL must contain, e.g. "/api/pay".'),
15
16
  method: z.string().optional().describe('Optional method filter (GET/POST/…), case-insensitive.'),
16
- status: z.number().int().optional().describe('Fulfill with this HTTP status (default 200).'),
17
+ status: httpStatusSchema.optional().describe('Fulfill with this HTTP status (default 200).'),
17
18
  body: z.string().optional().describe('Response body to fulfill with.'),
18
19
  contentType: z.string().optional().describe('Response content type (default application/json).'),
19
- delayMs: z
20
- .number()
21
- .int()
22
- .optional()
23
- .describe('Delay (ms) before fulfilling — simulate a slow API.'),
20
+ delayMs: delayMsSchema.optional().describe('Delay (ms) before fulfilling — simulate a slow API.'),
24
21
  abort: z
25
22
  .boolean()
26
23
  .optional()
@@ -171,6 +171,8 @@ export interface LaunchedProviderOptions {
171
171
  */
172
172
  onNetworkDetail?: (detail: NetworkDetail) => void;
173
173
  }
174
+ /** The only place the dynamic value import of Playwright lives for the launched (drive) path. */
175
+ export declare const launchedChromium: LaunchFn;
174
176
  /**
175
177
  * Launches and OWNS a Playwright Chromium, navigates it to `driveUrl`, then drives native
176
178
  * input on that page. Headless-capable so @reticlehq/test / CI can run hover/drag unattended.
@@ -1,3 +1,4 @@
1
+ import { chromiumLaunchOptions } from '../chromium-launch-options.js';
1
2
  import { gotoOptions } from '../pool/playwright-launcher.js';
2
3
  import { BrowserLaunchKind } from '@reticlehq/core';
3
4
  import { getSessionMetrics } from '../telemetry/session-metrics.js';
@@ -220,7 +221,7 @@ export class CdpRealInputProvider {
220
221
  }
221
222
  const INJECT_CONNECT_WAIT_MS = 8_000;
222
223
  /** The only place the dynamic value import of Playwright lives for the launched (drive) path. */
223
- const launchedChromium = async (headless) => {
224
+ export const launchedChromium = async (headless) => {
224
225
  let mod;
225
226
  try {
226
227
  mod = await import('playwright');
@@ -230,7 +231,7 @@ const launchedChromium = async (headless) => {
230
231
  }
231
232
  const settle = getSessionMetrics().recordConnectAttempt(BrowserLaunchKind.LAUNCHED);
232
233
  try {
233
- const browser = await mod.chromium.launch({ headless });
234
+ const browser = await mod.chromium.launch(chromiumLaunchOptions(headless));
234
235
  settle();
235
236
  return browser;
236
237
  }
@@ -301,8 +302,28 @@ export class LaunchedRealInputProvider {
301
302
  // No SDK on the page (or it connected already) — the no-session guard in verify reports it.
302
303
  }
303
304
  }
304
- isAvailableFor(sessionUrl) {
305
+ /**
306
+ * The page we own, or undefined once it is gone.
307
+ *
308
+ * The handle is cached for the life of the provider and Playwright keeps answering `url()` after
309
+ * the page has closed, so a closed window read as AVAILABLE and every method below threw
310
+ * "Target page, context or browser has been closed" — the raw Playwright message, surfaced to the
311
+ * agent as a tool error, on every call for the rest of the run. A dead page is the same fact as no
312
+ * page, and every caller already handles that. Only an EXPLICIT `true` drops it, matching
313
+ * `CdpRealInputProvider`'s `isConnected` check: a test fake without the method is assumed live.
314
+ */
315
+ #livePage() {
305
316
  const page = this.#page;
317
+ if (page === undefined)
318
+ return undefined;
319
+ if (true === page.isClosed?.()) {
320
+ this.#page = undefined; // never ask a corpse twice
321
+ return undefined;
322
+ }
323
+ return page;
324
+ }
325
+ isAvailableFor(sessionUrl) {
326
+ const page = this.#livePage();
306
327
  if (page === undefined)
307
328
  return Promise.resolve(false);
308
329
  if (page.url() === sessionUrl)
@@ -310,14 +331,14 @@ export class LaunchedRealInputProvider {
310
331
  return Promise.resolve(stripVolatile(page.url()) === stripVolatile(sessionUrl));
311
332
  }
312
333
  perform(_sessionUrl, action, box, args) {
313
- const page = this.#page;
334
+ const page = this.#livePage();
314
335
  if (page === undefined)
315
336
  return Promise.resolve({ performed: false, center: boxCenter(box) });
316
337
  return performGesture(page, action, box, args, this.#sleep);
317
338
  }
318
339
  /** PNG of the owned page, or undefined before navigate / after dispose. */
319
340
  screenshot(_sessionUrl, opts) {
320
- const page = this.#page;
341
+ const page = this.#livePage();
321
342
  if (page === undefined)
322
343
  return Promise.resolve(undefined);
323
344
  return capturePage(page, opts);
@@ -331,7 +352,7 @@ export class LaunchedRealInputProvider {
331
352
  * screenshots the whole time; only these two methods were missing.
332
353
  */
333
354
  async setViewport(_sessionUrl, size) {
334
- const page = this.#page;
355
+ const page = this.#livePage();
335
356
  if (page === undefined)
336
357
  return false;
337
358
  await page.setViewportSize({ width: size.width, height: size.height });
@@ -339,7 +360,7 @@ export class LaunchedRealInputProvider {
339
360
  }
340
361
  /** Apply network-mock rules to the owned page; false before navigate / after dispose. */
341
362
  async setMocks(_sessionUrl, rules) {
342
- const page = this.#page;
363
+ const page = this.#livePage();
343
364
  if (page === undefined)
344
365
  return false;
345
366
  await installNetworkMocks(page, rules);
@@ -36,10 +36,13 @@ export interface ScrollFindResult {
36
36
  note?: string;
37
37
  }
38
38
  /**
39
- * Reveal an element that a windowed/virtualized list has not mounted yet. Queries
40
- * once (it may already be visible), then scrolls the container ~one viewport at a time, re-querying
41
- * after each, until the element appears, the list ends, or the maxScrolls budget is spent. Pure
42
- * orchestration over the session command seam — fully unit-testable with a fake.
39
+ * Reveal an element that a windowed/virtualized list has not mounted yet. Queries once (it may
40
+ * already be visible), optionally jumps straight to a bisection estimate, then walks the container
41
+ * a viewport at a time re-querying after each step. Downward first; when the bottom is reached the
42
+ * walk TURNS AROUND and continues upward, because a list that is already scrolled to its end keeps
43
+ * its earlier rows mounted above the viewport and a downward-only search answered "exhausted" on
44
+ * its first step (#505). `exhausted` therefore means BOTH directions are spent, not "the bottom is
45
+ * here". Pure orchestration over the session command seam — fully unit-testable with a fake.
43
46
  */
44
47
  export declare function scrollToFind(session: ScrollFindSession, q: ScrollFindQuery, opts?: {
45
48
  maxScrolls?: number;