@reticlehq/server 2.3.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 (424) 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} +105 -15
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -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/cli-parse.d.ts +143 -0
  25. package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
  26. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
  27. package/dist/{cli-port.js → cli/cli-port.js} +29 -8
  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 +182 -93
  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.d.ts +0 -6
  88. package/dist/flows/decision.js +64 -8
  89. package/dist/flows/empty-flow.d.ts +6 -0
  90. package/dist/flows/empty-flow.js +24 -0
  91. package/dist/flows/flake-store.d.ts +0 -1
  92. package/dist/flows/flake-store.js +1 -1
  93. package/dist/flows/flake.d.ts +2 -1
  94. package/dist/flows/flake.js +2 -2
  95. package/dist/flows/flow-classify.js +12 -0
  96. package/dist/flows/flow-replay-run.js +4 -4
  97. package/dist/flows/flow-replay.d.ts +5 -7
  98. package/dist/flows/flow-replay.js +114 -47
  99. package/dist/flows/flow-report.js +1 -1
  100. package/dist/flows/flow-scope.d.ts +1 -6
  101. package/dist/flows/flow-step-runners.d.ts +26 -6
  102. package/dist/flows/flow-step-runners.js +157 -6
  103. package/dist/flows/flow-success.js +20 -15
  104. package/dist/flows/flow-tools.js +67 -13
  105. package/dist/flows/flows.js +15 -11
  106. package/dist/flows/gate.d.ts +4 -3
  107. package/dist/flows/gate.js +1 -1
  108. package/dist/flows/heal-run.d.ts +0 -8
  109. package/dist/flows/heal-run.js +5 -5
  110. package/dist/flows/heal.js +3 -3
  111. package/dist/flows/predicate-to-expect.d.ts +38 -0
  112. package/dist/flows/predicate-to-expect.js +95 -0
  113. package/dist/flows/replay.d.ts +16 -1
  114. package/dist/flows/replay.js +58 -22
  115. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  116. package/dist/flows/role-anchor-nearest.js +45 -0
  117. package/dist/flows/server-verify.d.ts +1 -1
  118. package/dist/flows/server-verify.js +5 -5
  119. package/dist/flows/verify-change-tools.js +32 -10
  120. package/dist/flows/verify-change-verdict.d.ts +15 -0
  121. package/dist/flows/verify-change-verdict.js +25 -0
  122. package/dist/flows/watch-batcher.d.ts +3 -2
  123. package/dist/honesty/already-true.d.ts +2 -0
  124. package/dist/honesty/already-true.js +31 -0
  125. package/dist/honesty/blind-spots.d.ts +16 -3
  126. package/dist/honesty/blind-spots.js +24 -12
  127. package/dist/honesty/honesty.d.ts +3 -2
  128. package/dist/honesty/honesty.js +4 -4
  129. package/dist/honesty/uncaptured-bodies.js +1 -1
  130. package/dist/honesty/unread-outcome.js +2 -2
  131. package/dist/honesty/verified.d.ts +22 -3
  132. package/dist/honesty/verified.js +48 -8
  133. package/dist/http-server.js +14 -7
  134. package/dist/hunt/hunt-report.d.ts +2 -1
  135. package/dist/hunt/hunt-report.js +2 -2
  136. package/dist/index.d.ts +8 -6
  137. package/dist/index.js +32 -25
  138. package/dist/init/agent-rules.d.ts +2 -1
  139. package/dist/init/agent-rules.js +45 -7
  140. package/dist/init/app-choice.d.ts +20 -0
  141. package/dist/init/app-choice.js +25 -0
  142. package/dist/init/astro-host.d.ts +21 -0
  143. package/dist/init/astro-host.js +27 -0
  144. package/dist/init/astro-patch.d.ts +16 -0
  145. package/dist/init/astro-patch.js +240 -0
  146. package/dist/init/capabilities.d.ts +17 -0
  147. package/dist/init/capabilities.js +54 -0
  148. package/dist/init/cra.d.ts +37 -0
  149. package/dist/init/cra.js +90 -0
  150. package/dist/init/cursor.js +39 -4
  151. package/dist/init/desktop-doctor.d.ts +3 -2
  152. package/dist/init/desktop-doctor.js +4 -4
  153. package/dist/init/detect.d.ts +26 -0
  154. package/dist/init/detect.js +78 -5
  155. package/dist/init/mcp-registered.d.ts +12 -0
  156. package/dist/init/mcp-registered.js +14 -0
  157. package/dist/init/mcp.d.ts +27 -2
  158. package/dist/init/mcp.js +40 -4
  159. package/dist/init/next-patch.d.ts +39 -0
  160. package/dist/init/next-patch.js +196 -0
  161. package/dist/init/node-io.js +48 -6
  162. package/dist/init/patch-kind.d.ts +20 -0
  163. package/dist/init/patch-kind.js +10 -0
  164. package/dist/init/plan-framework.d.ts +50 -0
  165. package/dist/init/plan-framework.js +341 -0
  166. package/dist/init/plan.d.ts +119 -6
  167. package/dist/init/plan.js +230 -131
  168. package/dist/init/project-id.d.ts +5 -9
  169. package/dist/init/project-id.js +10 -22
  170. package/dist/init/run.d.ts +22 -0
  171. package/dist/init/run.js +393 -28
  172. package/dist/init/slash-command.d.ts +27 -0
  173. package/dist/init/slash-command.js +61 -0
  174. package/dist/init/snippets.d.ts +41 -3
  175. package/dist/init/snippets.js +185 -10
  176. package/dist/init/vite-config.d.ts +4 -10
  177. package/dist/init/vite-config.js +15 -7
  178. package/dist/init/workspace-apps.d.ts +23 -0
  179. package/dist/init/workspace-apps.js +68 -0
  180. package/dist/input/driven-redaction.d.ts +15 -0
  181. package/dist/input/driven-redaction.js +76 -0
  182. package/dist/input/network-detail.d.ts +9 -3
  183. package/dist/input/network-detail.js +43 -23
  184. package/dist/input/network-mock-tools.js +2 -2
  185. package/dist/input/network-mock.js +4 -4
  186. package/dist/input/real-input.js +8 -3
  187. package/dist/input/scroll-find.js +2 -2
  188. package/dist/input/scroll-tools.d.ts +0 -5
  189. package/dist/input/scroll-tools.js +11 -4
  190. package/dist/input/viewport-tools.js +2 -2
  191. package/dist/journal/ambient-store.d.ts +0 -2
  192. package/dist/journal/ambient-store.js +1 -1
  193. package/dist/journal/ambient.js +1 -1
  194. package/dist/journal/attach-journal.d.ts +2 -1
  195. package/dist/journal/deviation-report.js +6 -6
  196. package/dist/journal/deviation-service.js +1 -1
  197. package/dist/journal/envelope-store.d.ts +0 -2
  198. package/dist/journal/envelope-store.js +1 -1
  199. package/dist/journal/envelope.d.ts +2 -3
  200. package/dist/journal/envelope.js +3 -3
  201. package/dist/journal/journal-query.js +1 -1
  202. package/dist/journal/journal-recorder.d.ts +2 -1
  203. package/dist/journal/journal-recorder.js +2 -2
  204. package/dist/journal/rollups.js +9 -9
  205. package/dist/journal/session-end.d.ts +2 -1
  206. package/dist/journal/session-journal.js +4 -4
  207. package/dist/license/license.d.ts +0 -14
  208. package/dist/license/license.js +8 -8
  209. package/dist/log.d.ts +10 -0
  210. package/dist/log.js +11 -1
  211. package/dist/mcp/mcp-is-error.d.ts +13 -0
  212. package/dist/mcp/mcp-is-error.js +18 -0
  213. package/dist/mcp/mcp-outage.d.ts +31 -0
  214. package/dist/mcp/mcp-outage.js +48 -0
  215. package/dist/mcp/mcp-proxy.d.ts +124 -0
  216. package/dist/mcp/mcp-proxy.js +697 -0
  217. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  218. package/dist/{mcp.js → mcp/mcp.js} +110 -35
  219. package/dist/mcp/proxy-handshake.d.ts +3 -0
  220. package/dist/mcp/proxy-handshake.js +54 -0
  221. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  222. package/dist/mcp/proxy-lifecycle.js +70 -0
  223. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  224. package/dist/mcp/tool-catalog-cache.js +55 -0
  225. package/dist/oracles/propose-consequences.d.ts +2 -1
  226. package/dist/oracles/propose-consequences.js +16 -11
  227. package/dist/oracles/self-instrument.d.ts +2 -1
  228. package/dist/oracles/self-instrument.js +1 -1
  229. package/dist/phenomena/phenomena.js +3 -3
  230. package/dist/platform.d.ts +16 -0
  231. package/dist/platform.js +16 -0
  232. package/dist/pool/playwright-launcher.d.ts +15 -2
  233. package/dist/pool/playwright-launcher.js +21 -2
  234. package/dist/project/fs-port.js +1 -1
  235. package/dist/project/project-tools.js +2 -2
  236. package/dist/runs/build-verification-run.js +1 -1
  237. package/dist/runs/repair-prompt.d.ts +0 -6
  238. package/dist/runs/repair-prompt.js +3 -3
  239. package/dist/runs/risk-classify.js +1 -1
  240. package/dist/runs/run-diff.d.ts +0 -2
  241. package/dist/runs/run-diff.js +3 -3
  242. package/dist/runs/run-tools.js +2 -2
  243. package/dist/runs/verification-sync.js +2 -2
  244. package/dist/runs/verify-http.js +1 -1
  245. package/dist/runs/verify-server.js +1 -1
  246. package/dist/session/command-timeout.d.ts +11 -3
  247. package/dist/session/command-timeout.js +2 -2
  248. package/dist/session/control-envelope.d.ts +6 -0
  249. package/dist/session/control-envelope.js +7 -1
  250. package/dist/session/dev-server-probe.d.ts +13 -0
  251. package/dist/session/dev-server-probe.js +52 -0
  252. package/dist/session/last-act.d.ts +17 -3
  253. package/dist/session/last-act.js +16 -4
  254. package/dist/session/live-control-tools.js +7 -2
  255. package/dist/session/live-control.js +1 -1
  256. package/dist/session/looks-like-dev-server.d.ts +14 -0
  257. package/dist/session/looks-like-dev-server.js +25 -0
  258. package/dist/session/no-session-diagnosis.d.ts +38 -0
  259. package/dist/session/no-session-diagnosis.js +70 -0
  260. package/dist/session/no-session-watch.d.ts +19 -0
  261. package/dist/session/no-session-watch.js +61 -0
  262. package/dist/session/observed-state.d.ts +4 -0
  263. package/dist/session/observed-state.js +19 -1
  264. package/dist/session/output-budget.js +1 -1
  265. package/dist/session/session-health.d.ts +8 -1
  266. package/dist/session/session-health.js +8 -7
  267. package/dist/session/session-info.d.ts +26 -7
  268. package/dist/session/session-info.js +42 -1
  269. package/dist/session/session-lease.d.ts +0 -11
  270. package/dist/session/session-lease.js +1 -1
  271. package/dist/session/session-manager.d.ts +3 -0
  272. package/dist/session/session-manager.js +58 -9
  273. package/dist/session/session-readiness.d.ts +1 -1
  274. package/dist/session/session-readiness.js +6 -1
  275. package/dist/session/session-reaper.js +1 -1
  276. package/dist/session/session-reconnect.d.ts +32 -0
  277. package/dist/session/session-reconnect.js +42 -0
  278. package/dist/session/session.d.ts +20 -2
  279. package/dist/session/session.js +76 -26
  280. package/dist/session/state-select.d.ts +1 -1
  281. package/dist/session/state-select.js +1 -1
  282. package/dist/status-payload.d.ts +19 -0
  283. package/dist/status-payload.js +11 -0
  284. package/dist/telemetry/argument-shape.js +10 -1
  285. package/dist/telemetry/browser-mode.d.ts +27 -0
  286. package/dist/telemetry/browser-mode.js +33 -0
  287. package/dist/telemetry/bug-found.d.ts +17 -21
  288. package/dist/telemetry/bug-found.js +120 -8
  289. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  290. package/dist/telemetry/cli-telemetry.js +27 -4
  291. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  292. package/dist/telemetry/daemon-telemetry.js +12 -2
  293. package/dist/telemetry/dev-repo.js +4 -4
  294. package/dist/telemetry/error-fingerprint.js +21 -2
  295. package/dist/telemetry/feedback-cli.d.ts +1 -1
  296. package/dist/telemetry/feedback-cli.js +4 -4
  297. package/dist/telemetry/feedback-context.d.ts +22 -0
  298. package/dist/telemetry/feedback-context.js +41 -1
  299. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  300. package/dist/telemetry/feedback-delivery.js +30 -0
  301. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  302. package/dist/telemetry/feedback-outbox.js +87 -0
  303. package/dist/telemetry/feedback.d.ts +22 -1
  304. package/dist/telemetry/feedback.js +67 -8
  305. package/dist/telemetry/git-facts.js +1 -1
  306. package/dist/telemetry/session-metrics.d.ts +2 -0
  307. package/dist/telemetry/session-metrics.js +68 -6
  308. package/dist/telemetry/telemetry.d.ts +27 -2
  309. package/dist/telemetry/telemetry.js +119 -29
  310. package/dist/telemetry/verification-of.d.ts +22 -0
  311. package/dist/telemetry/verification-of.js +84 -0
  312. package/dist/tools/act-capsule.js +2 -2
  313. package/dist/tools/act-danger.d.ts +12 -0
  314. package/dist/tools/act-danger.js +20 -3
  315. package/dist/tools/act-helpers.js +4 -4
  316. package/dist/tools/act-tools.d.ts +0 -8
  317. package/dist/tools/act-tools.js +84 -115
  318. package/dist/tools/act-view.js +7 -7
  319. package/dist/tools/alias-args.d.ts +17 -0
  320. package/dist/tools/alias-args.js +25 -0
  321. package/dist/tools/assert-grade.js +9 -9
  322. package/dist/tools/assert-verdict.d.ts +3 -1
  323. package/dist/tools/assert-verdict.js +8 -5
  324. package/dist/tools/browser-tools.js +30 -11
  325. package/dist/tools/contract-tools.js +1 -1
  326. package/dist/tools/coverage-identity.d.ts +34 -0
  327. package/dist/tools/coverage-identity.js +46 -0
  328. package/dist/tools/coverage-tools.js +10 -14
  329. package/dist/tools/dynamic-tools.d.ts +2 -1
  330. package/dist/tools/dynamic-tools.js +90 -18
  331. package/dist/tools/error-recovery.d.ts +20 -2
  332. package/dist/tools/error-recovery.js +179 -4
  333. package/dist/tools/feedback-tools.d.ts +12 -1
  334. package/dist/tools/feedback-tools.js +28 -5
  335. package/dist/tools/invoke-tool.d.ts +0 -6
  336. package/dist/tools/invoke-tool.js +57 -32
  337. package/dist/tools/lease-hint.d.ts +17 -0
  338. package/dist/tools/lease-hint.js +24 -0
  339. package/dist/tools/lease-tools.js +6 -5
  340. package/dist/tools/merge-tools.d.ts +10 -1
  341. package/dist/tools/merge-tools.js +9 -3
  342. package/dist/tools/merged-name-redirect.d.ts +13 -0
  343. package/dist/tools/merged-name-redirect.js +55 -0
  344. package/dist/tools/navigate-result.d.ts +17 -0
  345. package/dist/tools/navigate-result.js +31 -0
  346. package/dist/tools/observe-tools.js +54 -20
  347. package/dist/tools/observed-nothing.d.ts +25 -0
  348. package/dist/tools/observed-nothing.js +33 -0
  349. package/dist/tools/query-paginate.js +2 -2
  350. package/dist/tools/query-shape.d.ts +18 -0
  351. package/dist/tools/query-shape.js +39 -0
  352. package/dist/tools/read-tools.js +85 -20
  353. package/dist/tools/real-input-attempt.d.ts +28 -0
  354. package/dist/tools/real-input-attempt.js +88 -0
  355. package/dist/tools/reconcile-tools.js +7 -7
  356. package/dist/tools/reload-result.d.ts +14 -0
  357. package/dist/tools/reload-result.js +29 -0
  358. package/dist/tools/snapshot-delta.d.ts +4 -5
  359. package/dist/tools/snapshot-delta.js +0 -0
  360. package/dist/tools/tool-kit.d.ts +8 -0
  361. package/dist/tools/tool-surface.d.ts +83 -0
  362. package/dist/tools/tool-surface.js +204 -0
  363. package/dist/tools/tools-helpers.js +6 -6
  364. package/dist/tools/tools.d.ts +15 -0
  365. package/dist/tools/tools.js +53 -17
  366. package/dist/tools/unadvertised-help.d.ts +5 -0
  367. package/dist/tools/unadvertised-help.js +39 -0
  368. package/dist/trace.d.ts +69 -0
  369. package/dist/trace.js +150 -0
  370. package/dist/update/nudge-credit.d.ts +4 -0
  371. package/dist/update/nudge-credit.js +53 -0
  372. package/dist/update/sdk-sync.d.ts +21 -0
  373. package/dist/update/sdk-sync.js +42 -0
  374. package/dist/update/update-checker.js +3 -3
  375. package/dist/update/update-nudge.d.ts +63 -6
  376. package/dist/update/update-nudge.js +128 -15
  377. package/dist/update/updater.d.ts +1 -9
  378. package/dist/update/updater.js +13 -8
  379. package/dist/version/peer-announce.d.ts +4 -0
  380. package/dist/version/peer-announce.js +30 -0
  381. package/dist/{server-version.js → version/server-version.js} +5 -1
  382. package/dist/version/version-nudge.d.ts +28 -0
  383. package/dist/version/version-nudge.js +40 -0
  384. package/dist/version/version-skew.d.ts +66 -0
  385. package/dist/version/version-skew.js +71 -0
  386. package/dist/visual/visual-diff.js +2 -2
  387. package/dist/visual/visual-tools.js +4 -4
  388. package/docs/agent-cheatsheet.md +85 -0
  389. package/docs/architecture.md +113 -0
  390. package/docs/benchmarks.md +255 -0
  391. package/docs/debugging.md +102 -0
  392. package/docs/deploy-checks.md +69 -0
  393. package/docs/desktop-apps.md +256 -0
  394. package/docs/enterprise.md +62 -0
  395. package/docs/fixtures.md +28 -0
  396. package/docs/flows.md +166 -0
  397. package/docs/getting-started.md +469 -0
  398. package/docs/human-control.md +63 -0
  399. package/docs/integration-patterns.md +171 -0
  400. package/docs/local-registry.md +126 -0
  401. package/docs/mint.json +61 -0
  402. package/docs/multi-agent-testing.md +55 -0
  403. package/docs/platform-integration.md +122 -0
  404. package/docs/telemetry-contract.md +214 -0
  405. package/docs/telemetry.md +184 -0
  406. package/docs/testing.md +82 -0
  407. package/docs/token-efficiency.md +80 -0
  408. package/docs/usage.md +1046 -0
  409. package/package.json +8 -5
  410. package/dist/cli-launch.js +0 -112
  411. package/dist/cli-parse.d.ts +0 -140
  412. package/dist/daemon-resilience.d.ts +0 -22
  413. package/dist/daemon-resilience.js +0 -85
  414. package/dist/mcp-proxy.d.ts +0 -35
  415. package/dist/mcp-proxy.js +0 -190
  416. package/dist/tools/profiles.d.ts +0 -37
  417. package/dist/tools/profiles.js +0 -139
  418. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  419. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  420. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  421. /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
  422. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  423. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  424. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -0,0 +1,87 @@
1
+ /**
2
+ * A durable outbox for feedback, written BEFORE the network is touched.
3
+ *
4
+ * Feedback is the only qualitative channel this product has, and it carries an agent's whole
5
+ * root-cause analysis — often an hour of driving distilled into one payload. It was sent with the
6
+ * same 2-second fire-and-forget budget as a usage counter, with no retry and no persistence, so a
7
+ * 1.3-second network hiccup destroyed the report outright. Measured to the collector from one
8
+ * machine with a WARM DNS cache: dns 0.003s, connect 0.233s, tls 0.467s, total 0.694s — roughly a
9
+ * third of the entire budget spent before a byte of payload moves, and that is the good case. A
10
+ * fresh short-lived CLI process pays cold DNS and a cold route on top.
11
+ *
12
+ * So the order is inverted: write it down first, then try to send. A failed send is then a queued
13
+ * report rather than a lost one, and `sent: false` becomes a statement about the network instead of
14
+ * an epitaph.
15
+ *
16
+ * JSONL, appended, one payload per line. Append-only is the point — a crash mid-write costs at most
17
+ * the line being written, never the ones already there.
18
+ */
19
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
20
+ import { homedir } from 'node:os';
21
+ import { join } from 'node:path';
22
+ import { randomUUID } from 'node:crypto';
23
+ import { ReticleDir } from '@reticlehq/core';
24
+ export function outboxPath(home = homedir()) {
25
+ return join(home, ReticleDir.ROOT, 'feedback-outbox.jsonl');
26
+ }
27
+ /**
28
+ * Persist a report and return its id. Never throws: failing to queue must not also fail the send
29
+ * that was about to happen anyway.
30
+ */
31
+ export function queueFeedback(payload, now = () => new Date(), home = homedir()) {
32
+ const id = randomUUID();
33
+ try {
34
+ mkdirSync(join(home, ReticleDir.ROOT), { recursive: true });
35
+ const entry = { id, t: now().toISOString(), payload };
36
+ appendFileSync(outboxPath(home), `${JSON.stringify(entry)}\n`, 'utf8');
37
+ return id;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ /** Read every queued report. A malformed line is skipped, never fatal — the rest still matter. */
44
+ export function readOutbox(home = homedir()) {
45
+ try {
46
+ const path = outboxPath(home);
47
+ if (!existsSync(path))
48
+ return [];
49
+ return readFileSync(path, 'utf8')
50
+ .split('\n')
51
+ .filter((line) => 0 < line.trim().length)
52
+ .flatMap((line) => {
53
+ try {
54
+ return [JSON.parse(line)];
55
+ }
56
+ catch {
57
+ return [];
58
+ }
59
+ });
60
+ }
61
+ catch {
62
+ return [];
63
+ }
64
+ }
65
+ /**
66
+ * Drop a report that was delivered. Rewrites the file without it.
67
+ *
68
+ * A rewrite rather than a tombstone because the file's whole purpose is "what still needs sending" —
69
+ * a reader should be able to `cat` it and see exactly the backlog, with no filtering rule to learn.
70
+ * Volume is a handful of lines a week, so the cost is irrelevant.
71
+ */
72
+ export function markDelivered(id, home = homedir()) {
73
+ if (null === id)
74
+ return;
75
+ try {
76
+ const remaining = readOutbox(home).filter((entry) => entry.id !== id);
77
+ const path = outboxPath(home);
78
+ if (0 === remaining.length) {
79
+ writeFileSync(path, '', 'utf8');
80
+ return;
81
+ }
82
+ writeFileSync(path, `${remaining.map((entry) => JSON.stringify(entry)).join('\n')}\n`, 'utf8');
83
+ }
84
+ catch {
85
+ // A report that stays queued after a successful send is a duplicate at worst. Losing one is not.
86
+ }
87
+ }
@@ -39,8 +39,21 @@ export declare function feedbackDisabled(env?: NodeJS.ProcessEnv): boolean;
39
39
  /** What the author supplies; the environment context is detected, never asked for. */
40
40
  export type FeedbackInput = Pick<Feedback, 'source' | 'kind' | 'text' | 'trace' | 'rating' | 'need' | 'impact' | 'currentApproach' | 'model'>;
41
41
  export interface FeedbackReceipt {
42
- /** False when a kill switch is on — the report was DROPPED, and the caller is told so plainly. */
42
+ /**
43
+ * DELIVERY confirmed. Only ever true when the send was awaited and the endpoint accepted it —
44
+ * never as an optimistic stand-in for "we handed it to the emitter". That distinction is the whole
45
+ * value of this field: it was once unconditional, so a DNS miss and a 4xx both reported "filed".
46
+ *
47
+ * A backgrounded send (the agent tool) therefore returns `sent: false` with `accepted: true` —
48
+ * see below. It is not a failure, and the note says so.
49
+ */
43
50
  sent: boolean;
51
+ /**
52
+ * Validated, redacted and handed to the emitter. TRUE says the report is well-formed and on its
53
+ * way; it does NOT say it arrived. If a backgrounded send then fails, the reporter is told on its
54
+ * next tool result — see feedback-delivery.ts.
55
+ */
56
+ accepted: boolean;
44
57
  reason?: string;
45
58
  /** Which redaction rules fired. Empty when nothing needed removing. */
46
59
  redacted: string[];
@@ -56,6 +69,14 @@ export declare function submitFeedback(input: FeedbackInput, opts?: {
56
69
  cwd?: string;
57
70
  session?: SessionFacts;
58
71
  env?: NodeJS.ProcessEnv;
72
+ /**
73
+ * Return as soon as the report is validated and queued, instead of waiting out the POST.
74
+ *
75
+ * Used by the AGENT tool: ~340ms of network on a call made mid-task is the product blocking the
76
+ * user's work to talk about itself. NOT used by `reticle feedback`, where a human typed the
77
+ * command and is waiting for an answer — there, confirmed delivery is the answer.
78
+ */
79
+ background?: boolean;
59
80
  }): Promise<FeedbackReceipt>;
60
81
  /**
61
82
  * The receipt's context PLUS the fields the emitter stamps on every event regardless of kind — the
@@ -24,8 +24,11 @@
24
24
  import { FeedbackSchema, FEEDBACK_TEXT_MAX, FEEDBACK_TRACE_MAX, FEEDBACK_FIELD_MAX, TelemetryEventKind, } from '@reticlehq/core';
25
25
  import { platform } from 'node:os';
26
26
  import { getTelemetry } from './telemetry.js';
27
- import { SERVER_VERSION } from '../server-version.js';
27
+ import { noteFeedbackUndelivered } from './feedback-delivery.js';
28
+ import { isReticleSourceCheckout } from './dev-repo.js';
29
+ import { SERVER_VERSION } from '../version/server-version.js';
28
30
  import { feedbackContext } from './feedback-context.js';
31
+ import { markDelivered, outboxPath, queueFeedback } from './feedback-outbox.js';
29
32
  /** Kills the feedback channel ONLY — adoption counters keep flowing. */
30
33
  export const FEEDBACK_ENV = 'RETICLE_FEEDBACK';
31
34
  /** What replaces a redacted match. Visible on purpose: a reader must see that something was removed. */
@@ -67,7 +70,7 @@ export function redactFeedbackText(input, max) {
67
70
  removed.add(label);
68
71
  // A rule with a leading capture keeps it (the scheme, the `api_key=` key) so the reader still
69
72
  // sees WHAT was removed, not just that something was.
70
- const prefix = typeof groups[0] === 'string' ? groups[0] : '';
73
+ const prefix = 'string' === typeof groups[0] ? groups[0] : '';
71
74
  return `${prefix}${REDACTED}`;
72
75
  });
73
76
  }
@@ -76,7 +79,7 @@ export function redactFeedbackText(input, max) {
76
79
  /** True when the feedback channel is switched off on its own (the emitter's switches apply as well). */
77
80
  export function feedbackDisabled(env = process.env) {
78
81
  const value = (env[FEEDBACK_ENV] ?? '').toLowerCase();
79
- return value === '0' || value === 'false' || value === 'off' || value === 'no';
82
+ return '0' === value || 'false' === value || 'off' === value || 'no' === value;
80
83
  }
81
84
  /**
82
85
  * The fields an author writes, and therefore the fields that must be redacted. ONE list, used both to
@@ -118,7 +121,7 @@ export async function submitFeedback(input, opts = {}) {
118
121
  // addition. Deriving the set means a sixth field is covered the moment it exists.
119
122
  const redactions = new Map();
120
123
  for (const [key, value] of Object.entries(input)) {
121
- if (typeof value !== 'string' || value === '')
124
+ if (typeof value !== 'string' || '' === value)
122
125
  continue;
123
126
  if (!AUTHOR_WRITTEN_FIELDS.has(key))
124
127
  continue;
@@ -127,13 +130,25 @@ export async function submitFeedback(input, opts = {}) {
127
130
  const body = redactions.get('text') ?? { text: '', removed: [] };
128
131
  const redacted = [...new Set([...redactions.values()].flatMap((r) => r.removed))];
129
132
  if (feedbackDisabled(env)) {
130
- return { sent: false, reason: `feedback is disabled by ${FEEDBACK_ENV}`, redacted, context };
133
+ return {
134
+ sent: false,
135
+ accepted: false,
136
+ reason: `feedback is disabled by ${FEEDBACK_ENV}`,
137
+ redacted,
138
+ context,
139
+ };
131
140
  }
132
141
  const telemetry = getTelemetry();
133
142
  if (!telemetry.enabled) {
134
143
  return {
135
144
  sent: false,
136
- reason: 'telemetry is disabled on this machine, so feedback has nowhere to go',
145
+ accepted: false,
146
+ // Named precisely, because the commonest cause is not what the old wording suggested: a
147
+ // Reticle SOURCE CHECKOUT disables telemetry by cwd, and that is exactly where release runs and
148
+ // contributor sessions happen — so the reports most worth having were the ones silently lost.
149
+ reason: isReticleSourceCheckout(opts.cwd ?? process.cwd())
150
+ ? 'this is a Reticle source checkout, where telemetry is disabled by design — so feedback has nowhere to go. Open an issue at https://github.com/reticlehq/reticle/issues instead, or run from the app you are verifying.'
151
+ : `telemetry is disabled on this machine, so feedback has nowhere to go. Re-enable with \`reticle telemetry enable\`, or open an issue at https://github.com/reticlehq/reticle/issues.`,
137
152
  redacted,
138
153
  context,
139
154
  };
@@ -151,13 +166,57 @@ export async function submitFeedback(input, opts = {}) {
151
166
  if (!parsed.success) {
152
167
  return {
153
168
  sent: false,
169
+ accepted: false,
154
170
  reason: parsed.error.issues[0]?.message ?? 'invalid feedback',
155
171
  redacted,
156
172
  context,
157
173
  };
158
174
  }
159
- await telemetry.emit(TelemetryEventKind.FEEDBACK_SUBMITTED, { feedback: parsed.data });
160
- return { sent: true, redacted, context };
175
+ // BACKGROUND: return now, deliver after. The agent calls this mid-task and a ~340ms POST is the
176
+ // product blocking the user's work to talk about itself. The honesty that the awaited version was
177
+ // written for is kept elsewhere: `sent` stays false (nothing is confirmed yet), `accepted` says
178
+ // the report is well-formed and queued, and a send that then fails reaches the reporter on its
179
+ // next tool result instead of vanishing.
180
+ // Written down BEFORE the network is touched, on both paths. A failed send is then a queued report
181
+ // rather than a lost one — see feedback-outbox. Reported from the field: a 1.3s hiccup destroyed a
182
+ // root-cause analysis that took an hour of driving to produce, and it survived only because the
183
+ // reporter happened to have written the markdown by hand first.
184
+ const queued = queueFeedback(parsed.data);
185
+ if (true === opts.background) {
186
+ void telemetry
187
+ .emit(TelemetryEventKind.FEEDBACK_SUBMITTED, { feedback: parsed.data })
188
+ .then((ok) => {
189
+ if (ok)
190
+ markDelivered(queued);
191
+ else
192
+ noteFeedbackUndelivered('the telemetry endpoint did not accept it');
193
+ })
194
+ .catch((error) => {
195
+ noteFeedbackUndelivered(error instanceof Error ? error.message : String(error));
196
+ });
197
+ return { sent: false, accepted: true, redacted, context };
198
+ }
199
+ // `sent` reflects DELIVERY, not handing the payload to the emitter. It was unconditional, so a DNS
200
+ // miss or a 4xx both reported "filed" — and this is the only qualitative channel the product has,
201
+ // so a silent failure here loses the report AND tells the reporter it worked.
202
+ const delivered = await telemetry.emit(TelemetryEventKind.FEEDBACK_SUBMITTED, {
203
+ feedback: parsed.data,
204
+ });
205
+ if (delivered) {
206
+ markDelivered(queued);
207
+ return { sent: true, accepted: true, redacted, context };
208
+ }
209
+ // Undelivered, but no longer lost. `accepted` is true when it reached the outbox: the report is
210
+ // well-formed and on disk, which is a materially different situation from "it is gone".
211
+ return {
212
+ sent: false,
213
+ accepted: queued !== null,
214
+ reason: queued !== null
215
+ ? `the report could not be delivered (the network call failed or was rejected), but it is SAVED at ${outboxPath()} and nothing was lost. It will be retried; you can also open an issue at https://github.com/reticlehq/reticle/issues with the same detail.`
216
+ : 'the report could not be delivered and could not be saved locally either — it was NOT filed. Retry, or open an issue at https://github.com/reticlehq/reticle/issues with the same detail.',
217
+ redacted,
218
+ context,
219
+ };
161
220
  }
162
221
  /**
163
222
  * The receipt's context PLUS the fields the emitter stamps on every event regardless of kind — the
@@ -96,7 +96,7 @@ export function gitFacts(cwd, read = defaultRead, exists = defaultExists) {
96
96
  if (url === undefined)
97
97
  return { state: GitState.LOCAL_ONLY };
98
98
  const origin = normalizeGitOrigin(url);
99
- if (origin === '')
99
+ if ('' === origin)
100
100
  return { state: GitState.LOCAL_ONLY };
101
101
  return { state: GitState.REMOTE, origin, forge: forgeOf(origin) };
102
102
  }
@@ -62,6 +62,8 @@ export declare class SessionMetrics {
62
62
  breadcrumb: string[];
63
63
  inFlight: string | undefined;
64
64
  };
65
+ /** One action driven at the page. Settled by the next verdict; see #unsettledActions. */
66
+ recordAction(): void;
65
67
  recordVerification(): void;
66
68
  /**
67
69
  * One defect found in the app under test — the outcome number, kept broken down by kind.
@@ -21,6 +21,17 @@ import { describeToolParams } from './argument-shape.js';
21
21
  import { machineSnapshot } from './machine-snapshot.js';
22
22
  /** Cap the distinct error shapes held in memory — a pathological loop must not grow unbounded. */
23
23
  const MAX_ERROR_KINDS = 40;
24
+ /** Distinct tool names whose repeat-runs are tracked. Its own cap: the tool surface, not error shapes. */
25
+ const MAX_REPEAT_TOOLS = 64;
26
+ /**
27
+ * Tool errors that all mean the same thing to a user: the agent asked, and there was no app it could
28
+ * reach. Three different messages, one experience — "nothing is connected" — and it is the error
29
+ * that ends most sessions before a single verification happens.
30
+ *
31
+ * `multiple sessions connected` belongs here too: the agent could not reach AN app because it could
32
+ * not tell which one, and the outcome is identical.
33
+ */
34
+ const NO_SESSION_ERROR = /no browser session connected|no connected session with id|multiple sessions connected/i;
24
35
  /** Cap distinct MCP clients recorded; more than a handful on one daemon is already the story. */
25
36
  const MAX_CLIENTS = 8;
26
37
  /** Bounds on the parameter map. Our own schemas are already finite; these are a belt-and-braces cap. */
@@ -71,6 +82,25 @@ export class SessionMetrics {
71
82
  * capped: the kind vocabulary is a bounded enum plus oracle names, not user data.
72
83
  */
73
84
  #seenBugKinds = new Set();
85
+ /**
86
+ * Tool errors meaning "the agent could not reach an app at all" — the single biggest drop-off in
87
+ * the funnel, and until now reachable only by unpacking `errors[]` in HogQL. 74% of daemons never
88
+ * call a tool, and of the sessions that made exactly one call, most bounced on this.
89
+ */
90
+ #noSessionErrors = 0;
91
+ /** Longest back-to-back run per tool — a retry loop, which `toolCounts` cannot distinguish. */
92
+ #repeatRuns = new Map();
93
+ #lastTool;
94
+ #currentRun = 0;
95
+ /**
96
+ * Actions driven since the last verdict — the run that is left hanging if the loop stops here.
97
+ *
98
+ * NOT `actions - verifications`. That difference ignores ORDER, so a verdict that drove nothing
99
+ * (a `flow_verify` over saved flows) silently paid for a genuinely abandoned action elsewhere, and
100
+ * a session could verify first and act after and look settled. What is abandoned is the trailing
101
+ * run, which is exactly what the field claims to mean.
102
+ */
103
+ #unsettledActions = 0;
74
104
  #clients = new Set();
75
105
  #startedAt;
76
106
  #now;
@@ -120,6 +150,16 @@ export class SessionMetrics {
120
150
  this.#unknownToolCalls += 1;
121
151
  }
122
152
  recordToolCall(tool, args) {
153
+ // A run of the same tool back to back. Five calls to reticle_act is engagement; five in a row
154
+ // after four failures is an agent stuck, and toolCounts reports both as "5".
155
+ this.#currentRun = tool === this.#lastTool ? this.#currentRun + 1 : 1;
156
+ this.#lastTool = tool;
157
+ if (this.#currentRun > 1) {
158
+ const best = this.#repeatRuns.get(tool) ?? 0;
159
+ if (this.#currentRun > best &&
160
+ (this.#repeatRuns.has(tool) || this.#repeatRuns.size < MAX_REPEAT_TOOLS))
161
+ this.#repeatRuns.set(tool, this.#currentRun);
162
+ }
123
163
  this.#toolCalls += 1;
124
164
  bump(this.#toolCounts, tool);
125
165
  this.#inFlight = tool;
@@ -150,6 +190,8 @@ export class SessionMetrics {
150
190
  */
151
191
  recordToolError(message, tool) {
152
192
  this.#toolErrors += 1;
193
+ if (NO_SESSION_ERROR.test(message))
194
+ this.#noSessionErrors += 1;
153
195
  const fingerprint = fingerprintError(message);
154
196
  const existing = this.#errorKinds.get(fingerprint);
155
197
  if (existing !== undefined) {
@@ -194,8 +236,14 @@ export class SessionMetrics {
194
236
  get trail() {
195
237
  return { breadcrumb: [...this.#breadcrumb], inFlight: this.#inFlight };
196
238
  }
239
+ /** One action driven at the page. Settled by the next verdict; see #unsettledActions. */
240
+ recordAction() {
241
+ this.#unsettledActions += 1;
242
+ }
197
243
  recordVerification() {
198
244
  this.#verifications += 1;
245
+ // A verdict settles whatever was outstanding, however many actions it took to get there.
246
+ this.#unsettledActions = 0;
199
247
  }
200
248
  /**
201
249
  * One defect found in the app under test — the outcome number, kept broken down by kind.
@@ -258,6 +306,12 @@ export class SessionMetrics {
258
306
  verifications: this.#verifications,
259
307
  bugsFound: this.#bugsFound,
260
308
  ...(this.#bugKinds.size > 0 ? { bugKinds: Object.fromEntries(this.#bugKinds) } : {}),
309
+ ...(this.#noSessionErrors > 0 ? { noSessionErrors: this.#noSessionErrors } : {}),
310
+ ...(this.#repeatRuns.size > 0
311
+ ? { consecutiveRepeats: Object.fromEntries(this.#repeatRuns) }
312
+ : {}),
313
+ // Absent rather than zero, so the PRESENCE of the field is the signal on a dashboard.
314
+ ...(this.#unsettledActions > 0 ? { abandonedActions: this.#unsettledActions } : {}),
261
315
  ...(this.#toolParams.size > 0
262
316
  ? {
263
317
  toolParams: Object.fromEntries([...this.#toolParams].map(([tool, params]) => [tool, Object.fromEntries(params)])),
@@ -277,17 +331,22 @@ export class SessionMetrics {
277
331
  }
278
332
  /** True when nothing at all happened — a flush of an idle daemon is not worth an event. */
279
333
  get empty() {
280
- return (this.#toolCalls === 0 &&
281
- this.#verifications === 0 &&
282
- this.#toolErrors === 0 &&
283
- this.#bugsFound === 0 &&
284
- this.#sdkFailures === 0);
334
+ return (0 === this.#toolCalls &&
335
+ 0 === this.#verifications &&
336
+ 0 === this.#toolErrors &&
337
+ 0 === this.#bugsFound &&
338
+ 0 === this.#sdkFailures);
285
339
  }
286
340
  /** Zero the counters after a non-final flush so the next flush reports the NEXT window, not a total. */
287
341
  reset() {
288
342
  this.#toolCalls = 0;
289
343
  this.#toolErrors = 0;
290
344
  this.#verifications = 0;
345
+ this.#noSessionErrors = 0;
346
+ this.#repeatRuns.clear();
347
+ this.#lastTool = undefined;
348
+ this.#currentRun = 0;
349
+ this.#unsettledActions = 0;
291
350
  this.#toolCounts.clear();
292
351
  this.#toolParams.clear();
293
352
  this.#errorKinds.clear();
@@ -302,7 +361,10 @@ export class SessionMetrics {
302
361
  this.#unknownToolCalls = 0;
303
362
  this.#bugsFound = 0;
304
363
  this.#bugKinds.clear();
305
- this.#seenBugKinds.clear();
364
+ // #seenBugKinds is deliberately NOT cleared. It is not a window counter — it is the
365
+ // session-lifetime memory behind `repeat` on bug_found, and zeroing it made the same defect,
366
+ // found again after a flush, report as a newly distinct one. Sessions run to 11.5 hours in the
367
+ // data, so that was up to 23 chances to count one defect many times.
306
368
  }
307
369
  }
308
370
  function bump(map, key) {
@@ -1,4 +1,20 @@
1
- import { TelemetryEventKind, type Crash, type Feedback, type Identity, type BugFound, type InitOutcome, type McpConnection, type ProjectProfile, type SessionSummary, type TelemetryActor, type Verification, type VersionChange } from '@reticlehq/core';
1
+ import { TelemetryEventKind, type Crash, type Feedback, type Identity, type BugFound, type InitOutcome, type McpConnection, type McpOutage, type ProjectProfile, type SessionSummary, type TelemetryActor, type Verification, type VersionChange } from '@reticlehq/core';
2
+ /**
3
+ * Feedback gets its own, much larger budget — and a retry.
4
+ *
5
+ * 2s + drop is right for a usage counter: the metric is worthless if it costs the user latency, and
6
+ * losing one changes nothing. Feedback is the opposite on both counts. It is the only qualitative
7
+ * channel the product has, it carries an agent's entire root-cause analysis, and losing one loses
8
+ * work that cannot be reconstructed.
9
+ *
10
+ * Measured to the collector with a WARM DNS cache: dns 0.003s, connect 0.233s, tls 0.467s, total
11
+ * 0.694s — a third of the old budget gone before any payload moves, on the good path. A fresh
12
+ * short-lived CLI process pays cold DNS and a cold route on top, which is exactly the case that
13
+ * failed in the field and then succeeded on retry from a warmer process.
14
+ */
15
+ export declare const FEEDBACK_TIMEOUT_MS = 15000;
16
+ export declare const FEEDBACK_RETRIES = 1;
17
+ export declare const FEEDBACK_RETRY_BACKOFF_MS = 750;
2
18
  /** The current telemetry state and which control set it — what `reticle telemetry status` prints. */
3
19
  export declare const describeTelemetry: (env?: NodeJS.ProcessEnv, dir?: string, cwd?: string) => {
4
20
  enabled: boolean;
@@ -38,6 +54,8 @@ export interface TelemetryExtra {
38
54
  init?: InitOutcome;
39
55
  /** `bug_found`: one defect Reticle found in the app under test. */
40
56
  bug?: BugFound;
57
+ /** `mcp_connection_lost`: the agent lost its tools — which stage, and why. */
58
+ outage?: McpOutage;
41
59
  }
42
60
  export interface Telemetry {
43
61
  /**
@@ -45,7 +63,14 @@ export interface Telemetry {
45
63
  * CLI process can exit immediately instead of waiting out the POST (use it from command entry
46
64
  * points; daemon-side events send in-process).
47
65
  */
48
- emit(kind: TelemetryEventKind, extra?: TelemetryExtra): Promise<void>;
66
+ /**
67
+ * Send one event. Resolves to whether it was DELIVERED.
68
+ *
69
+ * Almost every caller ignores the result and should — a lost metric must never surface to a user.
70
+ * `reticle_feedback` is the exception: it hands a receipt to an agent, and reporting "filed" for a
71
+ * send that failed loses the report and lies about it in the same breath.
72
+ */
73
+ emit(kind: TelemetryEventKind, extra?: TelemetryExtra): Promise<boolean>;
49
74
  readonly enabled: boolean;
50
75
  /** True the very first run on this machine — the CLI emits INSTALL alongside the first INVOKE. */
51
76
  readonly firstRun: boolean;