@reticlehq/server 2.4.0 → 2.6.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 (472) hide show
  1. package/SKILL.md +719 -0
  2. package/dist/bridge/auth-failure-reason.d.ts +19 -0
  3. package/dist/bridge/auth-failure-reason.js +29 -0
  4. package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
  5. package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
  6. package/dist/{bridge.d.ts → bridge/bridge.d.ts} +13 -1
  7. package/dist/{bridge.js → bridge/bridge.js} +95 -15
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +9 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +18 -10
  10. package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
  11. package/dist/capsule/capsule-store.d.ts +8 -3
  12. package/dist/capsule/capsule-store.js +7 -2
  13. package/dist/capsule/capsule.js +3 -3
  14. package/dist/capsule/causal-summary.d.ts +8 -0
  15. package/dist/capsule/causal-summary.js +22 -12
  16. package/dist/capsule/divergence.d.ts +9 -4
  17. package/dist/capsule/divergence.js +8 -8
  18. package/dist/capsule/predicate-to-links.js +11 -8
  19. package/dist/cli/cli-doctor.d.ts +1 -0
  20. package/dist/cli/cli-doctor.js +135 -0
  21. package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
  22. package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
  23. package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
  24. package/dist/cli/cli-launch.js +171 -0
  25. package/dist/cli/cli-parse-feedback.d.ts +31 -0
  26. package/dist/cli/cli-parse-feedback.js +56 -0
  27. package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +6 -19
  28. package/dist/{cli-parse.js → cli/cli-parse.js} +118 -81
  29. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
  30. package/dist/{cli-port.js → cli/cli-port.js} +9 -9
  31. package/dist/cli/cli-update-commands.d.ts +4 -0
  32. package/dist/cli/cli-update-commands.js +93 -0
  33. package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
  34. package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
  35. package/dist/cli/doctor-daemon-line.d.ts +37 -0
  36. package/dist/cli/doctor-daemon-line.js +35 -0
  37. package/dist/cli/port-holder.d.ts +43 -0
  38. package/dist/cli/port-holder.js +99 -0
  39. package/dist/cli.d.ts +2 -2
  40. package/dist/cli.js +302 -100
  41. package/dist/cloud/cloud-config.d.ts +0 -1
  42. package/dist/cloud/cloud-config.js +9 -9
  43. package/dist/cloud/cloud-sync.d.ts +1 -7
  44. package/dist/cloud/cloud-sync.js +12 -12
  45. package/dist/crawl/crawl-empty.d.ts +16 -0
  46. package/dist/crawl/crawl-empty.js +24 -0
  47. package/dist/crawl/crawl-tools.js +4 -1
  48. package/dist/crawl/crawl.js +26 -7
  49. package/dist/daemon/daemon-resilience.d.ts +73 -0
  50. package/dist/daemon/daemon-resilience.js +279 -0
  51. package/dist/daemon/daemon-usefulness.d.ts +61 -0
  52. package/dist/daemon/daemon-usefulness.js +62 -0
  53. package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
  54. package/dist/{daemon.js → daemon/daemon.js} +105 -48
  55. package/dist/daemon/heartbeat.d.ts +115 -0
  56. package/dist/daemon/heartbeat.js +141 -0
  57. package/dist/daemon/idle-grace.d.ts +32 -0
  58. package/dist/daemon/idle-grace.js +41 -0
  59. package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +23 -2
  60. package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +37 -6
  61. package/dist/daemon/port-presence.d.ts +76 -0
  62. package/dist/daemon/port-presence.js +93 -0
  63. package/dist/daemon/state-dir.d.ts +7 -0
  64. package/dist/daemon/state-dir.js +59 -0
  65. package/dist/daemon/unclean-predecessor.d.ts +23 -0
  66. package/dist/daemon/unclean-predecessor.js +27 -0
  67. package/dist/domain/domain-model.js +2 -2
  68. package/dist/events/body-failures.js +8 -8
  69. package/dist/events/contradictions.d.ts +1 -1
  70. package/dist/events/contradictions.js +60 -10
  71. package/dist/events/echo-mismatch.js +10 -10
  72. package/dist/events/event-filters.js +6 -6
  73. package/dist/events/json-salvage.d.ts +2 -1
  74. package/dist/events/json-salvage.js +6 -6
  75. package/dist/events/observed-in-window.d.ts +12 -0
  76. package/dist/events/observed-in-window.js +21 -0
  77. package/dist/events/predicate-eval.d.ts +53 -20
  78. package/dist/events/predicate-eval.js +179 -55
  79. package/dist/events/predicate-parse.d.ts +23 -0
  80. package/dist/events/predicate-parse.js +54 -0
  81. package/dist/events/predicate.d.ts +7 -2
  82. package/dist/events/predicate.js +126 -35
  83. package/dist/events/reconcile.js +5 -5
  84. package/dist/events/ring-buffer.js +2 -17
  85. package/dist/events/stale-response.js +6 -6
  86. package/dist/events/testid-near-miss.d.ts +22 -0
  87. package/dist/events/testid-near-miss.js +33 -0
  88. package/dist/events/unit-mismatch.js +8 -8
  89. package/dist/flows/affected-tools.js +19 -4
  90. package/dist/flows/affected.js +1 -1
  91. package/dist/flows/annotate-target.d.ts +1 -0
  92. package/dist/flows/annotate-target.js +20 -0
  93. package/dist/flows/annotate-tools.js +25 -3
  94. package/dist/flows/annotate.js +17 -4
  95. package/dist/flows/assertion-integrity.d.ts +2 -1
  96. package/dist/flows/assertion-tiers-store.d.ts +3 -66
  97. package/dist/flows/assertion-tiers-store.js +2 -2
  98. package/dist/flows/attributed-failure.d.ts +17 -0
  99. package/dist/flows/attributed-failure.js +20 -0
  100. package/dist/flows/buddy-status.d.ts +2 -1
  101. package/dist/flows/buddy-status.js +2 -2
  102. package/dist/flows/coverage.d.ts +3 -2
  103. package/dist/flows/coverage.js +2 -2
  104. package/dist/flows/decision.js +24 -9
  105. package/dist/flows/empty-flow.d.ts +6 -0
  106. package/dist/flows/empty-flow.js +24 -0
  107. package/dist/flows/flake-store.d.ts +0 -1
  108. package/dist/flows/flake-store.js +1 -1
  109. package/dist/flows/flake.d.ts +2 -1
  110. package/dist/flows/flake.js +2 -2
  111. package/dist/flows/flow-classify.js +12 -0
  112. package/dist/flows/flow-replay-run.js +4 -4
  113. package/dist/flows/flow-replay.d.ts +6 -8
  114. package/dist/flows/flow-replay.js +132 -48
  115. package/dist/flows/flow-report.js +1 -1
  116. package/dist/flows/flow-scope.d.ts +1 -6
  117. package/dist/flows/flow-step-runners.d.ts +26 -6
  118. package/dist/flows/flow-step-runners.js +156 -6
  119. package/dist/flows/flow-success.js +20 -15
  120. package/dist/flows/flow-tools.js +63 -21
  121. package/dist/flows/flows.js +15 -11
  122. package/dist/flows/gate.d.ts +4 -3
  123. package/dist/flows/gate.js +1 -1
  124. package/dist/flows/heal-run.d.ts +0 -8
  125. package/dist/flows/heal-run.js +5 -5
  126. package/dist/flows/heal.js +3 -3
  127. package/dist/flows/predicate-to-expect.d.ts +38 -0
  128. package/dist/flows/predicate-to-expect.js +95 -0
  129. package/dist/flows/replay.d.ts +16 -1
  130. package/dist/flows/replay.js +58 -22
  131. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  132. package/dist/flows/role-anchor-nearest.js +45 -0
  133. package/dist/flows/role-drift-reason.d.ts +20 -0
  134. package/dist/flows/role-drift-reason.js +39 -0
  135. package/dist/flows/server-verify.d.ts +1 -1
  136. package/dist/flows/server-verify.js +5 -5
  137. package/dist/flows/suite-flakes.d.ts +33 -0
  138. package/dist/flows/suite-flakes.js +32 -0
  139. package/dist/flows/verify-change-tools.js +32 -10
  140. package/dist/flows/verify-change-verdict.d.ts +15 -0
  141. package/dist/flows/verify-change-verdict.js +25 -0
  142. package/dist/flows/watch-batcher.d.ts +3 -2
  143. package/dist/honesty/already-true.d.ts +2 -0
  144. package/dist/honesty/already-true.js +31 -0
  145. package/dist/honesty/blind-spots.d.ts +35 -3
  146. package/dist/honesty/blind-spots.js +57 -12
  147. package/dist/honesty/honesty.d.ts +3 -2
  148. package/dist/honesty/honesty.js +4 -4
  149. package/dist/honesty/uncaptured-bodies.js +1 -1
  150. package/dist/honesty/unread-outcome.js +2 -2
  151. package/dist/honesty/verified.d.ts +31 -3
  152. package/dist/honesty/verified.js +64 -8
  153. package/dist/http-server.js +23 -7
  154. package/dist/hunt/hunt-report.d.ts +2 -1
  155. package/dist/hunt/hunt-report.js +2 -2
  156. package/dist/index.d.ts +9 -6
  157. package/dist/index.js +41 -25
  158. package/dist/init/agent-rules.d.ts +20 -1
  159. package/dist/init/agent-rules.js +64 -8
  160. package/dist/init/app-choice.d.ts +20 -0
  161. package/dist/init/app-choice.js +25 -0
  162. package/dist/init/astro-host.d.ts +21 -0
  163. package/dist/init/astro-host.js +27 -0
  164. package/dist/init/astro-patch.d.ts +16 -0
  165. package/dist/init/astro-patch.js +240 -0
  166. package/dist/init/capabilities.js +4 -1
  167. package/dist/init/cra.d.ts +50 -0
  168. package/dist/init/cra.js +106 -0
  169. package/dist/init/cursor.js +39 -4
  170. package/dist/init/desktop-doctor.d.ts +3 -2
  171. package/dist/init/desktop-doctor.js +4 -4
  172. package/dist/init/detect.d.ts +9 -2
  173. package/dist/init/detect.js +24 -5
  174. package/dist/init/mcp-clients.d.ts +81 -0
  175. package/dist/init/mcp-clients.js +248 -0
  176. package/dist/init/mcp-registered.d.ts +12 -0
  177. package/dist/init/mcp-registered.js +14 -0
  178. package/dist/init/mcp.d.ts +27 -2
  179. package/dist/init/mcp.js +40 -4
  180. package/dist/init/next-patch.d.ts +2 -4
  181. package/dist/init/next-patch.js +109 -19
  182. package/dist/init/node-io.js +29 -6
  183. package/dist/init/plan-framework.d.ts +16 -1
  184. package/dist/init/plan-framework.js +166 -8
  185. package/dist/init/plan.d.ts +85 -6
  186. package/dist/init/plan.js +196 -33
  187. package/dist/init/project-id.d.ts +5 -9
  188. package/dist/init/project-id.js +10 -22
  189. package/dist/init/run.d.ts +23 -1
  190. package/dist/init/run.js +338 -47
  191. package/dist/init/slash-command.d.ts +9 -0
  192. package/dist/init/slash-command.js +10 -1
  193. package/dist/init/snippets.d.ts +7 -10
  194. package/dist/init/snippets.js +44 -15
  195. package/dist/init/vite-config.js +1 -1
  196. package/dist/init/windows-quote.d.ts +38 -0
  197. package/dist/init/windows-quote.js +70 -0
  198. package/dist/init/workspace-apps.d.ts +23 -0
  199. package/dist/init/workspace-apps.js +68 -0
  200. package/dist/input/driven-redaction.js +1 -1
  201. package/dist/input/network-detail.js +8 -8
  202. package/dist/input/network-mock-tools.js +2 -2
  203. package/dist/input/network-mock.js +4 -4
  204. package/dist/input/real-input.js +8 -3
  205. package/dist/input/scroll-find.js +2 -2
  206. package/dist/input/scroll-tools.d.ts +0 -5
  207. package/dist/input/scroll-tools.js +11 -4
  208. package/dist/input/viewport-tools.js +2 -2
  209. package/dist/journal/ambient-store.d.ts +0 -2
  210. package/dist/journal/ambient-store.js +1 -1
  211. package/dist/journal/ambient.js +1 -1
  212. package/dist/journal/attach-journal.d.ts +2 -1
  213. package/dist/journal/deviation-report.js +6 -6
  214. package/dist/journal/deviation-service.js +1 -1
  215. package/dist/journal/envelope-store.d.ts +0 -2
  216. package/dist/journal/envelope-store.js +1 -1
  217. package/dist/journal/envelope.d.ts +2 -3
  218. package/dist/journal/envelope.js +3 -3
  219. package/dist/journal/journal-query.js +1 -1
  220. package/dist/journal/journal-recorder.d.ts +2 -1
  221. package/dist/journal/journal-recorder.js +2 -2
  222. package/dist/journal/rollups.js +9 -9
  223. package/dist/journal/session-end.d.ts +2 -1
  224. package/dist/journal/session-journal.js +4 -4
  225. package/dist/license/license.d.ts +0 -14
  226. package/dist/license/license.js +8 -8
  227. package/dist/log.d.ts +10 -0
  228. package/dist/log.js +11 -1
  229. package/dist/mcp/mcp-is-error.d.ts +13 -0
  230. package/dist/mcp/mcp-is-error.js +18 -0
  231. package/dist/mcp/mcp-outage.d.ts +32 -0
  232. package/dist/mcp/mcp-outage.js +55 -0
  233. package/dist/mcp/mcp-proxy.d.ts +134 -0
  234. package/dist/mcp/mcp-proxy.js +720 -0
  235. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  236. package/dist/{mcp.js → mcp/mcp.js} +139 -37
  237. package/dist/mcp/proxy-handshake.d.ts +3 -0
  238. package/dist/mcp/proxy-handshake.js +54 -0
  239. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  240. package/dist/mcp/proxy-lifecycle.js +70 -0
  241. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  242. package/dist/mcp/tool-catalog-cache.js +55 -0
  243. package/dist/oracles/propose-consequences.d.ts +2 -1
  244. package/dist/oracles/propose-consequences.js +16 -11
  245. package/dist/oracles/self-instrument.d.ts +2 -1
  246. package/dist/oracles/self-instrument.js +1 -1
  247. package/dist/phenomena/phenomena.js +3 -3
  248. package/dist/platform.d.ts +16 -0
  249. package/dist/platform.js +16 -0
  250. package/dist/pool/browser-pool.d.ts +9 -0
  251. package/dist/pool/browser-pool.js +38 -9
  252. package/dist/pool/playwright-launcher.d.ts +15 -2
  253. package/dist/pool/playwright-launcher.js +21 -2
  254. package/dist/project/fs-port.js +1 -1
  255. package/dist/project/project-tools.js +2 -2
  256. package/dist/runs/build-verification-run.js +1 -1
  257. package/dist/runs/repair-prompt.d.ts +0 -6
  258. package/dist/runs/repair-prompt.js +3 -3
  259. package/dist/runs/risk-classify.js +1 -1
  260. package/dist/runs/run-diff.d.ts +0 -2
  261. package/dist/runs/run-diff.js +3 -3
  262. package/dist/runs/run-tools.js +2 -2
  263. package/dist/runs/verification-sync.js +2 -2
  264. package/dist/runs/verify-http.js +1 -1
  265. package/dist/runs/verify-server.js +1 -1
  266. package/dist/session/attachment-history.d.ts +46 -0
  267. package/dist/session/attachment-history.js +65 -0
  268. package/dist/session/command-timeout.d.ts +11 -3
  269. package/dist/session/command-timeout.js +2 -2
  270. package/dist/session/control-envelope.d.ts +6 -0
  271. package/dist/session/control-envelope.js +7 -1
  272. package/dist/session/dev-server-probe.d.ts +13 -0
  273. package/dist/session/dev-server-probe.js +52 -0
  274. package/dist/session/last-act.d.ts +17 -3
  275. package/dist/session/last-act.js +16 -4
  276. package/dist/session/live-control-tools.js +7 -2
  277. package/dist/session/live-control.js +1 -1
  278. package/dist/session/looks-like-dev-server.d.ts +14 -0
  279. package/dist/session/looks-like-dev-server.js +25 -0
  280. package/dist/session/no-session-diagnosis.d.ts +45 -0
  281. package/dist/session/no-session-diagnosis.js +120 -0
  282. package/dist/session/no-session-watch.d.ts +21 -0
  283. package/dist/session/no-session-watch.js +69 -0
  284. package/dist/session/observed-state.d.ts +4 -0
  285. package/dist/session/observed-state.js +19 -1
  286. package/dist/session/output-budget.js +1 -1
  287. package/dist/session/pending-commands.js +1 -0
  288. package/dist/session/session-health.d.ts +8 -1
  289. package/dist/session/session-health.js +8 -7
  290. package/dist/session/session-info.d.ts +43 -8
  291. package/dist/session/session-info.js +46 -1
  292. package/dist/session/session-lease.d.ts +0 -11
  293. package/dist/session/session-lease.js +1 -1
  294. package/dist/session/session-manager.d.ts +6 -0
  295. package/dist/session/session-manager.js +124 -12
  296. package/dist/session/session-readiness.d.ts +1 -1
  297. package/dist/session/session-readiness.js +6 -1
  298. package/dist/session/session-reaper.js +1 -1
  299. package/dist/session/session-reconnect.d.ts +32 -0
  300. package/dist/session/session-reconnect.js +42 -0
  301. package/dist/session/session.d.ts +15 -2
  302. package/dist/session/session.js +77 -26
  303. package/dist/session/state-select.d.ts +1 -1
  304. package/dist/session/state-select.js +1 -1
  305. package/dist/status-payload.d.ts +19 -0
  306. package/dist/status-payload.js +11 -0
  307. package/dist/telemetry/argument-shape.js +10 -1
  308. package/dist/telemetry/browser-mode.d.ts +27 -0
  309. package/dist/telemetry/browser-mode.js +33 -0
  310. package/dist/telemetry/bug-found.d.ts +17 -21
  311. package/dist/telemetry/bug-found.js +120 -8
  312. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  313. package/dist/telemetry/cli-telemetry.js +27 -4
  314. package/dist/telemetry/crash-cause.d.ts +47 -0
  315. package/dist/telemetry/crash-cause.js +104 -0
  316. package/dist/telemetry/daemon-telemetry.d.ts +38 -1
  317. package/dist/telemetry/daemon-telemetry.js +37 -12
  318. package/dist/telemetry/dev-repo.js +4 -4
  319. package/dist/telemetry/error-class.d.ts +26 -0
  320. package/dist/telemetry/error-class.js +52 -0
  321. package/dist/telemetry/error-fingerprint.js +21 -2
  322. package/dist/telemetry/feedback-cli.d.ts +8 -3
  323. package/dist/telemetry/feedback-cli.js +52 -8
  324. package/dist/telemetry/feedback-context.d.ts +23 -6
  325. package/dist/telemetry/feedback-context.js +105 -5
  326. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  327. package/dist/telemetry/feedback-delivery.js +30 -0
  328. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  329. package/dist/telemetry/feedback-outbox.js +87 -0
  330. package/dist/telemetry/feedback.d.ts +22 -1
  331. package/dist/telemetry/feedback.js +67 -8
  332. package/dist/telemetry/git-facts.d.ts +7 -0
  333. package/dist/telemetry/git-facts.js +5 -5
  334. package/dist/telemetry/project-profile.js +2 -1
  335. package/dist/telemetry/session-metrics.d.ts +47 -3
  336. package/dist/telemetry/session-metrics.js +315 -15
  337. package/dist/telemetry/telemetry.d.ts +45 -2
  338. package/dist/telemetry/telemetry.js +150 -37
  339. package/dist/telemetry/verification-of.d.ts +22 -0
  340. package/dist/telemetry/verification-of.js +84 -0
  341. package/dist/tools/act-capsule.js +2 -2
  342. package/dist/tools/act-danger.d.ts +12 -0
  343. package/dist/tools/act-danger.js +20 -3
  344. package/dist/tools/act-helpers.js +4 -4
  345. package/dist/tools/act-tools.d.ts +0 -8
  346. package/dist/tools/act-tools.js +114 -118
  347. package/dist/tools/act-view.js +7 -7
  348. package/dist/tools/alias-args.d.ts +17 -0
  349. package/dist/tools/alias-args.js +25 -0
  350. package/dist/tools/assert-grade.js +9 -9
  351. package/dist/tools/assert-verdict.d.ts +9 -1
  352. package/dist/tools/assert-verdict.js +21 -6
  353. package/dist/tools/browser-tools.js +36 -11
  354. package/dist/tools/contract-tools.d.ts +0 -5
  355. package/dist/tools/contract-tools.js +27 -1
  356. package/dist/tools/coverage-identity.d.ts +34 -0
  357. package/dist/tools/coverage-identity.js +46 -0
  358. package/dist/tools/coverage-tools.js +10 -14
  359. package/dist/tools/dynamic-tools.d.ts +2 -1
  360. package/dist/tools/dynamic-tools.js +96 -19
  361. package/dist/tools/error-recovery.d.ts +34 -2
  362. package/dist/tools/error-recovery.js +255 -4
  363. package/dist/tools/feedback-invite.d.ts +48 -0
  364. package/dist/tools/feedback-invite.js +71 -0
  365. package/dist/tools/feedback-tools.d.ts +12 -1
  366. package/dist/tools/feedback-tools.js +28 -5
  367. package/dist/tools/invoke-tool.d.ts +0 -12
  368. package/dist/tools/invoke-tool.js +126 -33
  369. package/dist/tools/lease-hint.d.ts +17 -0
  370. package/dist/tools/lease-hint.js +24 -0
  371. package/dist/tools/lease-tools.js +6 -5
  372. package/dist/tools/merge-tools.d.ts +10 -1
  373. package/dist/tools/merge-tools.js +9 -3
  374. package/dist/tools/merged-name-redirect.d.ts +13 -0
  375. package/dist/tools/merged-name-redirect.js +55 -0
  376. package/dist/tools/navigate-arrival.d.ts +26 -0
  377. package/dist/tools/navigate-arrival.js +60 -0
  378. package/dist/tools/navigate-result.d.ts +31 -0
  379. package/dist/tools/navigate-result.js +38 -0
  380. package/dist/tools/observe-tools.js +72 -20
  381. package/dist/tools/observed-nothing.d.ts +25 -0
  382. package/dist/tools/observed-nothing.js +33 -0
  383. package/dist/tools/query-paginate.js +2 -2
  384. package/dist/tools/query-shape.d.ts +18 -0
  385. package/dist/tools/query-shape.js +39 -0
  386. package/dist/tools/read-tools.js +81 -20
  387. package/dist/tools/real-input-attempt.d.ts +28 -0
  388. package/dist/tools/real-input-attempt.js +93 -0
  389. package/dist/tools/reconcile-tools.js +7 -7
  390. package/dist/tools/reload-result.d.ts +14 -0
  391. package/dist/tools/reload-result.js +29 -0
  392. package/dist/tools/snapshot-delta.d.ts +4 -5
  393. package/dist/tools/snapshot-delta.js +0 -0
  394. package/dist/tools/tool-kit.d.ts +16 -0
  395. package/dist/tools/tool-surface.d.ts +83 -0
  396. package/dist/tools/tool-surface.js +217 -0
  397. package/dist/tools/tools-helpers.js +6 -6
  398. package/dist/tools/tools.d.ts +15 -0
  399. package/dist/tools/tools.js +53 -17
  400. package/dist/tools/unadvertised-help.d.ts +5 -0
  401. package/dist/tools/unadvertised-help.js +39 -0
  402. package/dist/trace.d.ts +69 -0
  403. package/dist/trace.js +150 -0
  404. package/dist/update/nudge-credit.d.ts +4 -0
  405. package/dist/update/nudge-credit.js +53 -0
  406. package/dist/update/sdk-sync.d.ts +21 -0
  407. package/dist/update/sdk-sync.js +42 -0
  408. package/dist/update/update-checker.js +3 -3
  409. package/dist/update/update-nudge.d.ts +63 -6
  410. package/dist/update/update-nudge.js +128 -15
  411. package/dist/update/updater.d.ts +1 -9
  412. package/dist/update/updater.js +13 -8
  413. package/dist/version/peer-announce.d.ts +4 -0
  414. package/dist/version/peer-announce.js +30 -0
  415. package/dist/{server-version.js → version/server-version.js} +5 -1
  416. package/dist/version/version-nudge.d.ts +28 -0
  417. package/dist/version/version-nudge.js +40 -0
  418. package/dist/version/version-skew.d.ts +66 -0
  419. package/dist/version/version-skew.js +71 -0
  420. package/dist/visual/visual-diff.js +2 -2
  421. package/dist/visual/visual-tools.js +4 -4
  422. package/docs/README.md +55 -0
  423. package/docs/agent-cheatsheet.md +85 -0
  424. package/docs/architecture.md +113 -0
  425. package/docs/benchmarks.md +255 -0
  426. package/docs/debugging.md +102 -0
  427. package/docs/deploy-checks.md +69 -0
  428. package/docs/desktop-apps.md +256 -0
  429. package/docs/enterprise.md +62 -0
  430. package/docs/fixtures-dispatch-receiver.yml +76 -0
  431. package/docs/fixtures.md +45 -0
  432. package/docs/flows.md +166 -0
  433. package/docs/gate-plan.md +98 -0
  434. package/docs/gates.md +117 -0
  435. package/docs/getting-started.md +469 -0
  436. package/docs/human-control.md +63 -0
  437. package/docs/integration-patterns.md +171 -0
  438. package/docs/local-registry.md +126 -0
  439. package/docs/matrix/2.5.0/claude-code-machine.json +19 -0
  440. package/docs/matrix/2.5.0/codex-machine.json +20 -0
  441. package/docs/matrix/2.5.0/cursor-machine.json +22 -0
  442. package/docs/matrix/2.5.0/gemini-machine.json +22 -0
  443. package/docs/matrix/2.5.0/opencode-machine.json +22 -0
  444. package/docs/matrix/2.5.0/vscode-machine.json +22 -0
  445. package/docs/matrix/2.5.0/windsurf-machine.json +22 -0
  446. package/docs/matrix/MATRIX.md +26 -0
  447. package/docs/matrix/README.md +59 -0
  448. package/docs/mint.json +61 -0
  449. package/docs/multi-agent-testing.md +55 -0
  450. package/docs/platform-integration.md +122 -0
  451. package/docs/system-map.md +152 -0
  452. package/docs/telemetry-contract.md +214 -0
  453. package/docs/telemetry.md +191 -0
  454. package/docs/testing.md +82 -0
  455. package/docs/token-efficiency.md +80 -0
  456. package/docs/usage.md +1046 -0
  457. package/package.json +8 -5
  458. package/dist/cli-doctor.d.ts +0 -6
  459. package/dist/cli-doctor.js +0 -60
  460. package/dist/cli-launch.js +0 -112
  461. package/dist/daemon-resilience.d.ts +0 -22
  462. package/dist/daemon-resilience.js +0 -85
  463. package/dist/mcp-proxy.d.ts +0 -67
  464. package/dist/mcp-proxy.js +0 -337
  465. package/dist/tools/profiles.d.ts +0 -37
  466. package/dist/tools/profiles.js +0 -139
  467. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  468. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  469. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  470. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  471. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  472. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -15,19 +15,16 @@ export declare function nextConfigManual(configFile: string): string;
15
15
  * setup ended at `bridge refused the connection: authentication failed` and no session ever appeared.
16
16
  */
17
17
  export declare function nextReticleDevFile(port: number | undefined, projectId?: string, testids?: readonly string[], stores?: readonly string[]): string;
18
+ export declare function astroManual(port: number | undefined, projectId?: string,
18
19
  /**
19
- * Astro connect instructions.
20
+ * A layout file that actually exists, when one does.
20
21
  *
21
- * Astro is Vite-based but SSRs its own HTML, so the plugin's index.html injection never fires, and
22
- * `vite` is not a direct dependency — so this used to fall through to the generic HTML advice, which
23
- * tells you to add a connect to an "entry module" Astro does not have, or to bundle the SDK with
24
- * esbuild. Both are wrong for Astro, and following either gets you nothing.
25
- *
26
- * Astro bundles a page `<script>`, so the bare import resolves there. The token has to be inlined by
27
- * the config because there is no plugin in the page's path to inject it, and `build.target` has to be
28
- * raised or Astro down-levels the modern SDK bundle and dies on a destructuring transform.
22
+ * Reported from the field: on `examples/framework-react` — which has no layout at all, only
23
+ * `src/pages/index.astro` — init printed thirty lines telling the user to paste into "your
24
+ * layout". Instructions that name a file the project does not have read as a mistake by the
25
+ * reader, and cost them the time it takes to go and confirm it is missing.
29
26
  */
30
- export declare function astroManual(port: number | undefined, projectId?: string): string;
27
+ layoutPath?: string): string;
31
28
  /**
32
29
  * The app-side dev module the Vite plugin imports by convention.
33
30
  *
@@ -47,9 +47,9 @@ export function nextConfigManual(configFile) {
47
47
  */
48
48
  export function nextReticleDevFile(port, projectId, testids = [], stores = []) {
49
49
  const base = connectArg(port, projectId);
50
- const fields = base === '' ? '' : `${base.slice(1, -1).trim()}, `;
50
+ const fields = '' === base ? '' : `${base.slice(1, -1).trim()}, `;
51
51
  const ids = testids.map((t) => `'${t}'`).join(', ');
52
- const storeBlock = stores.length === 0
52
+ const storeBlock = 0 === stores.length
53
53
  ? ' // No state library detected. If you add one, register it here — see docs/usage.md.'
54
54
  : stores.map((h) => ` // import your store, then: ${h}`).join('\n');
55
55
  return `'use client';
@@ -73,7 +73,7 @@ export function ReticleDev() {
73
73
  // form wires \`subscribe\` too, so every mutation emits a diff; the getter form is read-only.
74
74
  ${storeBlock}
75
75
  registerCapabilities({
76
- testids: [${ids}],${testids.length === 0 ? ' // none found — add data-testid to your key elements' : ''}
76
+ testids: [${ids}],${0 === testids.length ? ' // none found — add data-testid to your key elements' : ''}
77
77
  signals: [], // names you pass to reticle.signal()
78
78
  stores: [], // the keys you registered above
79
79
  });
@@ -95,8 +95,28 @@ ${storeBlock}
95
95
  * the config because there is no plugin in the page's path to inject it, and `build.target` has to be
96
96
  * raised or Astro down-levels the modern SDK bundle and dies on a destructuring transform.
97
97
  */
98
- export function astroManual(port, projectId) {
99
- const extra = port !== undefined && port !== RETICLE_DEFAULT_PORT ? `\n url: '${bridgeWsUrl(port)}',` : '';
98
+ /**
99
+ * Name the file the connect <script> should go in — the layout when one exists, otherwise the page,
100
+ * because a project with no layout has nowhere else to put it and should not be told otherwise.
101
+ */
102
+ function layoutHost(layoutPath) {
103
+ return layoutPath === undefined
104
+ ? '2. This project has no layout, so put it in the page you want instrumented (e.g.\n src/pages/index.astro) — every page you want a session from needs it — inside <body>:'
105
+ : `2. In ${layoutPath} (or any other page you want instrumented), inside <body>:`;
106
+ }
107
+ export function astroManual(port, projectId,
108
+ /**
109
+ * A layout file that actually exists, when one does.
110
+ *
111
+ * Reported from the field: on `examples/framework-react` — which has no layout at all, only
112
+ * `src/pages/index.astro` — init printed thirty lines telling the user to paste into "your
113
+ * layout". Instructions that name a file the project does not have read as a mistake by the
114
+ * reader, and cost them the time it takes to go and confirm it is missing.
115
+ */
116
+ layoutPath) {
117
+ const extra = port !== undefined && port !== RETICLE_DEFAULT_PORT
118
+ ? `\n url: '${bridgeWsUrl(port)}',`
119
+ : '';
100
120
  const id = projectId !== undefined && projectId.length > 0 ? `\n projectId: '${projectId}',` : '';
101
121
  return `Astro renders its own HTML, so the connect goes in a page <script> and the pairing token is inlined by the config.
102
122
 
@@ -125,7 +145,7 @@ export function astroManual(port, projectId) {
125
145
  },
126
146
  });
127
147
 
128
- 2. In your layout (or the page you want instrumented), inside <body>:
148
+ ${layoutHost(layoutPath)}
129
149
 
130
150
  <script>
131
151
  if (import.meta.env.DEV) {
@@ -153,7 +173,7 @@ Start the daemon BEFORE \`astro dev\`, so the token file exists when the config
153
173
  */
154
174
  export function viteDevModuleFile(testids, stores) {
155
175
  const ids = testids.map((t) => `'${t}'`).join(', ');
156
- const storeBlock = stores.length === 0
176
+ const storeBlock = 0 === stores.length
157
177
  ? ' // No state library detected. If you add one, register it here — see docs/usage.md.'
158
178
  : stores.map((h) => ` // import your store, then: ${h}`).join('\n');
159
179
  return `// Dev-only. Imported automatically by @reticlehq/vite-plugin — you do not need to import it.
@@ -173,7 +193,7 @@ if (import.meta.env.DEV) {
173
193
  ${storeBlock}
174
194
 
175
195
  registerCapabilities({
176
- testids: [${ids}],${testids.length === 0 ? ' // none found — add data-testid to your key elements' : ''}
196
+ testids: [${ids}],${0 === testids.length ? ' // none found — add data-testid to your key elements' : ''}
177
197
  signals: [], // names you pass to reticle.signal()
178
198
  stores: [], // the keys you registered above
179
199
  });
@@ -203,10 +223,11 @@ export function htmlManual(port, projectId) {
203
223
  • Bundled app (Create React App, webpack, Parcel, Vue/Svelte CLI, etc.) — add to your ENTRY module
204
224
  (e.g. src/index.js or src/main.js), where '@reticlehq/react' resolves through your bundler:
205
225
 
206
- if (location.hostname === 'localhost') {
207
- const { reticle, install } = await import('@reticlehq/react');
208
- install();
209
- reticle.connect(${arg});
226
+ if (window.location.hostname === 'localhost') {
227
+ void import('@reticlehq/react').then(({ reticle, install }) => {
228
+ install();
229
+ reticle.connect(${arg});
230
+ });
210
231
  }
211
232
 
212
233
  • Plain static HTML with no build step — the browser can't resolve the bare '@reticlehq/react' import, so
@@ -226,7 +247,7 @@ export const SVELTEKIT_HOOKS_PATH = 'src/hooks.client.ts';
226
247
  * here is the one thing this project exists not to do.
227
248
  */
228
249
  export function unverifiedUiLibraryNote(library) {
229
- return `Detected a ${library} app. Reticle's DOM, network, console and state tools work here, but @reticlehq/react is a React adapter: component names and data-reticle-source file:line will be missing, and no CI gate covers ${library}. Gated today: Vite + React, Next.js, Remix, Astro. If something doesn't work, please open an issue.`;
250
+ return `Detected a ${library} app. Reticle's DOM, network, console and state tools work here, and source file:line does too — the build plugin stamps data-reticle-source regardless of UI library (measured on preact and svelte). What @reticlehq/react adds and you will NOT get is React component identity: component names and component stacks. No CI gate covers ${library}. Gated today: Vite + React, Next.js, Remix, Astro. If something doesn't work, please open an issue.`;
230
251
  }
231
252
  export const UNVERIFIED_FRAMEWORK_NOTE = 'Reticle has no SvelteKit app and no CI gate for one, so this wiring is untested — it may work, but nothing proves it and nothing will tell us if it breaks. Supported and gated today: Vite + React, Next.js, Remix and Astro. If the hook does not register a session, please open an issue.';
232
253
  /**
@@ -236,7 +257,7 @@ export const UNVERIFIED_FRAMEWORK_NOTE = 'Reticle has no SvelteKit app and no CI
236
257
  */
237
258
  export function svelteKitHooksFile(port, projectId) {
238
259
  const base = connectArg(port, projectId);
239
- const fields = base === '' ? '' : `${base.slice(1, -1).trim()}, `;
260
+ const fields = '' === base ? '' : `${base.slice(1, -1).trim()}, `;
240
261
  return `// Dev-only: connect Reticle on the client. SvelteKit renders via app.html, so the Vite-plugin
241
262
  // index.html injection doesn't fire — connect from this client hook instead.
242
263
  if (import.meta.env.DEV) {
@@ -246,11 +267,19 @@ if (import.meta.env.DEV) {
246
267
  // file it lives in, so @reticlehq/vite-plugin inlines it here at build time. Without it the
247
268
  // console reads "bridge refused the connection: authentication failed" and no session appears.
248
269
  const token = typeof __RETICLE_TOKEN__ !== 'undefined' ? __RETICLE_TOKEN__ : '';
249
- reticle.connect({ ${fields}...(token.length > 0 ? { token } : {}) });
270
+ const root = typeof __RETICLE_ROOT__ !== 'undefined' ? __RETICLE_ROOT__ : '';
271
+ const sdkVersion = typeof __RETICLE_SDK_VERSION__ !== 'undefined' ? __RETICLE_SDK_VERSION__ : '';
272
+ reticle.connect({
273
+ ${fields}...(token.length > 0 ? { token } : {}),
274
+ ...(root.length > 0 ? { root } : {}),
275
+ ...(sdkVersion.length > 0 ? { sdkVersion } : {}),
276
+ });
250
277
  });
251
278
  }
252
279
 
253
280
  declare const __RETICLE_TOKEN__: string | undefined;
281
+ declare const __RETICLE_ROOT__: string | undefined;
282
+ declare const __RETICLE_SDK_VERSION__: string | undefined;
254
283
  `;
255
284
  }
256
285
  /**
@@ -37,7 +37,7 @@ function insertImport(source) {
37
37
  function insertPlugin(source, port) {
38
38
  return source.replace(PLUGINS_ARRAY, (match, _g, offset) => {
39
39
  const next = source[offset + match.length] ?? '';
40
- const separator = next === '' || /\s/.test(next) ? '' : ' ';
40
+ const separator = '' === next || /\s/.test(next) ? '' : ' ';
41
41
  return `${match}${reticlePluginCall(port)},${separator}`;
42
42
  });
43
43
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Quote one argument for a Windows command line. Pure, and deliberately NOT platform-gated.
3
+ *
4
+ * The rule used to live inside a `process.platform === WINDOWS` branch in node-io.ts, which meant
5
+ * the Windows path could not be exercised on a mac or in CI's Linux job — so it stayed wrong. A
6
+ * pure function is most of the fix: it can be asserted anywhere, and it is.
7
+ *
8
+ * ## What was wrong
9
+ *
10
+ * ```ts
11
+ * /[\s"]/.test(arg) ? `"${arg.replace(/"/g, '\\"')}"` : arg
12
+ * ```
13
+ *
14
+ * Two independent holes, both reachable from an ordinary directory path:
15
+ *
16
+ * 1. **Backslashes were not escaped.** `C:\Users\ada\My Projects\` became
17
+ * `"C:\Users\ada\My Projects\"`, whose trailing `\"` reads as an ESCAPED quote — the quoted
18
+ * region never closes and the rest of the line is re-parsed by cmd.exe. CodeQL flagged this one
19
+ * (`js/incomplete-sanitization`, high).
20
+ * 2. **The predicate only looked for whitespace and quotes.** An argument like `foo&whoami` has
21
+ * neither, so it was handed to cmd.exe completely unquoted. Correct backslash escaping does
22
+ * nothing for that; it needs the metacharacters in the trigger.
23
+ *
24
+ * ## The rule implemented here
25
+ *
26
+ * `CommandLineToArgvW`: a run of backslashes is literal unless it precedes a `"`, in which case the
27
+ * run is doubled and the quote escaped; a run at the very end sits before the closing quote we add,
28
+ * so it is doubled too. Correctly-terminated quotes also neutralise cmd.exe's metacharacters, which
29
+ * it does not interpret inside a quoted region.
30
+ *
31
+ * ## Known limit, stated rather than papered over
32
+ *
33
+ * `%VAR%` is expanded by cmd.exe even inside quotes, and no quoting prevents it — only avoiding
34
+ * `shell: true` does, which Windows needs so `pnpm.cmd`/`npx.cmd` resolve (see `shellOpt`). That is
35
+ * variable substitution, not command execution, and every caller here passes paths and package
36
+ * names rather than user prose.
37
+ */
38
+ export declare function windowsShellArg(arg: string): string;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Quote one argument for a Windows command line. Pure, and deliberately NOT platform-gated.
3
+ *
4
+ * The rule used to live inside a `process.platform === WINDOWS` branch in node-io.ts, which meant
5
+ * the Windows path could not be exercised on a mac or in CI's Linux job — so it stayed wrong. A
6
+ * pure function is most of the fix: it can be asserted anywhere, and it is.
7
+ *
8
+ * ## What was wrong
9
+ *
10
+ * ```ts
11
+ * /[\s"]/.test(arg) ? `"${arg.replace(/"/g, '\\"')}"` : arg
12
+ * ```
13
+ *
14
+ * Two independent holes, both reachable from an ordinary directory path:
15
+ *
16
+ * 1. **Backslashes were not escaped.** `C:\Users\ada\My Projects\` became
17
+ * `"C:\Users\ada\My Projects\"`, whose trailing `\"` reads as an ESCAPED quote — the quoted
18
+ * region never closes and the rest of the line is re-parsed by cmd.exe. CodeQL flagged this one
19
+ * (`js/incomplete-sanitization`, high).
20
+ * 2. **The predicate only looked for whitespace and quotes.** An argument like `foo&whoami` has
21
+ * neither, so it was handed to cmd.exe completely unquoted. Correct backslash escaping does
22
+ * nothing for that; it needs the metacharacters in the trigger.
23
+ *
24
+ * ## The rule implemented here
25
+ *
26
+ * `CommandLineToArgvW`: a run of backslashes is literal unless it precedes a `"`, in which case the
27
+ * run is doubled and the quote escaped; a run at the very end sits before the closing quote we add,
28
+ * so it is doubled too. Correctly-terminated quotes also neutralise cmd.exe's metacharacters, which
29
+ * it does not interpret inside a quoted region.
30
+ *
31
+ * ## Known limit, stated rather than papered over
32
+ *
33
+ * `%VAR%` is expanded by cmd.exe even inside quotes, and no quoting prevents it — only avoiding
34
+ * `shell: true` does, which Windows needs so `pnpm.cmd`/`npx.cmd` resolve (see `shellOpt`). That is
35
+ * variable substitution, not command execution, and every caller here passes paths and package
36
+ * names rather than user prose.
37
+ */
38
+ /**
39
+ * Characters that make cmd.exe do something other than pass the text along.
40
+ *
41
+ * Whitespace and `"` split or delimit; the rest are the shell's control operators. An argument
42
+ * containing any of them must be quoted, not just one containing a space.
43
+ */
44
+ const NEEDS_QUOTING = /[\s"&|<>^()!%,;=]/;
45
+ export function windowsShellArg(arg) {
46
+ // An empty argument must still occupy a slot in argv. Unquoted it disappears entirely, silently
47
+ // shifting every argument after it by one.
48
+ if (0 === arg.length)
49
+ return '""';
50
+ if (!NEEDS_QUOTING.test(arg))
51
+ return arg;
52
+ let out = '"';
53
+ let backslashes = 0;
54
+ for (const ch of arg) {
55
+ if ('\\' === ch) {
56
+ backslashes += 1;
57
+ continue;
58
+ }
59
+ if ('"' === ch) {
60
+ // 2n+1 backslashes → n literal backslashes and an escaped quote.
61
+ out += '\\'.repeat(2 * backslashes + 1) + '"';
62
+ backslashes = 0;
63
+ continue;
64
+ }
65
+ out += '\\'.repeat(backslashes) + ch;
66
+ backslashes = 0;
67
+ }
68
+ // A trailing run sits immediately before the closing quote, so it must be doubled or it escapes it.
69
+ return `${out}${'\\'.repeat(2 * backslashes)}"`;
70
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Which directories to look in for the app, when `reticle init` runs at a monorepo root.
3
+ *
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.
13
+ */
14
+ interface WorkspaceSources {
15
+ /** Raw contents of pnpm-workspace.yaml, when present. */
16
+ pnpmWorkspace?: string;
17
+ /** The `workspaces` field of package.json — array form or the yarn/npm object form. */
18
+ pkgWorkspaces?: unknown;
19
+ /** Directory names at the repo root, used when nothing is declared. */
20
+ topLevelDirs?: readonly string[];
21
+ }
22
+ export declare function workspaceParents(sources: WorkspaceSources): string[];
23
+ export {};
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Which directories to look in for the app, when `reticle init` runs at a monorepo root.
3
+ *
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.
13
+ */
14
+ /** Directories that are never a workspace package, whatever the layout. */
15
+ const NEVER_A_PACKAGE = new Set(['node_modules', 'dist', 'build', 'out', 'coverage', 'target']);
16
+ /** `packages/*` -> `packages`; `web` -> `web`. The base directory a glob searches. */
17
+ function globBase(pattern) {
18
+ const base = pattern
19
+ .split('/')[0]
20
+ ?.trim()
21
+ .replace(/^['"]|['"]$/g, '');
22
+ return base === undefined || '' === base || '.' === base || base.includes('*') ? undefined : base;
23
+ }
24
+ function fromPnpm(yaml) {
25
+ // A deliberately small reader rather than a YAML dependency: this file is a list of globs, and the
26
+ // only shape that matters is `- 'pattern'` under `packages:`. A malformed file yields nothing,
27
+ // which falls through to the top-level scan rather than failing the install.
28
+ const out = [];
29
+ let inPackages = false;
30
+ for (const line of yaml.split('\n')) {
31
+ if (/^packages\s*:/.test(line)) {
32
+ inPackages = true;
33
+ continue;
34
+ }
35
+ if (inPackages && /^\S/.test(line))
36
+ break;
37
+ const item = /^\s*-\s*(.+)$/.exec(line);
38
+ if (inPackages && item?.[1] !== undefined) {
39
+ const base = globBase(item[1]);
40
+ if (base !== undefined)
41
+ out.push(base);
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+ function fromPkg(workspaces) {
47
+ const list = Array.isArray(workspaces)
48
+ ? workspaces
49
+ : 'object' === typeof workspaces && workspaces !== null
50
+ ? workspaces.packages
51
+ : undefined;
52
+ if (!Array.isArray(list))
53
+ return [];
54
+ return list
55
+ .filter((p) => 'string' === typeof p)
56
+ .map(globBase)
57
+ .filter((p) => p !== undefined);
58
+ }
59
+ export function workspaceParents(sources) {
60
+ const declared = [
61
+ ...(sources.pnpmWorkspace === undefined ? [] : fromPnpm(sources.pnpmWorkspace)),
62
+ ...fromPkg(sources.pkgWorkspaces),
63
+ ];
64
+ const candidates = declared.length > 0
65
+ ? declared
66
+ : (sources.topLevelDirs ?? []).filter((d) => !d.startsWith('.') && !NEVER_A_PACKAGE.has(d));
67
+ return [...new Set(candidates)];
68
+ }
@@ -35,7 +35,7 @@ function invalidate() {
35
35
  }
36
36
  /** Record what a session declared sensitive. Called when its hello lands. */
37
37
  export function declareDrivenRedactionKeys(sessionId, keys) {
38
- if (keys.length === 0) {
38
+ if (0 === keys.length) {
39
39
  if (declaredBySession.delete(sessionId))
40
40
  invalidate();
41
41
  return;
@@ -21,7 +21,7 @@ const DEFAULT_POLICY = { isSensitiveKey: defaultIsSensitiveKey };
21
21
  function redactByKey(value, policy) {
22
22
  if (Array.isArray(value))
23
23
  return value.map((v) => redactByKey(v, policy));
24
- if (value !== null && typeof value === 'object') {
24
+ if (value !== null && 'object' === typeof value) {
25
25
  const out = {};
26
26
  for (const [k, v] of Object.entries(value)) {
27
27
  out[k] = policy.isSensitiveKey(k) ? REDACTED_VALUE : redactByKey(v, policy);
@@ -82,15 +82,15 @@ export function buildNetworkDetail(raw, policy = DEFAULT_POLICY) {
82
82
  status: raw.status,
83
83
  headers: projectHeaders(raw.headers, policy),
84
84
  ...(raw.resourceType === undefined ? {} : { resourceType: raw.resourceType }),
85
- ...(raw.requestBody === undefined || raw.requestBody.length === 0
85
+ ...(raw.requestBody === undefined || 0 === raw.requestBody.length
86
86
  ? {}
87
87
  : { requestBody: projectWireBody(raw.requestBody, policy) }),
88
- ...(raw.pageUrl === undefined || raw.pageUrl.length === 0 ? {} : { pageUrl: raw.pageUrl }),
88
+ ...(raw.pageUrl === undefined || 0 === raw.pageUrl.length ? {} : { pageUrl: raw.pageUrl }),
89
89
  };
90
90
  }
91
91
  function keyOf(url, method) {
92
- const m = typeof method === 'string' ? method.toUpperCase() : '';
93
- const u = typeof url === 'string' ? url : '';
92
+ const m = 'string' === typeof method ? method.toUpperCase() : '';
93
+ const u = 'string' === typeof url ? url : '';
94
94
  return `${m} ${u}`;
95
95
  }
96
96
  /**
@@ -127,9 +127,9 @@ export function mergeNetworkDetail(events) {
127
127
  // finding — that is the whole reason for capturing it — so the authoritative one wins and the
128
128
  // divergence is flagged rather than silently resolved.
129
129
  const wireBody = e.data['requestBody'];
130
- if (typeof wireBody === 'string') {
130
+ if ('string' === typeof wireBody) {
131
131
  const pageBody = data['requestBody'];
132
- if (typeof pageBody === 'string' && pageBody !== wireBody) {
132
+ if ('string' === typeof pageBody && pageBody !== wireBody) {
133
133
  data['requestBodyDivergedFromPage'] = true;
134
134
  }
135
135
  data['requestBody'] = wireBody;
@@ -162,7 +162,7 @@ export function attachNetworkDetail(page, emit) {
162
162
  status: response.status(),
163
163
  headers,
164
164
  ...(resourceType === undefined ? {} : { resourceType }),
165
- ...(postData === null ? {} : { requestBody: postData }),
165
+ ...(null === postData ? {} : { requestBody: postData }),
166
166
  pageUrl: page.url(),
167
167
  },
168
168
  // Resolved per response, not per attachment: a session declaring extra keys can connect
@@ -5,7 +5,7 @@ import { sessionIdShape } from '../tools/tool-kit.js';
5
5
  import { asString } from '../tools/tools-helpers.js';
6
6
  function mockProvider(deps) {
7
7
  const p = deps.realInput;
8
- return p !== undefined && typeof p.setMocks === 'function' ? p : undefined;
8
+ return p !== undefined && 'function' === typeof p.setMocks ? p : undefined;
9
9
  }
10
10
  const ruleShape = z.object({
11
11
  urlContains: z
@@ -80,7 +80,7 @@ export const NETWORK_MOCK_TOOLS = [
80
80
  };
81
81
  }
82
82
  const session = deps.sessions.resolve(asString(args['sessionId']));
83
- const rules = args['clear'] === true ? [] : toRules(args['mocks']);
83
+ const rules = true === args['clear'] ? [] : toRules(args['mocks']);
84
84
  const applied = await provider.setMocks(session.url, rules);
85
85
  return { applied, count: applied ? rules.length : 0 };
86
86
  },
@@ -10,7 +10,7 @@ export function matchMock(rules, req) {
10
10
  continue;
11
11
  if (rule.method !== undefined && rule.method.toUpperCase() !== req.method.toUpperCase())
12
12
  continue;
13
- if (rule.abort === true)
13
+ if (true === rule.abort)
14
14
  return { kind: 'abort' };
15
15
  const outcome = {
16
16
  kind: 'fulfill',
@@ -27,11 +27,11 @@ export function matchMock(rules, req) {
27
27
  }
28
28
  /** Apply a matched outcome to a Playwright Route. Exported so the route handler is testable in isolation. */
29
29
  export async function applyOutcome(route, outcome, sleep) {
30
- if (outcome.kind === 'continue') {
30
+ if ('continue' === outcome.kind) {
31
31
  await route.continue();
32
32
  return;
33
33
  }
34
- if (outcome.kind === 'abort') {
34
+ if ('abort' === outcome.kind) {
35
35
  await route.abort('failed');
36
36
  return;
37
37
  }
@@ -51,7 +51,7 @@ const realSleep = (ms) => new Promise((res) => setTimeout(res, ms));
51
51
  */
52
52
  export async function installNetworkMocks(page, rules, sleep = realSleep) {
53
53
  await page.unroute('**/*').catch(() => undefined);
54
- if (rules.length === 0)
54
+ if (0 === rules.length)
55
55
  return;
56
56
  await page.route('**/*', (route) => {
57
57
  const req = route.request();
@@ -1,3 +1,4 @@
1
+ import { gotoOptions } from '../pool/playwright-launcher.js';
1
2
  import { BrowserLaunchKind } from '@reticlehq/core';
2
3
  import { getSessionMetrics } from '../telemetry/session-metrics.js';
3
4
  import { classifyConnectFailure } from '../telemetry/connect-failure.js';
@@ -93,7 +94,7 @@ const SCREENSHOT_DETERMINISM = { style: HIDE_RETICLE_CHROME_CSS, animations: 'di
93
94
  export async function capturePage(page, opts) {
94
95
  const buf = await page.screenshot(opts.clip !== undefined
95
96
  ? { ...SCREENSHOT_DETERMINISM, clip: opts.clip }
96
- : opts.fullPage === true
97
+ : true === opts.fullPage
97
98
  ? { ...SCREENSHOT_DETERMINISM, fullPage: true }
98
99
  : { ...SCREENSHOT_DETERMINISM });
99
100
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
@@ -269,7 +270,11 @@ export class LaunchedRealInputProvider {
269
270
  if (this.#onNetworkDetail !== undefined)
270
271
  attachNetworkDetail(page, this.#onNetworkDetail);
271
272
  try {
272
- await page.goto(this.#driveUrl);
273
+ // Same navigation rule as the pool, and for the same measured reason: Playwright's default
274
+ // waits for `load`, which an app with one never-finishing subresource never fires — 30s of
275
+ // nothing and then a failure that blames the app. The SDK connect is a module script, so it
276
+ // has already run by DOMContentLoaded. See gotoOptions.
277
+ await page.goto(this.#driveUrl, gotoOptions(undefined));
273
278
  }
274
279
  catch (e) {
275
280
  throw new DriveError(DriveErrorCode.NAVIGATE_FAILED, e instanceof Error ? e.message : String(e));
@@ -369,7 +374,7 @@ export function selectPage(pages, sessionUrl) {
369
374
  return exact;
370
375
  const target = stripVolatile(sessionUrl);
371
376
  const loose = pages.filter((p) => stripVolatile(p.url()) === target);
372
- return loose.length === 1 ? loose[0] : undefined;
377
+ return 1 === loose.length ? loose[0] : undefined;
373
378
  }
374
379
  function stripVolatile(url) {
375
380
  const hash = url.indexOf('#');
@@ -38,7 +38,7 @@ export async function scrollToFind(session, q, opts = {}) {
38
38
  return { found: true, element: hit, scrolls, exhausted: false };
39
39
  // Fall through to linear refinement from current position (already near the target).
40
40
  const data = asRecord(sr.result);
41
- if (data['atEnd'] === true || data['scrolled'] === false) {
41
+ if (true === data['atEnd'] || false === data['scrolled']) {
42
42
  return { found: false, scrolls, exhausted: true };
43
43
  }
44
44
  }
@@ -50,7 +50,7 @@ export async function scrollToFind(session, q, opts = {}) {
50
50
  if (hit !== undefined)
51
51
  return { found: true, element: hit, scrolls, exhausted: false };
52
52
  // Reached the bottom or the container would not move — no more rows to reveal.
53
- if (data['atEnd'] === true || data['scrolled'] === false) {
53
+ if (true === data['atEnd'] || false === data['scrolled']) {
54
54
  return { found: false, scrolls, exhausted: true };
55
55
  }
56
56
  }
@@ -1,7 +1,2 @@
1
1
  import type { ToolDef } from '../tools/tools.js';
2
- /**
3
- * reticle_scroll_to — the windowed/virtualized-list escape hatch. A plain reticle_query
4
- * only sees rendered nodes, so an off-screen row in a react-window/react-virtualized list returns
5
- * nothing. This scrolls the container until the row mounts, then returns its ref.
6
- */
7
2
  export declare const SCROLL_TOOLS: ToolDef[];
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { QueryBy } from '@reticlehq/core';
2
3
  import { ReticleTool } from '../tools/tool-names.js';
3
4
  import { asNumber, asString } from '../tools/tools-helpers.js';
4
5
  import { scrollToFind } from './scroll-find.js';
@@ -7,14 +8,20 @@ import { scrollToFind } from './scroll-find.js';
7
8
  * only sees rendered nodes, so an off-screen row in a react-window/react-virtualized list returns
8
9
  * nothing. This scrolls the container until the row mounts, then returns its ref.
9
10
  */
11
+ /**
12
+ * The query strategies, derived from QueryBy — the same vocabulary reticle_query uses, and for the
13
+ * same reason. A free string here produced the identical false negative: `by:'css'` scrolled the
14
+ * whole list and reported `{ found: false, exhausted: true }`, which reads as "the row is not in
15
+ * this list" rather than "that strategy does not exist".
16
+ */
17
+ const QUERY_BY_LIST = Object.values(QueryBy).join(' | ');
18
+ const queryByEnum = z.enum(Object.values(QueryBy));
10
19
  export const SCROLL_TOOLS = [
11
20
  {
12
21
  name: ReticleTool.SCROLL_TO,
13
- description: 'Find an element in a VIRTUALIZED list that has not rendered yet. Pass `by` (role|text|testid|label|placeholder|alt) and `value` (query string) to identify the target row. Scrolls the container until the row mounts, the list ends, or maxScrolls (default 20) is spent. Pass targetIndex + totalCount for bisection — jumps directly to the estimated offset in one scroll (e.g. targetIndex:800 totalCount:1000 jumps to 80% of scrollHeight). Returns { found, element?, scrolls, exhausted }.',
22
+ description: 'Find an element in a VIRTUALIZED list that has not rendered yet. Pass `by` (see the parameter for the exact strategies) and `value` (query string) to identify the target row. Scrolls the container until the row mounts, the list ends, or maxScrolls (default 20) is spent. Pass targetIndex + totalCount for bisection — jumps directly to the estimated offset in one scroll (e.g. targetIndex:800 totalCount:1000 jumps to 80% of scrollHeight). Returns { found, element?, scrolls, exhausted }.',
14
23
  inputSchema: {
15
- by: z
16
- .string()
17
- .describe('Query strategy for finding the target: role | text | testid | label | placeholder | alt'),
24
+ by: queryByEnum.describe(`Query strategy for finding the target: ${QUERY_BY_LIST}`),
18
25
  value: z
19
26
  .string()
20
27
  .describe('Query value for the selected strategy (the element to scroll into view).'),
@@ -8,7 +8,7 @@ const MIN_DIM = 64;
8
8
  const MAX_DIM = 10000;
9
9
  function viewportProvider(deps) {
10
10
  const p = deps.realInput;
11
- return p !== undefined && typeof p.setViewport === 'function'
11
+ return p !== undefined && 'function' === typeof p.setViewport
12
12
  ? p
13
13
  : undefined;
14
14
  }
@@ -54,6 +54,6 @@ export const VIEWPORT_TOOLS = [
54
54
  ];
55
55
  /** Clamp a requested dimension into [MIN_DIM, MAX_DIM]; a missing/NaN value falls back to MIN_DIM. */
56
56
  function clampDim(value) {
57
- const n = typeof value === 'number' && Number.isFinite(value) ? Math.round(value) : MIN_DIM;
57
+ const n = 'number' === typeof value && Number.isFinite(value) ? Math.round(value) : MIN_DIM;
58
58
  return Math.max(MIN_DIM, Math.min(n, MAX_DIM));
59
59
  }
@@ -1,7 +1,5 @@
1
1
  import type { FileSystemPort } from '../project/fs-port.js';
2
2
  import { type AmbientCounts } from './ambient.js';
3
- /** Bumped on any breaking change to the persisted ambient-map shape. */
4
- export declare const AMBIENT_FILE_VERSION = 1;
5
3
  /**
6
4
  * Persists the learned ambient-churn region map at `.reticle/ambient.json`. Local, single-project
7
5
  * memory (stays OSS — OSS-VS-SERVER). Loads never throw: missing/malformed/wrong-version degrades to
@@ -2,7 +2,7 @@ import { dirname } from 'node:path';
2
2
  import { reticleDirPaths } from '../project/reticle-dir.js';
3
3
  import { AmbientFileSchema } from './ambient.js';
4
4
  /** Bumped on any breaking change to the persisted ambient-map shape. */
5
- export const AMBIENT_FILE_VERSION = 1;
5
+ const AMBIENT_FILE_VERSION = 1;
6
6
  /**
7
7
  * Persists the learned ambient-churn region map at `.reticle/ambient.json`. Local, single-project
8
8
  * memory (stays OSS — OSS-VS-SERVER). Loads never throw: missing/malformed/wrong-version degrades to
@@ -8,7 +8,7 @@ import { z } from 'zod';
8
8
  */
9
9
  export function ambientKeyOf(event) {
10
10
  const region = event.data?.['region'];
11
- if (typeof region === 'string' && region.length > 0)
11
+ if ('string' === typeof region && region.length > 0)
12
12
  return region;
13
13
  return event.ref;
14
14
  }