@reticlehq/server 2.4.0 → 2.5.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 (416) hide show
  1. package/SKILL.md +702 -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} +1 -1
  7. package/dist/{bridge.js → bridge/bridge.js} +63 -13
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +1 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +9 -9
  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-doctor.js → cli/cli-doctor.js} +9 -2
  20. package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
  21. package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
  22. package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
  23. package/dist/cli/cli-launch.js +171 -0
  24. package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +2 -11
  25. package/dist/{cli-parse.js → cli/cli-parse.js} +113 -60
  26. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
  27. package/dist/{cli-port.js → cli/cli-port.js} +9 -9
  28. package/dist/cli/cli-update-commands.d.ts +4 -0
  29. package/dist/cli/cli-update-commands.js +93 -0
  30. package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
  31. package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
  32. package/dist/cli.d.ts +2 -2
  33. package/dist/cli.js +174 -92
  34. package/dist/cloud/cloud-config.d.ts +0 -1
  35. package/dist/cloud/cloud-config.js +9 -9
  36. package/dist/cloud/cloud-sync.d.ts +1 -7
  37. package/dist/cloud/cloud-sync.js +12 -12
  38. package/dist/crawl/crawl-empty.d.ts +16 -0
  39. package/dist/crawl/crawl-empty.js +24 -0
  40. package/dist/crawl/crawl-tools.js +4 -1
  41. package/dist/crawl/crawl.js +26 -7
  42. package/dist/daemon/daemon-resilience.d.ts +49 -0
  43. package/dist/daemon/daemon-resilience.js +191 -0
  44. package/dist/daemon/daemon-usefulness.d.ts +61 -0
  45. package/dist/daemon/daemon-usefulness.js +62 -0
  46. package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
  47. package/dist/{daemon.js → daemon/daemon.js} +80 -48
  48. package/dist/daemon/idle-grace.d.ts +32 -0
  49. package/dist/daemon/idle-grace.js +41 -0
  50. package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
  51. package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
  52. package/dist/domain/domain-model.js +2 -2
  53. package/dist/events/body-failures.js +8 -8
  54. package/dist/events/contradictions.d.ts +1 -1
  55. package/dist/events/contradictions.js +60 -10
  56. package/dist/events/echo-mismatch.js +10 -10
  57. package/dist/events/event-filters.js +6 -6
  58. package/dist/events/json-salvage.d.ts +2 -1
  59. package/dist/events/json-salvage.js +6 -6
  60. package/dist/events/observed-in-window.d.ts +12 -0
  61. package/dist/events/observed-in-window.js +21 -0
  62. package/dist/events/predicate-eval.d.ts +43 -20
  63. package/dist/events/predicate-eval.js +159 -55
  64. package/dist/events/predicate.d.ts +2 -2
  65. package/dist/events/predicate.js +112 -35
  66. package/dist/events/reconcile.js +5 -5
  67. package/dist/events/ring-buffer.js +1 -1
  68. package/dist/events/stale-response.js +6 -6
  69. package/dist/events/testid-near-miss.d.ts +22 -0
  70. package/dist/events/testid-near-miss.js +33 -0
  71. package/dist/events/unit-mismatch.js +8 -8
  72. package/dist/flows/affected-tools.js +19 -4
  73. package/dist/flows/affected.js +1 -1
  74. package/dist/flows/annotate-target.d.ts +1 -0
  75. package/dist/flows/annotate-target.js +20 -0
  76. package/dist/flows/annotate-tools.js +25 -3
  77. package/dist/flows/annotate.js +17 -4
  78. package/dist/flows/assertion-integrity.d.ts +2 -1
  79. package/dist/flows/assertion-tiers-store.d.ts +3 -66
  80. package/dist/flows/assertion-tiers-store.js +2 -2
  81. package/dist/flows/attributed-failure.d.ts +17 -0
  82. package/dist/flows/attributed-failure.js +20 -0
  83. package/dist/flows/buddy-status.d.ts +2 -1
  84. package/dist/flows/buddy-status.js +2 -2
  85. package/dist/flows/coverage.d.ts +3 -2
  86. package/dist/flows/coverage.js +2 -2
  87. package/dist/flows/decision.js +24 -9
  88. package/dist/flows/empty-flow.d.ts +6 -0
  89. package/dist/flows/empty-flow.js +24 -0
  90. package/dist/flows/flake-store.d.ts +0 -1
  91. package/dist/flows/flake-store.js +1 -1
  92. package/dist/flows/flake.d.ts +2 -1
  93. package/dist/flows/flake.js +2 -2
  94. package/dist/flows/flow-classify.js +12 -0
  95. package/dist/flows/flow-replay-run.js +4 -4
  96. package/dist/flows/flow-replay.d.ts +5 -7
  97. package/dist/flows/flow-replay.js +114 -47
  98. package/dist/flows/flow-report.js +1 -1
  99. package/dist/flows/flow-scope.d.ts +1 -6
  100. package/dist/flows/flow-step-runners.d.ts +26 -6
  101. package/dist/flows/flow-step-runners.js +157 -6
  102. package/dist/flows/flow-success.js +20 -15
  103. package/dist/flows/flow-tools.js +53 -7
  104. package/dist/flows/flows.js +15 -11
  105. package/dist/flows/gate.d.ts +4 -3
  106. package/dist/flows/gate.js +1 -1
  107. package/dist/flows/heal-run.d.ts +0 -8
  108. package/dist/flows/heal-run.js +5 -5
  109. package/dist/flows/heal.js +3 -3
  110. package/dist/flows/predicate-to-expect.d.ts +38 -0
  111. package/dist/flows/predicate-to-expect.js +95 -0
  112. package/dist/flows/replay.d.ts +16 -1
  113. package/dist/flows/replay.js +58 -22
  114. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  115. package/dist/flows/role-anchor-nearest.js +45 -0
  116. package/dist/flows/server-verify.d.ts +1 -1
  117. package/dist/flows/server-verify.js +5 -5
  118. package/dist/flows/verify-change-tools.js +32 -10
  119. package/dist/flows/verify-change-verdict.d.ts +15 -0
  120. package/dist/flows/verify-change-verdict.js +25 -0
  121. package/dist/flows/watch-batcher.d.ts +3 -2
  122. package/dist/honesty/already-true.d.ts +2 -0
  123. package/dist/honesty/already-true.js +31 -0
  124. package/dist/honesty/blind-spots.d.ts +16 -3
  125. package/dist/honesty/blind-spots.js +24 -12
  126. package/dist/honesty/honesty.d.ts +3 -2
  127. package/dist/honesty/honesty.js +4 -4
  128. package/dist/honesty/uncaptured-bodies.js +1 -1
  129. package/dist/honesty/unread-outcome.js +2 -2
  130. package/dist/honesty/verified.d.ts +22 -3
  131. package/dist/honesty/verified.js +48 -8
  132. package/dist/http-server.js +14 -7
  133. package/dist/hunt/hunt-report.d.ts +2 -1
  134. package/dist/hunt/hunt-report.js +2 -2
  135. package/dist/index.d.ts +8 -6
  136. package/dist/index.js +32 -25
  137. package/dist/init/agent-rules.d.ts +2 -1
  138. package/dist/init/agent-rules.js +45 -7
  139. package/dist/init/app-choice.d.ts +20 -0
  140. package/dist/init/app-choice.js +25 -0
  141. package/dist/init/astro-host.d.ts +21 -0
  142. package/dist/init/astro-host.js +27 -0
  143. package/dist/init/astro-patch.d.ts +16 -0
  144. package/dist/init/astro-patch.js +240 -0
  145. package/dist/init/capabilities.js +4 -1
  146. package/dist/init/cra.d.ts +37 -0
  147. package/dist/init/cra.js +90 -0
  148. package/dist/init/cursor.js +39 -4
  149. package/dist/init/desktop-doctor.d.ts +3 -2
  150. package/dist/init/desktop-doctor.js +4 -4
  151. package/dist/init/detect.d.ts +3 -2
  152. package/dist/init/detect.js +16 -5
  153. package/dist/init/mcp-registered.d.ts +12 -0
  154. package/dist/init/mcp-registered.js +14 -0
  155. package/dist/init/mcp.d.ts +27 -2
  156. package/dist/init/mcp.js +40 -4
  157. package/dist/init/next-patch.d.ts +2 -4
  158. package/dist/init/next-patch.js +109 -19
  159. package/dist/init/node-io.js +23 -6
  160. package/dist/init/plan-framework.d.ts +16 -1
  161. package/dist/init/plan-framework.js +132 -8
  162. package/dist/init/plan.d.ts +73 -8
  163. package/dist/init/plan.js +133 -34
  164. package/dist/init/project-id.d.ts +5 -9
  165. package/dist/init/project-id.js +10 -22
  166. package/dist/init/run.d.ts +5 -0
  167. package/dist/init/run.js +210 -36
  168. package/dist/init/slash-command.d.ts +9 -0
  169. package/dist/init/slash-command.js +10 -1
  170. package/dist/init/snippets.d.ts +7 -10
  171. package/dist/init/snippets.js +44 -15
  172. package/dist/init/vite-config.js +1 -1
  173. package/dist/init/workspace-apps.d.ts +23 -0
  174. package/dist/init/workspace-apps.js +68 -0
  175. package/dist/input/driven-redaction.js +1 -1
  176. package/dist/input/network-detail.js +8 -8
  177. package/dist/input/network-mock-tools.js +2 -2
  178. package/dist/input/network-mock.js +4 -4
  179. package/dist/input/real-input.js +8 -3
  180. package/dist/input/scroll-find.js +2 -2
  181. package/dist/input/scroll-tools.d.ts +0 -5
  182. package/dist/input/scroll-tools.js +11 -4
  183. package/dist/input/viewport-tools.js +2 -2
  184. package/dist/journal/ambient-store.d.ts +0 -2
  185. package/dist/journal/ambient-store.js +1 -1
  186. package/dist/journal/ambient.js +1 -1
  187. package/dist/journal/attach-journal.d.ts +2 -1
  188. package/dist/journal/deviation-report.js +6 -6
  189. package/dist/journal/deviation-service.js +1 -1
  190. package/dist/journal/envelope-store.d.ts +0 -2
  191. package/dist/journal/envelope-store.js +1 -1
  192. package/dist/journal/envelope.d.ts +2 -3
  193. package/dist/journal/envelope.js +3 -3
  194. package/dist/journal/journal-query.js +1 -1
  195. package/dist/journal/journal-recorder.d.ts +2 -1
  196. package/dist/journal/journal-recorder.js +2 -2
  197. package/dist/journal/rollups.js +9 -9
  198. package/dist/journal/session-end.d.ts +2 -1
  199. package/dist/journal/session-journal.js +4 -4
  200. package/dist/license/license.d.ts +0 -14
  201. package/dist/license/license.js +8 -8
  202. package/dist/log.d.ts +10 -0
  203. package/dist/log.js +11 -1
  204. package/dist/mcp/mcp-is-error.d.ts +13 -0
  205. package/dist/mcp/mcp-is-error.js +18 -0
  206. package/dist/mcp/mcp-outage.d.ts +31 -0
  207. package/dist/mcp/mcp-outage.js +48 -0
  208. package/dist/mcp/mcp-proxy.d.ts +124 -0
  209. package/dist/mcp/mcp-proxy.js +697 -0
  210. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  211. package/dist/{mcp.js → mcp/mcp.js} +110 -35
  212. package/dist/mcp/proxy-handshake.d.ts +3 -0
  213. package/dist/mcp/proxy-handshake.js +54 -0
  214. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  215. package/dist/mcp/proxy-lifecycle.js +70 -0
  216. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  217. package/dist/mcp/tool-catalog-cache.js +55 -0
  218. package/dist/oracles/propose-consequences.d.ts +2 -1
  219. package/dist/oracles/propose-consequences.js +16 -11
  220. package/dist/oracles/self-instrument.d.ts +2 -1
  221. package/dist/oracles/self-instrument.js +1 -1
  222. package/dist/phenomena/phenomena.js +3 -3
  223. package/dist/platform.d.ts +16 -0
  224. package/dist/platform.js +16 -0
  225. package/dist/pool/playwright-launcher.d.ts +15 -2
  226. package/dist/pool/playwright-launcher.js +21 -2
  227. package/dist/project/fs-port.js +1 -1
  228. package/dist/project/project-tools.js +2 -2
  229. package/dist/runs/build-verification-run.js +1 -1
  230. package/dist/runs/repair-prompt.d.ts +0 -6
  231. package/dist/runs/repair-prompt.js +3 -3
  232. package/dist/runs/risk-classify.js +1 -1
  233. package/dist/runs/run-diff.d.ts +0 -2
  234. package/dist/runs/run-diff.js +3 -3
  235. package/dist/runs/run-tools.js +2 -2
  236. package/dist/runs/verification-sync.js +2 -2
  237. package/dist/runs/verify-http.js +1 -1
  238. package/dist/runs/verify-server.js +1 -1
  239. package/dist/session/command-timeout.d.ts +11 -3
  240. package/dist/session/command-timeout.js +2 -2
  241. package/dist/session/control-envelope.d.ts +6 -0
  242. package/dist/session/control-envelope.js +7 -1
  243. package/dist/session/dev-server-probe.d.ts +13 -0
  244. package/dist/session/dev-server-probe.js +52 -0
  245. package/dist/session/last-act.d.ts +17 -3
  246. package/dist/session/last-act.js +16 -4
  247. package/dist/session/live-control-tools.js +7 -2
  248. package/dist/session/live-control.js +1 -1
  249. package/dist/session/looks-like-dev-server.d.ts +14 -0
  250. package/dist/session/looks-like-dev-server.js +25 -0
  251. package/dist/session/no-session-diagnosis.d.ts +38 -0
  252. package/dist/session/no-session-diagnosis.js +70 -0
  253. package/dist/session/no-session-watch.d.ts +19 -0
  254. package/dist/session/no-session-watch.js +61 -0
  255. package/dist/session/observed-state.d.ts +4 -0
  256. package/dist/session/observed-state.js +19 -1
  257. package/dist/session/output-budget.js +1 -1
  258. package/dist/session/session-health.d.ts +8 -1
  259. package/dist/session/session-health.js +8 -7
  260. package/dist/session/session-info.d.ts +26 -7
  261. package/dist/session/session-info.js +42 -1
  262. package/dist/session/session-lease.d.ts +0 -11
  263. package/dist/session/session-lease.js +1 -1
  264. package/dist/session/session-manager.d.ts +3 -0
  265. package/dist/session/session-manager.js +52 -9
  266. package/dist/session/session-readiness.d.ts +1 -1
  267. package/dist/session/session-readiness.js +6 -1
  268. package/dist/session/session-reaper.js +1 -1
  269. package/dist/session/session-reconnect.d.ts +32 -0
  270. package/dist/session/session-reconnect.js +42 -0
  271. package/dist/session/session.d.ts +14 -2
  272. package/dist/session/session.js +69 -26
  273. package/dist/session/state-select.d.ts +1 -1
  274. package/dist/session/state-select.js +1 -1
  275. package/dist/status-payload.d.ts +19 -0
  276. package/dist/status-payload.js +11 -0
  277. package/dist/telemetry/argument-shape.js +10 -1
  278. package/dist/telemetry/browser-mode.d.ts +27 -0
  279. package/dist/telemetry/browser-mode.js +33 -0
  280. package/dist/telemetry/bug-found.d.ts +17 -21
  281. package/dist/telemetry/bug-found.js +120 -8
  282. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  283. package/dist/telemetry/cli-telemetry.js +27 -4
  284. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  285. package/dist/telemetry/daemon-telemetry.js +12 -2
  286. package/dist/telemetry/dev-repo.js +4 -4
  287. package/dist/telemetry/error-fingerprint.js +21 -2
  288. package/dist/telemetry/feedback-cli.d.ts +1 -1
  289. package/dist/telemetry/feedback-cli.js +4 -4
  290. package/dist/telemetry/feedback-context.d.ts +22 -0
  291. package/dist/telemetry/feedback-context.js +41 -1
  292. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  293. package/dist/telemetry/feedback-delivery.js +30 -0
  294. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  295. package/dist/telemetry/feedback-outbox.js +87 -0
  296. package/dist/telemetry/feedback.d.ts +22 -1
  297. package/dist/telemetry/feedback.js +67 -8
  298. package/dist/telemetry/git-facts.js +1 -1
  299. package/dist/telemetry/session-metrics.d.ts +2 -0
  300. package/dist/telemetry/session-metrics.js +68 -6
  301. package/dist/telemetry/telemetry.d.ts +27 -2
  302. package/dist/telemetry/telemetry.js +119 -29
  303. package/dist/telemetry/verification-of.d.ts +22 -0
  304. package/dist/telemetry/verification-of.js +84 -0
  305. package/dist/tools/act-capsule.js +2 -2
  306. package/dist/tools/act-danger.d.ts +12 -0
  307. package/dist/tools/act-danger.js +20 -3
  308. package/dist/tools/act-helpers.js +4 -4
  309. package/dist/tools/act-tools.d.ts +0 -8
  310. package/dist/tools/act-tools.js +84 -115
  311. package/dist/tools/act-view.js +7 -7
  312. package/dist/tools/alias-args.d.ts +17 -0
  313. package/dist/tools/alias-args.js +25 -0
  314. package/dist/tools/assert-grade.js +9 -9
  315. package/dist/tools/assert-verdict.d.ts +3 -1
  316. package/dist/tools/assert-verdict.js +8 -5
  317. package/dist/tools/browser-tools.js +30 -11
  318. package/dist/tools/contract-tools.js +1 -1
  319. package/dist/tools/coverage-identity.d.ts +34 -0
  320. package/dist/tools/coverage-identity.js +46 -0
  321. package/dist/tools/coverage-tools.js +10 -14
  322. package/dist/tools/dynamic-tools.d.ts +2 -1
  323. package/dist/tools/dynamic-tools.js +90 -18
  324. package/dist/tools/error-recovery.d.ts +20 -2
  325. package/dist/tools/error-recovery.js +179 -4
  326. package/dist/tools/feedback-tools.d.ts +12 -1
  327. package/dist/tools/feedback-tools.js +28 -5
  328. package/dist/tools/invoke-tool.d.ts +0 -6
  329. package/dist/tools/invoke-tool.js +57 -32
  330. package/dist/tools/lease-hint.d.ts +17 -0
  331. package/dist/tools/lease-hint.js +24 -0
  332. package/dist/tools/lease-tools.js +6 -5
  333. package/dist/tools/merge-tools.d.ts +10 -1
  334. package/dist/tools/merge-tools.js +9 -3
  335. package/dist/tools/merged-name-redirect.d.ts +13 -0
  336. package/dist/tools/merged-name-redirect.js +55 -0
  337. package/dist/tools/navigate-result.d.ts +17 -0
  338. package/dist/tools/navigate-result.js +31 -0
  339. package/dist/tools/observe-tools.js +54 -20
  340. package/dist/tools/observed-nothing.d.ts +25 -0
  341. package/dist/tools/observed-nothing.js +33 -0
  342. package/dist/tools/query-paginate.js +2 -2
  343. package/dist/tools/query-shape.d.ts +18 -0
  344. package/dist/tools/query-shape.js +39 -0
  345. package/dist/tools/read-tools.js +81 -20
  346. package/dist/tools/real-input-attempt.d.ts +28 -0
  347. package/dist/tools/real-input-attempt.js +88 -0
  348. package/dist/tools/reconcile-tools.js +7 -7
  349. package/dist/tools/reload-result.d.ts +14 -0
  350. package/dist/tools/reload-result.js +29 -0
  351. package/dist/tools/snapshot-delta.d.ts +4 -5
  352. package/dist/tools/snapshot-delta.js +0 -0
  353. package/dist/tools/tool-kit.d.ts +8 -0
  354. package/dist/tools/tool-surface.d.ts +83 -0
  355. package/dist/tools/tool-surface.js +204 -0
  356. package/dist/tools/tools-helpers.js +6 -6
  357. package/dist/tools/tools.d.ts +15 -0
  358. package/dist/tools/tools.js +53 -17
  359. package/dist/tools/unadvertised-help.d.ts +5 -0
  360. package/dist/tools/unadvertised-help.js +39 -0
  361. package/dist/trace.d.ts +69 -0
  362. package/dist/trace.js +150 -0
  363. package/dist/update/nudge-credit.d.ts +4 -0
  364. package/dist/update/nudge-credit.js +53 -0
  365. package/dist/update/sdk-sync.d.ts +21 -0
  366. package/dist/update/sdk-sync.js +42 -0
  367. package/dist/update/update-checker.js +3 -3
  368. package/dist/update/update-nudge.d.ts +63 -6
  369. package/dist/update/update-nudge.js +128 -15
  370. package/dist/update/updater.d.ts +1 -9
  371. package/dist/update/updater.js +13 -8
  372. package/dist/version/peer-announce.d.ts +4 -0
  373. package/dist/version/peer-announce.js +30 -0
  374. package/dist/{server-version.js → version/server-version.js} +5 -1
  375. package/dist/version/version-nudge.d.ts +28 -0
  376. package/dist/version/version-nudge.js +40 -0
  377. package/dist/version/version-skew.d.ts +66 -0
  378. package/dist/version/version-skew.js +71 -0
  379. package/dist/visual/visual-diff.js +2 -2
  380. package/dist/visual/visual-tools.js +4 -4
  381. package/docs/agent-cheatsheet.md +85 -0
  382. package/docs/architecture.md +113 -0
  383. package/docs/benchmarks.md +255 -0
  384. package/docs/debugging.md +102 -0
  385. package/docs/deploy-checks.md +69 -0
  386. package/docs/desktop-apps.md +256 -0
  387. package/docs/enterprise.md +62 -0
  388. package/docs/fixtures.md +28 -0
  389. package/docs/flows.md +166 -0
  390. package/docs/getting-started.md +469 -0
  391. package/docs/human-control.md +63 -0
  392. package/docs/integration-patterns.md +171 -0
  393. package/docs/local-registry.md +126 -0
  394. package/docs/mint.json +61 -0
  395. package/docs/multi-agent-testing.md +55 -0
  396. package/docs/platform-integration.md +122 -0
  397. package/docs/telemetry-contract.md +214 -0
  398. package/docs/telemetry.md +184 -0
  399. package/docs/testing.md +82 -0
  400. package/docs/token-efficiency.md +80 -0
  401. package/docs/usage.md +1046 -0
  402. package/package.json +8 -5
  403. package/dist/cli-launch.js +0 -112
  404. package/dist/daemon-resilience.d.ts +0 -22
  405. package/dist/daemon-resilience.js +0 -85
  406. package/dist/mcp-proxy.d.ts +0 -67
  407. package/dist/mcp-proxy.js +0 -337
  408. package/dist/tools/profiles.d.ts +0 -37
  409. package/dist/tools/profiles.js +0 -139
  410. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  411. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  412. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  413. /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
  414. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  415. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  416. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Which predicates can be satisfied by something that was already true before the action.
3
+ *
4
+ * Event-based kinds (net, signal, route, console, animation, settled) are evaluated against the
5
+ * event buffer floored at the act's own cursor, so a stale event cannot satisfy them — that floor is
6
+ * why `act_and_wait` can trust them at all. `state` is read through the same floored path.
7
+ *
8
+ * `element` and `text` read the LIVE DOM, where no floor exists. A condition that held before the
9
+ * click holds after it and passes instantly, whatever the action did. Measured in the field: a click
10
+ * asserted with `{ kind: 'text', contains: 'Parallel Routes' }` returned `verified: "yes"` in 478ms
11
+ * against `routeChanges: 0`, because the predicate matched the nav link that was already on screen —
12
+ * the real navigation landed 1.8 seconds later.
13
+ *
14
+ * So these are the kinds worth evaluating BEFORE the act, to find out whether the green means
15
+ * anything.
16
+ */
17
+ import { PredicateKind } from '@reticlehq/core';
18
+ export function readsDomState(predicate) {
19
+ switch (predicate.kind) {
20
+ case PredicateKind.ELEMENT:
21
+ case PredicateKind.TEXT:
22
+ return true;
23
+ case PredicateKind.ALL_OF:
24
+ case PredicateKind.ANY_OF:
25
+ return predicate.predicates.some(readsDomState);
26
+ case PredicateKind.NOT:
27
+ return readsDomState(predicate.predicate);
28
+ default:
29
+ return false;
30
+ }
31
+ }
@@ -6,12 +6,25 @@
6
6
  */
7
7
  export { BlindSpotKind } from '@reticlehq/core';
8
8
  import { BlindSpotKind, type ReticleEvent } from '@reticlehq/core';
9
- export interface BlindSpot {
9
+ interface BlindSpot {
10
10
  kind: BlindSpotKind;
11
11
  count: number;
12
12
  }
13
- export interface CoverageStatement {
14
- coverage: 'full' | 'partial';
13
+ /**
14
+ * Whether the observation window saw everything it was asked about.
15
+ *
16
+ * NOT core's VerdictStatus, which happens to spell one of its values 'partial' too: that one grades
17
+ * a verification RUN (some flows passed, some failed), this one grades what could be OBSERVED. Two
18
+ * meanings behind one string is exactly how a comparison ends up reading the wrong field, so they
19
+ * stay separate vocabularies.
20
+ */
21
+ export declare const Coverage: {
22
+ readonly FULL: "full";
23
+ readonly PARTIAL: "partial";
24
+ };
25
+ export type Coverage = (typeof Coverage)[keyof typeof Coverage];
26
+ interface CoverageStatement {
27
+ coverage: Coverage;
15
28
  /** Present only when partial — the human/agent-legible list of what went unobserved. */
16
29
  note?: string;
17
30
  spots: BlindSpot[];
@@ -8,22 +8,34 @@
8
8
  // honesty-side imports keep working.
9
9
  export { BlindSpotKind } from '@reticlehq/core';
10
10
  import { BlindSpotKind, EventType } from '@reticlehq/core';
11
+ /**
12
+ * Whether the observation window saw everything it was asked about.
13
+ *
14
+ * NOT core's VerdictStatus, which happens to spell one of its values 'partial' too: that one grades
15
+ * a verification RUN (some flows passed, some failed), this one grades what could be OBSERVED. Two
16
+ * meanings behind one string is exactly how a comparison ends up reading the wrong field, so they
17
+ * stay separate vocabularies.
18
+ */
19
+ export const Coverage = {
20
+ FULL: 'full',
21
+ PARTIAL: 'partial',
22
+ };
11
23
  const LABEL = {
12
- [BlindSpotKind.CLOSED_SHADOW_ROOT]: (n) => `${String(n)} closed shadow root${n === 1 ? '' : 's'} unobserved`,
13
- [BlindSpotKind.CROSS_ORIGIN_IFRAME]: (n) => `${String(n)} cross-origin frame${n === 1 ? '' : 's'} unobserved`,
24
+ [BlindSpotKind.CLOSED_SHADOW_ROOT]: (n) => `${String(n)} closed shadow root${1 === n ? '' : 's'} unobserved`,
25
+ [BlindSpotKind.CROSS_ORIGIN_IFRAME]: (n) => `${String(n)} cross-origin frame${1 === n ? '' : 's'} unobserved`,
14
26
  // The DOM of these frames IS observed; only their network is not. Saying so precisely matters — a
15
27
  // flat "unobserved" would discard a real capability and push agents back to guessing.
16
- [BlindSpotKind.UNINSTRUMENTED_FRAME]: (n) => `${String(n)} same-origin frame${n === 1 ? '' : 's'} observed for DOM but not network — requests they make are invisible`,
17
- [BlindSpotKind.VIRTUALIZED_UNMOUNTED]: (n) => `${String(n)} virtualized unmounted row${n === 1 ? '' : 's'} unobserved`,
28
+ [BlindSpotKind.UNINSTRUMENTED_FRAME]: (n) => `${String(n)} same-origin frame${1 === n ? '' : 's'} observed for DOM but not network — requests they make are invisible`,
29
+ [BlindSpotKind.VIRTUALIZED_UNMOUNTED]: (n) => `${String(n)} virtualized unmounted row${1 === n ? '' : 's'} unobserved`,
18
30
  // Not "some rows we could not see" — the events never reached the observer, so this window is a
19
31
  // SAMPLE of what the app did. Phrased as a caveat on what the whole result MEANS.
20
- [BlindSpotKind.RATE_LIMITED]: (n) => `${String(n)} event${n === 1 ? '' : 's'} dropped by the bridge rate cap, so this window is SAMPLED — raise RETICLE_MAX_MESSAGES_PER_SECOND for a busy app`,
32
+ [BlindSpotKind.RATE_LIMITED]: (n) => `${String(n)} event${1 === n ? '' : 's'} dropped by the bridge rate cap, so this window is SAMPLED — raise RETICLE_MAX_MESSAGES_PER_SECOND for a busy app`,
21
33
  // Not a count of things — a single fact about the page. Phrased so the coverage line reads as a
22
34
  // caveat on what the network view MEANS, not as a tally.
23
35
  // A count of unverifiable ACTIONS, not of things we failed to look at. The distinction matters:
24
36
  // nothing here was missed, there was simply never a verdict to observe, and no amount of extra
25
37
  // instrumentation would produce one.
26
- [BlindSpotKind.VERDICTLESS_SEND]: (n) => `${String(n)} one-way IPC send${n === 1 ? '' : 's'} dispatched with NO verdict — the renderer never learns whether the main process handled ${n === 1 ? 'it' : 'them'}, so this cannot be confirmed from the page`,
38
+ [BlindSpotKind.VERDICTLESS_SEND]: (n) => `${String(n)} one-way IPC send${1 === n ? '' : 's'} dispatched with NO verdict — the renderer never learns whether the main process handled ${1 === n ? 'it' : 'them'}, so this cannot be confirmed from the page`,
27
39
  [BlindSpotKind.WRAPPED_NETWORK]: () => 'fetch was already wrapped before Reticle, so recorded requests may differ from what was sent',
28
40
  // A fact about the app's wiring, not a tally. Says what the empty network view MEANS, because an
29
41
  // empty one here is indistinguishable from "this app made no backend calls" — and that reading is
@@ -53,8 +65,8 @@ export function impeachesCapture(kind) {
53
65
  /** Compose the coverage statement. `full` (no note) when nothing was unobserved. */
54
66
  export function buildCoverageStatement(spots) {
55
67
  const present = spots.filter((s) => s.count > 0);
56
- if (present.length === 0)
57
- return { coverage: 'full', spots: [] };
68
+ if (0 === present.length)
69
+ return { coverage: Coverage.FULL, spots: [] };
58
70
  // Each label carries its own ending. Appending a blanket " unobserved" here produced
59
71
  // "...may differ from what was sent unobserved" for the wrapped-network caveat, which is a
60
72
  // sentence rather than a count — and the same dangle appeared the moment a second prose-shaped
@@ -63,9 +75,9 @@ export function buildCoverageStatement(spots) {
63
75
  // daemon can report one, and `LABEL[kind](count)` threw a TypeError on the verdict path when it
64
76
  // did — turning "there is something I could not see" into a crashed assert, which is worse than
65
77
  // either the caveat or the silence. Unknown kinds degrade to their own name.
66
- const label = (s) => typeof LABEL[s.kind] === 'function' ? LABEL[s.kind](s.count) : `${s.kind} (${String(s.count)})`;
67
- const note = `partial — ${present.map(label).join(', ')}`;
68
- return { coverage: 'partial', note, spots: present };
78
+ const label = (s) => 'function' === typeof LABEL[s.kind] ? LABEL[s.kind](s.count) : `${s.kind} (${String(s.count)})`;
79
+ const note = `${Coverage.PARTIAL} — ${present.map(label).join(', ')}`;
80
+ return { coverage: Coverage.PARTIAL, note, spots: present };
69
81
  }
70
82
  /**
71
83
  * Reduce a window's BLIND_SPOT events to one spot per kind — the LATEST reported count wins (the sensor
@@ -79,7 +91,7 @@ export function blindSpotsFromEvents(events) {
79
91
  continue;
80
92
  const kind = e.data['kind'];
81
93
  const count = e.data['count'];
82
- if (typeof kind === 'string' && typeof count === 'number') {
94
+ if ('string' === typeof kind && 'number' === typeof count) {
83
95
  latest.set(kind, count);
84
96
  }
85
97
  }
@@ -14,7 +14,7 @@ export declare const HonestyGrade: {
14
14
  readonly NONE: "none";
15
15
  };
16
16
  export type HonestyGrade = (typeof HonestyGrade)[keyof typeof HonestyGrade];
17
- export interface HonestyInputs {
17
+ interface HonestyInputs {
18
18
  grade: HonestyGrade;
19
19
  /** Present when a causal chain is presented; `window` = time-heuristic, never dataflow truth. */
20
20
  attribution?: string;
@@ -43,7 +43,7 @@ export interface HonestyBlock {
43
43
  };
44
44
  }
45
45
  export declare function buildHonestyBlock(inputs: HonestyInputs): HonestyBlock;
46
- export interface HonestyBar {
46
+ interface HonestyBar {
47
47
  /** The minimum grade a green must carry to be trusted (default: any). */
48
48
  minGrade?: HonestyGrade;
49
49
  /** Require capture integrity to be clean (no truncation / blind spots). */
@@ -54,3 +54,4 @@ export declare function meetsHonestyBar(block: HonestyBlock, bar?: HonestyBar):
54
54
  ok: boolean;
55
55
  reasons: string[];
56
56
  };
57
+ export {};
@@ -26,7 +26,7 @@ const MIN_ENVELOPE_SAMPLES = 3;
26
26
  const FULL_COVERAGE_PCT = 100;
27
27
  export function buildHonestyBlock(inputs) {
28
28
  const issues = [];
29
- if (inputs.truncated === true)
29
+ if (true === inputs.truncated)
30
30
  issues.push('capture truncated');
31
31
  for (const spot of inputs.blindSpots ?? [])
32
32
  issues.push(`blind spot: ${spot}`);
@@ -46,7 +46,7 @@ export function buildHonestyBlock(inputs) {
46
46
  ? {}
47
47
  : { envelope: { samples, sufficient: samples >= MIN_ENVELOPE_SAMPLES } }),
48
48
  coverage: { ...(pct === undefined ? {} : { pct }), partial },
49
- integrity: { clean: issues.length === 0, issues },
49
+ integrity: { clean: 0 === issues.length, issues },
50
50
  };
51
51
  }
52
52
  /** Whether a verdict's honesty block clears the harness's bar. Reasons list every failed criterion. */
@@ -55,8 +55,8 @@ export function meetsHonestyBar(block, bar = {}) {
55
55
  if (bar.minGrade !== undefined && GRADE_RANK[block.grade] < GRADE_RANK[bar.minGrade]) {
56
56
  reasons.push(`grade ${block.grade} below required ${bar.minGrade}`);
57
57
  }
58
- if (bar.requireIntegrityClean === true && !block.integrity.clean) {
58
+ if (true === bar.requireIntegrityClean && !block.integrity.clean) {
59
59
  reasons.push(`integrity not clean: ${block.integrity.issues.join('; ')}`);
60
60
  }
61
- return { ok: reasons.length === 0, reasons };
61
+ return { ok: 0 === reasons.length, reasons };
62
62
  }
@@ -15,7 +15,7 @@ const BODY_BEARING_METHODS = new Set(['POST', 'PUT', 'PATCH']);
15
15
  */
16
16
  export function bodiesNotCaptured(calls) {
17
17
  const bodyBearing = calls.filter((c) => BODY_BEARING_METHODS.has((c.method ?? '').toUpperCase()));
18
- if (bodyBearing.length === 0)
18
+ if (0 === bodyBearing.length)
19
19
  return {};
20
20
  if (bodyBearing.some((c) => c.requestBody !== undefined))
21
21
  return {};
@@ -36,7 +36,7 @@ export function hasUnreadWriteOutcome(events) {
36
36
  return events.some((event) => {
37
37
  if (event.type !== EventType.NET_REQUEST)
38
38
  return false;
39
- const method = (typeof event.data['method'] === 'string' ? event.data['method'] : '').toUpperCase();
39
+ const method = ('string' === typeof event.data['method'] ? event.data['method'] : '').toUpperCase();
40
40
  if (method === IPC_METHOD || !MUTATING_METHODS.includes(method))
41
41
  return false;
42
42
  const status = event.data['status'];
@@ -45,6 +45,6 @@ export function hasUnreadWriteOutcome(events) {
45
45
  if (event.data['responseBody'] !== undefined)
46
46
  return false; // read — findBodyFailures judged it
47
47
  const size = event.data['responseSize'];
48
- return typeof size === 'number' && size > 0;
48
+ return 'number' === typeof size && size > 0;
49
49
  });
50
50
  }
@@ -1,4 +1,4 @@
1
- import { Verified } from '@reticlehq/core';
1
+ import { Verified, VerifiedReason } from '@reticlehq/core';
2
2
  import { type HonestyBlock } from './honesty.js';
3
3
  /**
4
4
  * The decision rule: eight trust dimensions in, one answer out.
@@ -11,10 +11,21 @@ import { type HonestyBlock } from './honesty.js';
11
11
  * Ordering is deliberate, because the first matching clause also writes `because`, and the reader
12
12
  * should be told the most actionable fact rather than the first true one.
13
13
  */
14
- export interface VerifiedInputs {
14
+ interface VerifiedInputs {
15
15
  /** Did the declared consequence hold? Undefined when the action declared none. */
16
16
  pass?: boolean;
17
17
  honesty: HonestyBlock;
18
+ /**
19
+ * Set when the assertion could not be EVALUATED at all — an under-specified call, or nothing
20
+ * instrumented to read. Carries the sentence naming what is missing.
21
+ */
22
+ inconclusive?: string;
23
+ /**
24
+ * The declared consequence was ALREADY TRUE before the action ran, so its holding afterwards says
25
+ * nothing about the action. Only meaningful for predicates that read live DOM state — event-based
26
+ * ones are floored at the act's cursor and cannot be satisfied by the past.
27
+ */
28
+ alreadyTrue?: boolean;
18
29
  /** Cross-channel disagreements found in the action's window. */
19
30
  contradictions?: readonly {
20
31
  kind: string;
@@ -32,9 +43,17 @@ export interface VerifiedInputs {
32
43
  */
33
44
  outcomeUnread?: boolean;
34
45
  }
35
- export interface VerifiedVerdict {
46
+ interface VerifiedVerdict {
36
47
  verified: Verified;
48
+ /**
49
+ * WHICH clause below decided this, as a closed enum. `verified` has three values and this rule has
50
+ * ten clauses, so the verdict alone collapses opposite facts — "Reticle caught a real bug", "the
51
+ * agent wrote a bad predicate" and "Reticle could not see" all arrived as one string. Named here,
52
+ * beside the sentence, so the vocabulary cannot drift from the branches that produce it.
53
+ */
54
+ verifiedReason: VerifiedReason;
37
55
  /** One sentence naming the deciding evidence — never a restatement of the field. */
38
56
  because: string;
39
57
  }
40
58
  export declare function decideVerified(inputs: VerifiedInputs): VerifiedVerdict;
59
+ export {};
@@ -1,10 +1,25 @@
1
- import { Verified } from '@reticlehq/core';
1
+ import { Verified, VerifiedReason } from '@reticlehq/core';
2
2
  import { HonestyGrade } from './honesty.js';
3
3
  export function decideVerified(inputs) {
4
4
  const { pass, honesty, contradictions = [], settled, outcomePending, outcomeUnread } = inputs;
5
- // A failed assertion is the most actionable fact there is; it leads.
6
- if (pass === false) {
7
- return { verified: Verified.NO, because: 'the declared consequence did not hold' };
5
+ // Ahead of the failure clause, because a failure is only the most actionable fact when there WAS
6
+ // one. An assertion nobody could evaluate is not a defect in the app, and calling it one was
7
+ // putting the agent's own malformed calls into the bug count.
8
+ if (inputs.inconclusive !== undefined) {
9
+ return {
10
+ verified: Verified.UNKNOWN,
11
+ verifiedReason: VerifiedReason.INCONCLUSIVE,
12
+ because: `the assertion could not be evaluated: ${inputs.inconclusive}`,
13
+ };
14
+ }
15
+ // A failed assertion is the most actionable fact there is; it leads — including over
16
+ // `alreadyTrue`, because a condition that held before AND fails now is a real regression.
17
+ if (false === pass) {
18
+ return {
19
+ verified: Verified.NO,
20
+ verifiedReason: VerifiedReason.ASSERTION_FAILED,
21
+ because: 'the declared consequence did not hold',
22
+ };
8
23
  }
9
24
  // A contradiction outranks a passing assertion, and that inversion is the whole point: the case
10
25
  // this product exists to catch is a green assertion sitting on top of a failed write. Measured on
@@ -14,15 +29,35 @@ export function decideVerified(inputs) {
14
29
  const kinds = contradictions.map((c) => c.kind).join(', ');
15
30
  return {
16
31
  verified: Verified.NO,
32
+ verifiedReason: VerifiedReason.CONTRADICTED,
17
33
  because: `channels disagree about this action (${kinds}) even though the assertion passed`,
18
34
  };
19
35
  }
36
+ // Below the contradiction clause, and for the same reason a contradiction outranks a dirty
37
+ // capture: evidence AGAINST beats absence of evidence, whichever absence it is. Both can hold at
38
+ // once — assert `{ text: 'Saved' }` that was already on screen while the write 500s — and ordering
39
+ // this first downgraded a DETECTED false green from NO to UNKNOWN, which reads as "assert
40
+ // something else" rather than "this is broken".
41
+ //
42
+ // A green that was already green before the action is not evidence about the action. Measured in
43
+ // the field: a click asserted with `{ text: 'Parallel Routes' }` returned verified "yes" in 478ms
44
+ // with routeChanges 0, because the text was the nav link already on screen — the real navigation
45
+ // landed 1.8s later. UNKNOWN rather than NO on purpose: the app may well be fine, and reporting a
46
+ // failure we did not observe would be its own false claim.
47
+ if (true === inputs.alreadyTrue) {
48
+ return {
49
+ verified: Verified.UNKNOWN,
50
+ verifiedReason: VerifiedReason.ALREADY_TRUE,
51
+ because: 'the declared consequence was already true before this action, so it proves nothing about it — assert something the action CHANGES (a signal, a request, a route, or store state)',
52
+ };
53
+ }
20
54
  // Dirty capture is NOT failure. The layer could not see part of the window, so any green is a
21
55
  // statement about what it happened to observe — which is precisely the thing that must not be
22
56
  // reported as proof.
23
57
  if (!honesty.integrity.clean) {
24
58
  return {
25
59
  verified: Verified.UNKNOWN,
60
+ verifiedReason: VerifiedReason.UNCLEAN_CAPTURE,
26
61
  because: `capture was not clean (${honesty.integrity.issues.join('; ')}), so a green here would only describe what was observed`,
27
62
  };
28
63
  }
@@ -32,6 +67,7 @@ export function decideVerified(inputs) {
32
67
  if (honesty.grade === HonestyGrade.NONE) {
33
68
  return {
34
69
  verified: Verified.UNKNOWN,
70
+ verifiedReason: VerifiedReason.VACUOUS_GRADE,
35
71
  because: 'nothing was asserted at a real grade, so passing proves nothing — assert a signal, request, or state path',
36
72
  };
37
73
  }
@@ -43,9 +79,10 @@ export function decideVerified(inputs) {
43
79
  // optimistically rendered "dispatched", the page settled, and the verdict came back `yes` — then
44
80
  // the server REVERTED it to `held` 1.2s later. Every channel agreed, and every channel was early.
45
81
  // UNKNOWN rather than NO: nothing has failed, and saying it has would be its own false report.
46
- if (outcomePending === true) {
82
+ if (true === outcomePending) {
47
83
  return {
48
84
  verified: Verified.UNKNOWN,
85
+ verifiedReason: VerifiedReason.OUTCOME_PENDING,
49
86
  because: 'a write returned 202 Accepted, so the server has not finished processing it — this window cannot contain the outcome; re-check once it reconciles',
50
87
  };
51
88
  }
@@ -56,16 +93,18 @@ export function decideVerified(inputs) {
56
93
  //
57
94
  // UNKNOWN, not NO: nothing is known to have failed. The remedy is in the sentence, because an
58
95
  // agent that cannot act on a caveat will learn to skip it.
59
- if (outcomeUnread === true) {
96
+ if (true === outcomeUnread) {
60
97
  return {
61
98
  verified: Verified.UNKNOWN,
99
+ verifiedReason: VerifiedReason.OUTCOME_UNREAD,
62
100
  because: 'a write returned 2xx with a response body that was never recorded, so its outcome is unread — a 200 describes the transport, not the result (a batch reports per-item failures in the body, and every GraphQL error is a 200). Enable it where your app calls connect(): `reticle.connect({ captureNetworkBodies: true })`, then re-run',
63
101
  };
64
102
  }
65
103
  // Never settled: the page may still be moving, so the observation window may have closed early.
66
- if (settled === false) {
104
+ if (false === settled) {
67
105
  return {
68
106
  verified: Verified.UNKNOWN,
107
+ verifiedReason: VerifiedReason.UNSETTLED,
69
108
  because: 'the page never settled, so the reaction window may have closed before the app finished',
70
109
  };
71
110
  }
@@ -79,7 +118,8 @@ export function decideVerified(inputs) {
79
118
  // own. Seen on a one-way IPC send: coverage said the outcome was unobservable, `because` said clean.
80
119
  return {
81
120
  verified: Verified.YES,
82
- because: honesty.coverage?.partial === true
121
+ verifiedReason: VerifiedReason.PROVED,
122
+ because: true === honesty.coverage?.partial
83
123
  ? `assertion held at ${honesty.grade} grade with no channel disagreeing, but coverage was PARTIAL — see \`coverage\` for what went unobserved`
84
124
  : `assertion held at ${honesty.grade} grade over a clean capture with no channel disagreeing`,
85
125
  };
@@ -1,9 +1,10 @@
1
1
  import * as http from 'node:http';
2
2
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
3
3
  import { MCP_SSE_PATH, MCP_MESSAGE_PATH, STATUS_PATH } from '@reticlehq/core';
4
+ import { noteAgentPeer, PEER_VERSION_PARAM, PEER_CONTRACT_PARAM } from './version/peer-announce.js';
4
5
  import { log } from './log.js';
5
6
  import { reportMcpConnected } from './telemetry/mcp-connection.js';
6
- import { isLoopbackHost, isLocalWebOrigin, isLoopbackPeer, requestToken, tokensMatch, } from './token-auth.js';
7
+ import { isLoopbackHost, isLocalWebOrigin, isLoopbackPeer, requestToken, tokensMatch, } from './bridge/token-auth.js';
7
8
  /**
8
9
  * Creates a shared HTTP server that handles both the WebSocket bridge (browser SDK) and the
9
10
  * SSE MCP transport (Claude/agent). Does NOT call listen — caller controls that.
@@ -52,13 +53,19 @@ export function createSharedServer(options = {}) {
52
53
  return;
53
54
  }
54
55
  }
55
- if (req.method === 'GET' && path === STATUS_PATH) {
56
+ if ('GET' === req.method && path === STATUS_PATH) {
56
57
  const body = JSON.stringify(statusProvider?.() ?? { running: true });
57
58
  res.writeHead(200, { 'Content-Type': 'application/json' });
58
59
  res.end(body);
59
60
  return;
60
61
  }
61
- if (req.method === 'GET' && path === MCP_SSE_PATH) {
62
+ if ('GET' === req.method && path === MCP_SSE_PATH) {
63
+ // The agent's MCP server announces itself here, on the connect it already makes. The daemon is
64
+ // the single judge of skew, so this is where the third pair is decided — and unlike the CLI's
65
+ // own check (a stderr line no agent reads), a nudge queued here rides out on the agent's next
66
+ // tool result. That is the pair the user hits after `npm update`: a cached npx MCP package
67
+ // talking to a daemon from a different build.
68
+ noteAgentPeer(url.searchParams.get(PEER_VERSION_PARAM), url.searchParams.get(PEER_CONTRACT_PARAM));
62
69
  if (mcpFactory === undefined) {
63
70
  res.writeHead(503, { 'Content-Type': 'text/plain' });
64
71
  res.end('MCP server not ready');
@@ -71,14 +78,14 @@ export function createSharedServer(options = {}) {
71
78
  const transport = new SSEServerTransport(MCP_MESSAGE_PATH, res);
72
79
  const sid = transport.sessionId;
73
80
  transports.set(sid, transport);
74
- if (transports.size === 1)
81
+ if (1 === transports.size)
75
82
  agentPresence?.(true); // first agent attached
76
83
  res.on('close', () => {
77
84
  transports.delete(sid);
78
85
  transport.close().catch(() => undefined);
79
86
  mcpServer.close().catch(() => undefined);
80
87
  log('mcp_client_disconnected', { sessionId: sid });
81
- if (transports.size === 0)
88
+ if (0 === transports.size)
82
89
  agentPresence?.(false); // last agent detached → it's the human's turn
83
90
  });
84
91
  mcpServer
@@ -96,9 +103,9 @@ export function createSharedServer(options = {}) {
96
103
  });
97
104
  return;
98
105
  }
99
- if (req.method === 'POST' && path === MCP_MESSAGE_PATH) {
106
+ if ('POST' === req.method && path === MCP_MESSAGE_PATH) {
100
107
  const sessionId = url.searchParams.get('sessionId');
101
- if (sessionId === null) {
108
+ if (null === sessionId) {
102
109
  res.writeHead(400, { 'Content-Type': 'text/plain' });
103
110
  res.end('missing sessionId');
104
111
  return;
@@ -33,7 +33,7 @@ export interface HuntRun {
33
33
  /** Controls actually driven. A run that drove nothing proves nothing and is reported separately. */
34
34
  stepsRun?: number;
35
35
  }
36
- export interface HuntSummary {
36
+ interface HuntSummary {
37
37
  runs: number;
38
38
  /** Runs that actually drove at least one control. The denominator that can honestly be quoted. */
39
39
  runsWithCoverage: number;
@@ -48,3 +48,4 @@ export interface HuntSummary {
48
48
  headline: string;
49
49
  }
50
50
  export declare function summarizeHunt(runs: readonly HuntRun[]): HuntSummary;
51
+ export {};
@@ -74,10 +74,10 @@ export function summarizeHunt(runs) {
74
74
  * this project exists to distrust.
75
75
  */
76
76
  function buildHeadline(withCoverage, flaggedRuns, contradictions) {
77
- if (withCoverage === 0) {
77
+ if (0 === withCoverage) {
78
78
  return 'no run drove a single control — nothing was measured, which is not the same as nothing being wrong';
79
79
  }
80
- if (flaggedRuns === 0) {
80
+ if (0 === flaggedRuns) {
81
81
  return `${String(withCoverage)} merged changes crawled, no cross-channel contradictions found — confirm coverage was real before reading this as clean`;
82
82
  }
83
83
  return `${String(flaggedRuns)} of ${String(withCoverage)} merged, already-green changes carried a candidate false green (${String(contradictions)} contradictions) — each needs manual confirmation before it is counted`;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { Bridge } from './bridge.js';
1
+ import { Bridge } from './bridge/bridge.js';
2
2
  import type { OwnedRealInputProvider, RealInputProvider, InjectConnectOptions } from './input/real-input.js';
3
3
  export { ReticleTool } from './tools/tool-names.js';
4
4
  export { RingBuffer } from './events/ring-buffer.js';
5
- export { Bridge } from './bridge.js';
5
+ export { Bridge } from './bridge/bridge.js';
6
6
  export { Session, SessionManager } from './session/session.js';
7
7
  export type { SessionInfo, SessionHealth } from './session/session.js';
8
8
  export { buildSessionRecommendation } from './session/session-recommendation.js';
@@ -33,12 +33,12 @@ export { BrowserPool, DEFAULT_LEASE_TTL_MS } from './pool/browser-pool.js';
33
33
  export type { Lease, Launcher, PooledBrowser } from './pool/browser-pool.js';
34
34
  export { playwrightLauncher, resolveMaxContexts } from './pool/playwright-launcher.js';
35
35
  export { appendReticleParams } from './tools/lease-tools.js';
36
- export { writePid, removePid, isRunning, logPath, readPid, isAlive } from './daemon.js';
36
+ export { writePid, removePid, isRunning, logPath, readPid, isAlive } from './daemon/daemon.js';
37
37
  export type { CrawlReport, CrawlAnomaly, CrawlOptions, CrawlSession } from './crawl/crawl.js';
38
38
  export { scrollToFind } from './input/scroll-find.js';
39
39
  export type { ScrollFindResult, ScrollFindQuery, ScrollFindSession } from './input/scroll-find.js';
40
- export { CORE_TOOL_NAMES, TOOL_PROFILE, TOOL_PROFILE_ENV, filterTools, resolveToolProfile, } from './tools/profiles.js';
41
- export type { ToolProfile } from './tools/profiles.js';
40
+ export { CORE_TOOL_NAMES, TOOL_SURFACE, TOOL_PROFILE_ENV, filterTools, resolveToolSurface, } from './tools/tool-surface.js';
41
+ export type { ToolSurface } from './tools/tool-surface.js';
42
42
  export { AnnotationStore } from './flows/annotation-store.js';
43
43
  export { replayFlow, nearestTestid } from './flows/flow-replay.js';
44
44
  export type { FlowReplaySession, WaitForSignal } from './flows/flow-replay.js';
@@ -118,11 +118,13 @@ export interface RunningServer {
118
118
  /** True when nothing is using the daemon: no agent connected, no browser session, no pool lease.
119
119
  * The daemon entry (cli.ts) polls this to self-shut-down when idle so Reticle never lingers. */
120
120
  isIdle?: () => boolean;
121
+ /** True while an agent's MCP client is attached — see IdleShutdownOptions.agentAttached. */
122
+ agentAttached?: () => boolean;
121
123
  /** The pairing token the bridge is enforcing (explicit, env, or auto-provisioned); undefined if none. */
122
124
  token?: string;
123
125
  close: () => Promise<void>;
124
126
  }
125
- export { resolveBridgeSecurity } from './bridge-security.js';
127
+ export { resolveBridgeSecurity } from './bridge/bridge-security.js';
126
128
  /** Start the Reticle bridge (browser WS endpoint) and, by default, the MCP stdio server. */
127
129
  export declare function start(options?: StartOptions): Promise<RunningServer>;
128
130
  /**