@reticlehq/server 2.2.0 → 2.3.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 (768) hide show
  1. package/README.md +1 -1
  2. package/dist/bridge-security.d.ts +0 -1
  3. package/dist/bridge-security.js +0 -1
  4. package/dist/bridge.d.ts +0 -1
  5. package/dist/bridge.js +60 -10
  6. package/dist/bridge.test-harness.d.ts +0 -1
  7. package/dist/bridge.test-harness.js +0 -1
  8. package/dist/capsule/capsule-store.d.ts +2 -3
  9. package/dist/capsule/capsule-store.js +0 -1
  10. package/dist/capsule/capsule.d.ts +0 -1
  11. package/dist/capsule/capsule.js +0 -1
  12. package/dist/capsule/causal-summary.d.ts +21 -1
  13. package/dist/capsule/causal-summary.js +20 -2
  14. package/dist/capsule/divergence.d.ts +0 -1
  15. package/dist/capsule/divergence.js +0 -1
  16. package/dist/capsule/minimize.d.ts +0 -1
  17. package/dist/capsule/minimize.js +0 -1
  18. package/dist/capsule/predicate-to-links.d.ts +0 -1
  19. package/dist/capsule/predicate-to-links.js +0 -1
  20. package/dist/cli-doctor.d.ts +6 -0
  21. package/dist/cli-doctor.js +60 -0
  22. package/dist/cli-flow-commands.d.ts +0 -1
  23. package/dist/cli-flow-commands.js +0 -1
  24. package/dist/cli-launch.d.ts +0 -1
  25. package/dist/cli-launch.js +7 -3
  26. package/dist/cli-parse.d.ts +52 -2
  27. package/dist/cli-parse.js +147 -3
  28. package/dist/cli-port.d.ts +0 -1
  29. package/dist/cli-port.js +0 -1
  30. package/dist/cli-verify.d.ts +2 -1
  31. package/dist/cli-verify.js +24 -3
  32. package/dist/cli.d.ts +2 -4
  33. package/dist/cli.js +109 -10
  34. package/dist/cloud/cloud-config.d.ts +36 -0
  35. package/dist/cloud/cloud-config.js +86 -0
  36. package/dist/cloud/cloud-sync.d.ts +96 -4
  37. package/dist/cloud/cloud-sync.js +131 -3
  38. package/dist/cloud-cli.d.ts +3 -0
  39. package/dist/cloud-cli.js +514 -0
  40. package/dist/crawl/crawl-tools.d.ts +0 -1
  41. package/dist/crawl/crawl-tools.js +1 -2
  42. package/dist/crawl/crawl.d.ts +17 -3
  43. package/dist/crawl/crawl.js +43 -4
  44. package/dist/daemon-resilience.d.ts +6 -1
  45. package/dist/daemon-resilience.js +63 -1
  46. package/dist/daemon.d.ts +23 -3
  47. package/dist/daemon.js +78 -21
  48. package/dist/domain/domain-model.d.ts +0 -1
  49. package/dist/domain/domain-model.js +1 -2
  50. package/dist/domain/domain-tools.d.ts +0 -7
  51. package/dist/domain/domain-tools.js +21 -4
  52. package/dist/domain/flow-risk.d.ts +0 -1
  53. package/dist/domain/flow-risk.js +0 -1
  54. package/dist/ee/audit-log.d.ts +0 -1
  55. package/dist/ee/audit-log.js +0 -1
  56. package/dist/events/body-failures.d.ts +4 -0
  57. package/dist/events/body-failures.js +113 -0
  58. package/dist/events/contradictions.d.ts +53 -0
  59. package/dist/events/contradictions.js +282 -0
  60. package/dist/events/echo-mismatch.d.ts +4 -0
  61. package/dist/events/echo-mismatch.js +138 -0
  62. package/dist/events/event-filters.d.ts +17 -3
  63. package/dist/events/event-filters.js +13 -3
  64. package/dist/events/json-salvage.d.ts +32 -0
  65. package/dist/events/json-salvage.js +96 -0
  66. package/dist/events/predicate-eval.d.ts +2 -1
  67. package/dist/events/predicate-eval.js +56 -9
  68. package/dist/events/predicate.d.ts +0 -1
  69. package/dist/events/predicate.js +56 -2
  70. package/dist/events/reaction.d.ts +0 -1
  71. package/dist/events/reaction.js +0 -1
  72. package/dist/events/reconcile.d.ts +39 -0
  73. package/dist/events/reconcile.js +211 -0
  74. package/dist/events/ring-buffer.d.ts +0 -1
  75. package/dist/events/ring-buffer.js +0 -1
  76. package/dist/events/stale-response.d.ts +4 -0
  77. package/dist/events/stale-response.js +139 -0
  78. package/dist/events/unit-mismatch.d.ts +16 -0
  79. package/dist/events/unit-mismatch.js +167 -0
  80. package/dist/flows/affected-tools.d.ts +18 -0
  81. package/dist/flows/affected-tools.js +52 -0
  82. package/dist/flows/affected.d.ts +0 -1
  83. package/dist/flows/affected.js +0 -1
  84. package/dist/flows/annotate-tools.d.ts +0 -1
  85. package/dist/flows/annotate-tools.js +21 -3
  86. package/dist/flows/annotate.d.ts +0 -1
  87. package/dist/flows/annotate.js +0 -1
  88. package/dist/flows/annotation-store.d.ts +0 -1
  89. package/dist/flows/annotation-store.js +0 -1
  90. package/dist/flows/assertion-integrity.d.ts +0 -1
  91. package/dist/flows/assertion-integrity.js +0 -1
  92. package/dist/flows/assertion-tiers-store.d.ts +0 -1
  93. package/dist/flows/assertion-tiers-store.js +0 -1
  94. package/dist/flows/buddy-status.d.ts +0 -1
  95. package/dist/flows/buddy-status.js +0 -1
  96. package/dist/flows/coverage.d.ts +0 -1
  97. package/dist/flows/coverage.js +0 -1
  98. package/dist/flows/decision.d.ts +0 -1
  99. package/dist/flows/decision.js +0 -1
  100. package/dist/flows/flake-store.d.ts +0 -1
  101. package/dist/flows/flake-store.js +0 -1
  102. package/dist/flows/flake.d.ts +0 -1
  103. package/dist/flows/flake.js +0 -1
  104. package/dist/flows/flow-classify.d.ts +0 -1
  105. package/dist/flows/flow-classify.js +0 -1
  106. package/dist/flows/flow-replay-run.d.ts +0 -1
  107. package/dist/flows/flow-replay-run.js +24 -8
  108. package/dist/flows/flow-replay.d.ts +20 -4
  109. package/dist/flows/flow-replay.js +9 -43
  110. package/dist/flows/flow-report.d.ts +0 -1
  111. package/dist/flows/flow-report.js +0 -1
  112. package/dist/flows/flow-scope.d.ts +0 -1
  113. package/dist/flows/flow-scope.js +0 -1
  114. package/dist/flows/flow-sources.d.ts +0 -1
  115. package/dist/flows/flow-sources.js +0 -1
  116. package/dist/flows/flow-step-runners.d.ts +23 -0
  117. package/dist/flows/flow-step-runners.js +102 -0
  118. package/dist/flows/flow-success.d.ts +0 -1
  119. package/dist/flows/flow-success.js +0 -1
  120. package/dist/flows/flow-tools.d.ts +0 -1
  121. package/dist/flows/flow-tools.js +54 -16
  122. package/dist/flows/flows.d.ts +6 -2
  123. package/dist/flows/flows.js +15 -2
  124. package/dist/flows/gate.d.ts +0 -1
  125. package/dist/flows/gate.js +0 -1
  126. package/dist/flows/git-changed.d.ts +0 -1
  127. package/dist/flows/git-changed.js +0 -1
  128. package/dist/flows/heal-run.d.ts +0 -1
  129. package/dist/flows/heal-run.js +0 -1
  130. package/dist/flows/heal.d.ts +0 -1
  131. package/dist/flows/heal.js +0 -1
  132. package/dist/flows/parallel-suite.d.ts +0 -1
  133. package/dist/flows/parallel-suite.js +0 -1
  134. package/dist/flows/recordings.d.ts +0 -1
  135. package/dist/flows/recordings.js +0 -1
  136. package/dist/flows/replay.d.ts +0 -1
  137. package/dist/flows/replay.js +71 -4
  138. package/dist/flows/server-verify.d.ts +15 -0
  139. package/dist/flows/server-verify.js +42 -0
  140. package/dist/flows/verify-change-tools.d.ts +2 -0
  141. package/dist/flows/verify-change-tools.js +187 -0
  142. package/dist/flows/watch-batcher.d.ts +0 -1
  143. package/dist/flows/watch-batcher.js +0 -1
  144. package/dist/honesty/accepted-write.d.ts +14 -0
  145. package/dist/honesty/accepted-write.js +17 -0
  146. package/dist/honesty/blind-spots.d.ts +18 -1
  147. package/dist/honesty/blind-spots.js +47 -5
  148. package/dist/honesty/honesty.d.ts +0 -1
  149. package/dist/honesty/honesty.js +0 -1
  150. package/dist/honesty/uncaptured-bodies.d.ts +19 -0
  151. package/dist/honesty/uncaptured-bodies.js +30 -0
  152. package/dist/honesty/unread-outcome.d.ts +2 -0
  153. package/dist/honesty/unread-outcome.js +50 -0
  154. package/dist/honesty/verified.d.ts +40 -0
  155. package/dist/honesty/verified.js +86 -0
  156. package/dist/http-server.d.ts +0 -1
  157. package/dist/http-server.js +5 -1
  158. package/dist/hunt/hunt-report.d.ts +50 -0
  159. package/dist/hunt/hunt-report.js +84 -0
  160. package/dist/idle-shutdown.d.ts +0 -1
  161. package/dist/idle-shutdown.js +0 -1
  162. package/dist/index.d.ts +0 -1
  163. package/dist/index.js +0 -1
  164. package/dist/init/agent-rules.d.ts +0 -1
  165. package/dist/init/agent-rules.js +4 -2
  166. package/dist/init/cursor.d.ts +0 -1
  167. package/dist/init/cursor.js +0 -1
  168. package/dist/init/desktop-doctor.d.ts +40 -0
  169. package/dist/init/desktop-doctor.js +198 -0
  170. package/dist/init/detect.d.ts +0 -1
  171. package/dist/init/detect.js +0 -1
  172. package/dist/init/mcp.d.ts +0 -1
  173. package/dist/init/mcp.js +0 -1
  174. package/dist/init/node-io.d.ts +0 -1
  175. package/dist/init/node-io.js +0 -1
  176. package/dist/init/plan.d.ts +4 -1
  177. package/dist/init/plan.js +23 -5
  178. package/dist/init/project-id.d.ts +0 -1
  179. package/dist/init/project-id.js +0 -1
  180. package/dist/init/run.d.ts +0 -1
  181. package/dist/init/run.js +31 -3
  182. package/dist/init/snippets.d.ts +5 -1
  183. package/dist/init/snippets.js +5 -1
  184. package/dist/init/vite-config.d.ts +0 -1
  185. package/dist/init/vite-config.js +0 -1
  186. package/dist/input/network-detail.d.ts +0 -1
  187. package/dist/input/network-detail.js +0 -1
  188. package/dist/input/network-mock-tools.d.ts +0 -1
  189. package/dist/input/network-mock-tools.js +3 -4
  190. package/dist/input/network-mock.d.ts +0 -1
  191. package/dist/input/network-mock.js +0 -1
  192. package/dist/input/real-input.d.ts +14 -1
  193. package/dist/input/real-input.js +45 -3
  194. package/dist/input/scroll-find.d.ts +0 -1
  195. package/dist/input/scroll-find.js +0 -1
  196. package/dist/input/scroll-tools.d.ts +0 -1
  197. package/dist/input/scroll-tools.js +0 -1
  198. package/dist/input/viewport-tools.d.ts +0 -1
  199. package/dist/input/viewport-tools.js +3 -4
  200. package/dist/journal/ambient-store.d.ts +0 -1
  201. package/dist/journal/ambient-store.js +0 -1
  202. package/dist/journal/ambient.d.ts +0 -1
  203. package/dist/journal/ambient.js +0 -1
  204. package/dist/journal/attach-journal.d.ts +0 -1
  205. package/dist/journal/attach-journal.js +0 -1
  206. package/dist/journal/deviation-report.d.ts +0 -1
  207. package/dist/journal/deviation-report.js +0 -1
  208. package/dist/journal/deviation-service.d.ts +0 -1
  209. package/dist/journal/deviation-service.js +0 -1
  210. package/dist/journal/envelope-store.d.ts +0 -1
  211. package/dist/journal/envelope-store.js +0 -1
  212. package/dist/journal/envelope.d.ts +8 -9
  213. package/dist/journal/envelope.js +0 -1
  214. package/dist/journal/journal-query.d.ts +0 -1
  215. package/dist/journal/journal-query.js +0 -1
  216. package/dist/journal/journal-recorder.d.ts +0 -1
  217. package/dist/journal/journal-recorder.js +0 -1
  218. package/dist/journal/retention.d.ts +0 -1
  219. package/dist/journal/retention.js +0 -1
  220. package/dist/journal/rollups.d.ts +0 -1
  221. package/dist/journal/rollups.js +0 -1
  222. package/dist/journal/session-end.d.ts +0 -1
  223. package/dist/journal/session-end.js +0 -1
  224. package/dist/journal/session-journal.d.ts +0 -1
  225. package/dist/journal/session-journal.js +0 -1
  226. package/dist/license/license.d.ts +0 -1
  227. package/dist/license/license.js +0 -1
  228. package/dist/log.d.ts +0 -1
  229. package/dist/log.js +0 -1
  230. package/dist/mcp-proxy.d.ts +0 -1
  231. package/dist/mcp-proxy.js +0 -1
  232. package/dist/mcp.d.ts +15 -1
  233. package/dist/mcp.js +145 -17
  234. package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
  235. package/dist/oracles/flow-instrument-gaps.js +0 -1
  236. package/dist/oracles/propose-consequences.d.ts +0 -1
  237. package/dist/oracles/propose-consequences.js +0 -1
  238. package/dist/oracles/self-instrument.d.ts +0 -1
  239. package/dist/oracles/self-instrument.js +0 -1
  240. package/dist/pairing-token.d.ts +0 -1
  241. package/dist/pairing-token.js +0 -1
  242. package/dist/phenomena/phenomena.d.ts +0 -1
  243. package/dist/phenomena/phenomena.js +0 -1
  244. package/dist/pool/browser-pool.d.ts +0 -1
  245. package/dist/pool/browser-pool.js +0 -1
  246. package/dist/pool/lease-reaper.d.ts +0 -1
  247. package/dist/pool/lease-reaper.js +0 -1
  248. package/dist/pool/playwright-launcher.d.ts +2 -1
  249. package/dist/pool/playwright-launcher.js +22 -2
  250. package/dist/project/baselines.d.ts +0 -1
  251. package/dist/project/baselines.js +5 -4
  252. package/dist/project/file-lock.d.ts +2 -1
  253. package/dist/project/file-lock.js +12 -2
  254. package/dist/project/fs-port.d.ts +0 -1
  255. package/dist/project/fs-port.js +0 -1
  256. package/dist/project/project-store.d.ts +0 -1
  257. package/dist/project/project-store.js +20 -9
  258. package/dist/project/project-tools.d.ts +0 -1
  259. package/dist/project/project-tools.js +57 -9
  260. package/dist/project/reticle-dir.d.ts +0 -1
  261. package/dist/project/reticle-dir.js +0 -1
  262. package/dist/runs/build-verification-run.d.ts +0 -1
  263. package/dist/runs/build-verification-run.js +0 -1
  264. package/dist/runs/profile-redact.d.ts +0 -1
  265. package/dist/runs/profile-redact.js +0 -1
  266. package/dist/runs/render-report.d.ts +0 -1
  267. package/dist/runs/render-report.js +0 -1
  268. package/dist/runs/repair-prompt.d.ts +0 -1
  269. package/dist/runs/repair-prompt.js +0 -1
  270. package/dist/runs/replay-mapping.d.ts +0 -1
  271. package/dist/runs/replay-mapping.js +0 -1
  272. package/dist/runs/reticle-runner.d.ts +0 -1
  273. package/dist/runs/reticle-runner.js +4 -2
  274. package/dist/runs/risk-classify.d.ts +0 -1
  275. package/dist/runs/risk-classify.js +0 -1
  276. package/dist/runs/run-diff.d.ts +0 -1
  277. package/dist/runs/run-diff.js +0 -1
  278. package/dist/runs/run-store.d.ts +0 -1
  279. package/dist/runs/run-store.js +0 -1
  280. package/dist/runs/run-tools.d.ts +0 -1
  281. package/dist/runs/run-tools.js +0 -1
  282. package/dist/runs/runner-port.d.ts +0 -1
  283. package/dist/runs/runner-port.js +0 -1
  284. package/dist/runs/verification-sync.d.ts +23 -0
  285. package/dist/runs/verification-sync.js +66 -0
  286. package/dist/runs/verify-http.d.ts +0 -1
  287. package/dist/runs/verify-http.js +0 -1
  288. package/dist/runs/verify-server.d.ts +0 -1
  289. package/dist/runs/verify-server.js +0 -1
  290. package/dist/server-version.d.ts +0 -1
  291. package/dist/server-version.js +0 -1
  292. package/dist/session/command-timeout.d.ts +35 -0
  293. package/dist/session/command-timeout.js +41 -0
  294. package/dist/session/control-envelope.d.ts +2 -3
  295. package/dist/session/control-envelope.js +2 -3
  296. package/dist/session/last-act.d.ts +31 -0
  297. package/dist/session/last-act.js +24 -0
  298. package/dist/session/live-control-tools.d.ts +0 -1
  299. package/dist/session/live-control-tools.js +3 -4
  300. package/dist/session/live-control.d.ts +0 -1
  301. package/dist/session/live-control.js +0 -1
  302. package/dist/session/observed-state.d.ts +12 -2
  303. package/dist/session/observed-state.js +29 -2
  304. package/dist/session/output-budget.d.ts +0 -1
  305. package/dist/session/output-budget.js +0 -1
  306. package/dist/session/pending-commands.d.ts +12 -0
  307. package/dist/session/pending-commands.js +36 -0
  308. package/dist/session/presenter-args.d.ts +0 -1
  309. package/dist/session/presenter-args.js +0 -1
  310. package/dist/session/review-store.d.ts +0 -1
  311. package/dist/session/review-store.js +0 -1
  312. package/dist/session/session-health.d.ts +26 -2
  313. package/dist/session/session-health.js +13 -1
  314. package/dist/session/session-info.d.ts +29 -0
  315. package/dist/session/session-info.js +1 -0
  316. package/dist/session/session-lease.d.ts +25 -0
  317. package/dist/session/session-lease.js +14 -0
  318. package/dist/session/session-manager.d.ts +7 -19
  319. package/dist/session/session-manager.js +29 -2
  320. package/dist/session/session-readiness.d.ts +0 -1
  321. package/dist/session/session-readiness.js +3 -4
  322. package/dist/session/session-reaper.d.ts +0 -1
  323. package/dist/session/session-reaper.js +0 -1
  324. package/dist/session/session-recommendation.d.ts +0 -1
  325. package/dist/session/session-recommendation.js +0 -1
  326. package/dist/session/session-tools.d.ts +0 -1
  327. package/dist/session/session-tools.js +2 -3
  328. package/dist/session/session.d.ts +27 -53
  329. package/dist/session/session.js +95 -66
  330. package/dist/session/state-select.d.ts +0 -1
  331. package/dist/session/state-select.js +0 -1
  332. package/dist/telemetry/argument-shape.d.ts +41 -0
  333. package/dist/telemetry/argument-shape.js +87 -0
  334. package/dist/telemetry/bug-found.d.ts +33 -0
  335. package/dist/telemetry/bug-found.js +95 -0
  336. package/dist/telemetry/cli-telemetry.d.ts +13 -0
  337. package/dist/telemetry/cli-telemetry.js +43 -0
  338. package/dist/telemetry/connect-failure.d.ts +16 -0
  339. package/dist/telemetry/connect-failure.js +44 -0
  340. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  341. package/dist/telemetry/daemon-telemetry.js +76 -0
  342. package/dist/telemetry/dev-repo.d.ts +10 -0
  343. package/dist/telemetry/dev-repo.js +80 -0
  344. package/dist/telemetry/error-fingerprint.d.ts +24 -0
  345. package/dist/telemetry/error-fingerprint.js +88 -0
  346. package/dist/telemetry/feedback-cli.d.ts +31 -0
  347. package/dist/telemetry/feedback-cli.js +102 -0
  348. package/dist/telemetry/feedback-context.d.ts +32 -0
  349. package/dist/telemetry/feedback-context.js +143 -0
  350. package/dist/telemetry/feedback.d.ts +66 -0
  351. package/dist/telemetry/feedback.js +175 -0
  352. package/dist/telemetry/git-facts.d.ts +21 -0
  353. package/dist/telemetry/git-facts.js +109 -0
  354. package/dist/telemetry/identify.d.ts +22 -0
  355. package/dist/telemetry/identify.js +73 -0
  356. package/dist/telemetry/init-telemetry.d.ts +26 -0
  357. package/dist/telemetry/init-telemetry.js +33 -0
  358. package/dist/telemetry/machine-snapshot.d.ts +6 -0
  359. package/dist/telemetry/machine-snapshot.js +39 -0
  360. package/dist/telemetry/mcp-connection.d.ts +5 -0
  361. package/dist/telemetry/mcp-connection.js +44 -0
  362. package/dist/telemetry/project-profile.d.ts +44 -0
  363. package/dist/telemetry/project-profile.js +205 -0
  364. package/dist/telemetry/run-telemetry.d.ts +21 -0
  365. package/dist/telemetry/run-telemetry.js +62 -0
  366. package/dist/telemetry/session-metrics.d.ts +103 -0
  367. package/dist/telemetry/session-metrics.js +329 -0
  368. package/dist/telemetry/telemetry.d.ts +68 -0
  369. package/dist/telemetry/telemetry.js +313 -0
  370. package/dist/token-auth.d.ts +0 -1
  371. package/dist/token-auth.js +0 -1
  372. package/dist/tools/act-capsule.d.ts +23 -0
  373. package/dist/tools/act-capsule.js +47 -0
  374. package/dist/tools/act-danger.d.ts +7 -0
  375. package/dist/tools/act-danger.js +44 -0
  376. package/dist/tools/act-helpers.d.ts +17 -0
  377. package/dist/tools/act-helpers.js +40 -0
  378. package/dist/tools/act-tools.d.ts +8 -1
  379. package/dist/tools/act-tools.js +96 -98
  380. package/dist/tools/act-view.d.ts +7 -1
  381. package/dist/tools/act-view.js +13 -1
  382. package/dist/tools/assert-grade.d.ts +22 -1
  383. package/dist/tools/assert-grade.js +46 -1
  384. package/dist/tools/assert-verdict.d.ts +21 -0
  385. package/dist/tools/assert-verdict.js +62 -0
  386. package/dist/tools/browser-tools.d.ts +0 -1
  387. package/dist/tools/browser-tools.js +2 -2
  388. package/dist/tools/contract-tools.d.ts +0 -1
  389. package/dist/tools/contract-tools.js +0 -1
  390. package/dist/tools/coverage-tools.d.ts +9 -0
  391. package/dist/tools/coverage-tools.js +92 -0
  392. package/dist/tools/dynamic-tools.d.ts +0 -1
  393. package/dist/tools/dynamic-tools.js +21 -2
  394. package/dist/tools/error-recovery.d.ts +18 -2
  395. package/dist/tools/error-recovery.js +42 -7
  396. package/dist/tools/feedback-tools.d.ts +24 -0
  397. package/dist/tools/feedback-tools.js +180 -0
  398. package/dist/tools/invoke-tool.d.ts +0 -1
  399. package/dist/tools/invoke-tool.js +116 -2
  400. package/dist/tools/lease-tools.d.ts +0 -1
  401. package/dist/tools/lease-tools.js +6 -5
  402. package/dist/tools/merge-tools.d.ts +0 -1
  403. package/dist/tools/merge-tools.js +0 -1
  404. package/dist/tools/observe-tools.d.ts +0 -1
  405. package/dist/tools/observe-tools.js +91 -39
  406. package/dist/tools/profiles.d.ts +1 -2
  407. package/dist/tools/profiles.js +43 -16
  408. package/dist/tools/query-paginate.d.ts +0 -1
  409. package/dist/tools/query-paginate.js +0 -1
  410. package/dist/tools/read-tools.d.ts +0 -1
  411. package/dist/tools/read-tools.js +10 -8
  412. package/dist/tools/reconcile-tools.d.ts +2 -0
  413. package/dist/tools/reconcile-tools.js +111 -0
  414. package/dist/tools/snapshot-delta.d.ts +0 -1
  415. package/dist/tools/snapshot-delta.js +0 -0
  416. package/dist/tools/tool-invoker.d.ts +0 -1
  417. package/dist/tools/tool-invoker.js +0 -1
  418. package/dist/tools/tool-kit.d.ts +16 -1
  419. package/dist/tools/tool-kit.js +8 -2
  420. package/dist/tools/tool-names.d.ts +6 -1
  421. package/dist/tools/tool-names.js +6 -1
  422. package/dist/tools/tools-helpers.d.ts +0 -1
  423. package/dist/tools/tools-helpers.js +0 -1
  424. package/dist/tools/tools.d.ts +0 -1
  425. package/dist/tools/tools.js +24 -4
  426. package/dist/update/update-checker.d.ts +0 -1
  427. package/dist/update/update-checker.js +26 -2
  428. package/dist/update/update-nudge.d.ts +20 -0
  429. package/dist/update/update-nudge.js +72 -0
  430. package/dist/update/updater.d.ts +14 -1
  431. package/dist/update/updater.js +33 -2
  432. package/dist/visual/visual-diff.d.ts +0 -1
  433. package/dist/visual/visual-diff.js +0 -1
  434. package/dist/visual/visual-store.d.ts +0 -1
  435. package/dist/visual/visual-store.js +0 -1
  436. package/dist/visual/visual-tools.d.ts +0 -1
  437. package/dist/visual/visual-tools.js +103 -16
  438. package/package.json +2 -2
  439. package/dist/bridge-security.d.ts.map +0 -1
  440. package/dist/bridge-security.js.map +0 -1
  441. package/dist/bridge.d.ts.map +0 -1
  442. package/dist/bridge.js.map +0 -1
  443. package/dist/bridge.test-harness.d.ts.map +0 -1
  444. package/dist/bridge.test-harness.js.map +0 -1
  445. package/dist/capsule/capsule-store.d.ts.map +0 -1
  446. package/dist/capsule/capsule-store.js.map +0 -1
  447. package/dist/capsule/capsule.d.ts.map +0 -1
  448. package/dist/capsule/capsule.js.map +0 -1
  449. package/dist/capsule/causal-summary.d.ts.map +0 -1
  450. package/dist/capsule/causal-summary.js.map +0 -1
  451. package/dist/capsule/divergence.d.ts.map +0 -1
  452. package/dist/capsule/divergence.js.map +0 -1
  453. package/dist/capsule/minimize.d.ts.map +0 -1
  454. package/dist/capsule/minimize.js.map +0 -1
  455. package/dist/capsule/predicate-to-links.d.ts.map +0 -1
  456. package/dist/capsule/predicate-to-links.js.map +0 -1
  457. package/dist/cli-flow-commands.d.ts.map +0 -1
  458. package/dist/cli-flow-commands.js.map +0 -1
  459. package/dist/cli-launch.d.ts.map +0 -1
  460. package/dist/cli-launch.js.map +0 -1
  461. package/dist/cli-parse.d.ts.map +0 -1
  462. package/dist/cli-parse.js.map +0 -1
  463. package/dist/cli-port.d.ts.map +0 -1
  464. package/dist/cli-port.js.map +0 -1
  465. package/dist/cli-verify.d.ts.map +0 -1
  466. package/dist/cli-verify.js.map +0 -1
  467. package/dist/cli.d.ts.map +0 -1
  468. package/dist/cli.js.map +0 -1
  469. package/dist/cloud/cloud-sync.d.ts.map +0 -1
  470. package/dist/cloud/cloud-sync.js.map +0 -1
  471. package/dist/crawl/crawl-tools.d.ts.map +0 -1
  472. package/dist/crawl/crawl-tools.js.map +0 -1
  473. package/dist/crawl/crawl.d.ts.map +0 -1
  474. package/dist/crawl/crawl.js.map +0 -1
  475. package/dist/daemon-resilience.d.ts.map +0 -1
  476. package/dist/daemon-resilience.js.map +0 -1
  477. package/dist/daemon.d.ts.map +0 -1
  478. package/dist/daemon.js.map +0 -1
  479. package/dist/domain/domain-model.d.ts.map +0 -1
  480. package/dist/domain/domain-model.js.map +0 -1
  481. package/dist/domain/domain-tools.d.ts.map +0 -1
  482. package/dist/domain/domain-tools.js.map +0 -1
  483. package/dist/domain/flow-risk.d.ts.map +0 -1
  484. package/dist/domain/flow-risk.js.map +0 -1
  485. package/dist/ee/audit-log.d.ts.map +0 -1
  486. package/dist/ee/audit-log.js.map +0 -1
  487. package/dist/events/event-filters.d.ts.map +0 -1
  488. package/dist/events/event-filters.js.map +0 -1
  489. package/dist/events/predicate-eval.d.ts.map +0 -1
  490. package/dist/events/predicate-eval.js.map +0 -1
  491. package/dist/events/predicate.d.ts.map +0 -1
  492. package/dist/events/predicate.js.map +0 -1
  493. package/dist/events/reaction.d.ts.map +0 -1
  494. package/dist/events/reaction.js.map +0 -1
  495. package/dist/events/ring-buffer.d.ts.map +0 -1
  496. package/dist/events/ring-buffer.js.map +0 -1
  497. package/dist/flows/affected.d.ts.map +0 -1
  498. package/dist/flows/affected.js.map +0 -1
  499. package/dist/flows/annotate-tools.d.ts.map +0 -1
  500. package/dist/flows/annotate-tools.js.map +0 -1
  501. package/dist/flows/annotate.d.ts.map +0 -1
  502. package/dist/flows/annotate.js.map +0 -1
  503. package/dist/flows/annotation-store.d.ts.map +0 -1
  504. package/dist/flows/annotation-store.js.map +0 -1
  505. package/dist/flows/assertion-integrity.d.ts.map +0 -1
  506. package/dist/flows/assertion-integrity.js.map +0 -1
  507. package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
  508. package/dist/flows/assertion-tiers-store.js.map +0 -1
  509. package/dist/flows/buddy-status.d.ts.map +0 -1
  510. package/dist/flows/buddy-status.js.map +0 -1
  511. package/dist/flows/coverage.d.ts.map +0 -1
  512. package/dist/flows/coverage.js.map +0 -1
  513. package/dist/flows/decision.d.ts.map +0 -1
  514. package/dist/flows/decision.js.map +0 -1
  515. package/dist/flows/flake-store.d.ts.map +0 -1
  516. package/dist/flows/flake-store.js.map +0 -1
  517. package/dist/flows/flake.d.ts.map +0 -1
  518. package/dist/flows/flake.js.map +0 -1
  519. package/dist/flows/flow-classify.d.ts.map +0 -1
  520. package/dist/flows/flow-classify.js.map +0 -1
  521. package/dist/flows/flow-replay-run.d.ts.map +0 -1
  522. package/dist/flows/flow-replay-run.js.map +0 -1
  523. package/dist/flows/flow-replay.d.ts.map +0 -1
  524. package/dist/flows/flow-replay.js.map +0 -1
  525. package/dist/flows/flow-report.d.ts.map +0 -1
  526. package/dist/flows/flow-report.js.map +0 -1
  527. package/dist/flows/flow-scope.d.ts.map +0 -1
  528. package/dist/flows/flow-scope.js.map +0 -1
  529. package/dist/flows/flow-sources.d.ts.map +0 -1
  530. package/dist/flows/flow-sources.js.map +0 -1
  531. package/dist/flows/flow-success.d.ts.map +0 -1
  532. package/dist/flows/flow-success.js.map +0 -1
  533. package/dist/flows/flow-tools.d.ts.map +0 -1
  534. package/dist/flows/flow-tools.js.map +0 -1
  535. package/dist/flows/flows.d.ts.map +0 -1
  536. package/dist/flows/flows.js.map +0 -1
  537. package/dist/flows/gate.d.ts.map +0 -1
  538. package/dist/flows/gate.js.map +0 -1
  539. package/dist/flows/git-changed.d.ts.map +0 -1
  540. package/dist/flows/git-changed.js.map +0 -1
  541. package/dist/flows/heal-run.d.ts.map +0 -1
  542. package/dist/flows/heal-run.js.map +0 -1
  543. package/dist/flows/heal.d.ts.map +0 -1
  544. package/dist/flows/heal.js.map +0 -1
  545. package/dist/flows/parallel-suite.d.ts.map +0 -1
  546. package/dist/flows/parallel-suite.js.map +0 -1
  547. package/dist/flows/recordings.d.ts.map +0 -1
  548. package/dist/flows/recordings.js.map +0 -1
  549. package/dist/flows/replay.d.ts.map +0 -1
  550. package/dist/flows/replay.js.map +0 -1
  551. package/dist/flows/watch-batcher.d.ts.map +0 -1
  552. package/dist/flows/watch-batcher.js.map +0 -1
  553. package/dist/honesty/blind-spots.d.ts.map +0 -1
  554. package/dist/honesty/blind-spots.js.map +0 -1
  555. package/dist/honesty/honesty.d.ts.map +0 -1
  556. package/dist/honesty/honesty.js.map +0 -1
  557. package/dist/http-server.d.ts.map +0 -1
  558. package/dist/http-server.js.map +0 -1
  559. package/dist/idle-shutdown.d.ts.map +0 -1
  560. package/dist/idle-shutdown.js.map +0 -1
  561. package/dist/index.d.ts.map +0 -1
  562. package/dist/index.js.map +0 -1
  563. package/dist/init/agent-rules.d.ts.map +0 -1
  564. package/dist/init/agent-rules.js.map +0 -1
  565. package/dist/init/cursor.d.ts.map +0 -1
  566. package/dist/init/cursor.js.map +0 -1
  567. package/dist/init/detect.d.ts.map +0 -1
  568. package/dist/init/detect.js.map +0 -1
  569. package/dist/init/mcp.d.ts.map +0 -1
  570. package/dist/init/mcp.js.map +0 -1
  571. package/dist/init/node-io.d.ts.map +0 -1
  572. package/dist/init/node-io.js.map +0 -1
  573. package/dist/init/plan.d.ts.map +0 -1
  574. package/dist/init/plan.js.map +0 -1
  575. package/dist/init/project-id.d.ts.map +0 -1
  576. package/dist/init/project-id.js.map +0 -1
  577. package/dist/init/run.d.ts.map +0 -1
  578. package/dist/init/run.js.map +0 -1
  579. package/dist/init/snippets.d.ts.map +0 -1
  580. package/dist/init/snippets.js.map +0 -1
  581. package/dist/init/vite-config.d.ts.map +0 -1
  582. package/dist/init/vite-config.js.map +0 -1
  583. package/dist/input/network-detail.d.ts.map +0 -1
  584. package/dist/input/network-detail.js.map +0 -1
  585. package/dist/input/network-mock-tools.d.ts.map +0 -1
  586. package/dist/input/network-mock-tools.js.map +0 -1
  587. package/dist/input/network-mock.d.ts.map +0 -1
  588. package/dist/input/network-mock.js.map +0 -1
  589. package/dist/input/real-input.d.ts.map +0 -1
  590. package/dist/input/real-input.js.map +0 -1
  591. package/dist/input/scroll-find.d.ts.map +0 -1
  592. package/dist/input/scroll-find.js.map +0 -1
  593. package/dist/input/scroll-tools.d.ts.map +0 -1
  594. package/dist/input/scroll-tools.js.map +0 -1
  595. package/dist/input/viewport-tools.d.ts.map +0 -1
  596. package/dist/input/viewport-tools.js.map +0 -1
  597. package/dist/journal/ambient-store.d.ts.map +0 -1
  598. package/dist/journal/ambient-store.js.map +0 -1
  599. package/dist/journal/ambient.d.ts.map +0 -1
  600. package/dist/journal/ambient.js.map +0 -1
  601. package/dist/journal/attach-journal.d.ts.map +0 -1
  602. package/dist/journal/attach-journal.js.map +0 -1
  603. package/dist/journal/deviation-report.d.ts.map +0 -1
  604. package/dist/journal/deviation-report.js.map +0 -1
  605. package/dist/journal/deviation-service.d.ts.map +0 -1
  606. package/dist/journal/deviation-service.js.map +0 -1
  607. package/dist/journal/envelope-store.d.ts.map +0 -1
  608. package/dist/journal/envelope-store.js.map +0 -1
  609. package/dist/journal/envelope.d.ts.map +0 -1
  610. package/dist/journal/envelope.js.map +0 -1
  611. package/dist/journal/journal-query.d.ts.map +0 -1
  612. package/dist/journal/journal-query.js.map +0 -1
  613. package/dist/journal/journal-recorder.d.ts.map +0 -1
  614. package/dist/journal/journal-recorder.js.map +0 -1
  615. package/dist/journal/retention.d.ts.map +0 -1
  616. package/dist/journal/retention.js.map +0 -1
  617. package/dist/journal/rollups.d.ts.map +0 -1
  618. package/dist/journal/rollups.js.map +0 -1
  619. package/dist/journal/session-end.d.ts.map +0 -1
  620. package/dist/journal/session-end.js.map +0 -1
  621. package/dist/journal/session-journal.d.ts.map +0 -1
  622. package/dist/journal/session-journal.js.map +0 -1
  623. package/dist/license/license.d.ts.map +0 -1
  624. package/dist/license/license.js.map +0 -1
  625. package/dist/log.d.ts.map +0 -1
  626. package/dist/log.js.map +0 -1
  627. package/dist/mcp-proxy.d.ts.map +0 -1
  628. package/dist/mcp-proxy.js.map +0 -1
  629. package/dist/mcp.d.ts.map +0 -1
  630. package/dist/mcp.js.map +0 -1
  631. package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
  632. package/dist/oracles/flow-instrument-gaps.js.map +0 -1
  633. package/dist/oracles/propose-consequences.d.ts.map +0 -1
  634. package/dist/oracles/propose-consequences.js.map +0 -1
  635. package/dist/oracles/self-instrument.d.ts.map +0 -1
  636. package/dist/oracles/self-instrument.js.map +0 -1
  637. package/dist/pairing-token.d.ts.map +0 -1
  638. package/dist/pairing-token.js.map +0 -1
  639. package/dist/phenomena/phenomena.d.ts.map +0 -1
  640. package/dist/phenomena/phenomena.js.map +0 -1
  641. package/dist/pool/browser-pool.d.ts.map +0 -1
  642. package/dist/pool/browser-pool.js.map +0 -1
  643. package/dist/pool/lease-reaper.d.ts.map +0 -1
  644. package/dist/pool/lease-reaper.js.map +0 -1
  645. package/dist/pool/playwright-launcher.d.ts.map +0 -1
  646. package/dist/pool/playwright-launcher.js.map +0 -1
  647. package/dist/project/baselines.d.ts.map +0 -1
  648. package/dist/project/baselines.js.map +0 -1
  649. package/dist/project/file-lock.d.ts.map +0 -1
  650. package/dist/project/file-lock.js.map +0 -1
  651. package/dist/project/fs-port.d.ts.map +0 -1
  652. package/dist/project/fs-port.js.map +0 -1
  653. package/dist/project/project-store.d.ts.map +0 -1
  654. package/dist/project/project-store.js.map +0 -1
  655. package/dist/project/project-tools.d.ts.map +0 -1
  656. package/dist/project/project-tools.js.map +0 -1
  657. package/dist/project/reticle-dir.d.ts.map +0 -1
  658. package/dist/project/reticle-dir.js.map +0 -1
  659. package/dist/runs/build-verification-run.d.ts.map +0 -1
  660. package/dist/runs/build-verification-run.js.map +0 -1
  661. package/dist/runs/profile-redact.d.ts.map +0 -1
  662. package/dist/runs/profile-redact.js.map +0 -1
  663. package/dist/runs/render-report.d.ts.map +0 -1
  664. package/dist/runs/render-report.js.map +0 -1
  665. package/dist/runs/repair-prompt.d.ts.map +0 -1
  666. package/dist/runs/repair-prompt.js.map +0 -1
  667. package/dist/runs/replay-mapping.d.ts.map +0 -1
  668. package/dist/runs/replay-mapping.js.map +0 -1
  669. package/dist/runs/reticle-runner.d.ts.map +0 -1
  670. package/dist/runs/reticle-runner.js.map +0 -1
  671. package/dist/runs/risk-classify.d.ts.map +0 -1
  672. package/dist/runs/risk-classify.js.map +0 -1
  673. package/dist/runs/run-diff.d.ts.map +0 -1
  674. package/dist/runs/run-diff.js.map +0 -1
  675. package/dist/runs/run-store.d.ts.map +0 -1
  676. package/dist/runs/run-store.js.map +0 -1
  677. package/dist/runs/run-tools.d.ts.map +0 -1
  678. package/dist/runs/run-tools.js.map +0 -1
  679. package/dist/runs/runner-port.d.ts.map +0 -1
  680. package/dist/runs/runner-port.js.map +0 -1
  681. package/dist/runs/verify-http.d.ts.map +0 -1
  682. package/dist/runs/verify-http.js.map +0 -1
  683. package/dist/runs/verify-server.d.ts.map +0 -1
  684. package/dist/runs/verify-server.js.map +0 -1
  685. package/dist/server-version.d.ts.map +0 -1
  686. package/dist/server-version.js.map +0 -1
  687. package/dist/session/control-envelope.d.ts.map +0 -1
  688. package/dist/session/control-envelope.js.map +0 -1
  689. package/dist/session/live-control-tools.d.ts.map +0 -1
  690. package/dist/session/live-control-tools.js.map +0 -1
  691. package/dist/session/live-control.d.ts.map +0 -1
  692. package/dist/session/live-control.js.map +0 -1
  693. package/dist/session/observed-state.d.ts.map +0 -1
  694. package/dist/session/observed-state.js.map +0 -1
  695. package/dist/session/output-budget.d.ts.map +0 -1
  696. package/dist/session/output-budget.js.map +0 -1
  697. package/dist/session/presenter-args.d.ts.map +0 -1
  698. package/dist/session/presenter-args.js.map +0 -1
  699. package/dist/session/review-store.d.ts.map +0 -1
  700. package/dist/session/review-store.js.map +0 -1
  701. package/dist/session/session-health.d.ts.map +0 -1
  702. package/dist/session/session-health.js.map +0 -1
  703. package/dist/session/session-manager.d.ts.map +0 -1
  704. package/dist/session/session-manager.js.map +0 -1
  705. package/dist/session/session-readiness.d.ts.map +0 -1
  706. package/dist/session/session-readiness.js.map +0 -1
  707. package/dist/session/session-reaper.d.ts.map +0 -1
  708. package/dist/session/session-reaper.js.map +0 -1
  709. package/dist/session/session-recommendation.d.ts.map +0 -1
  710. package/dist/session/session-recommendation.js.map +0 -1
  711. package/dist/session/session-tools.d.ts.map +0 -1
  712. package/dist/session/session-tools.js.map +0 -1
  713. package/dist/session/session.d.ts.map +0 -1
  714. package/dist/session/session.js.map +0 -1
  715. package/dist/session/state-select.d.ts.map +0 -1
  716. package/dist/session/state-select.js.map +0 -1
  717. package/dist/token-auth.d.ts.map +0 -1
  718. package/dist/token-auth.js.map +0 -1
  719. package/dist/tools/act-tools.d.ts.map +0 -1
  720. package/dist/tools/act-tools.js.map +0 -1
  721. package/dist/tools/act-view.d.ts.map +0 -1
  722. package/dist/tools/act-view.js.map +0 -1
  723. package/dist/tools/assert-grade.d.ts.map +0 -1
  724. package/dist/tools/assert-grade.js.map +0 -1
  725. package/dist/tools/browser-tools.d.ts.map +0 -1
  726. package/dist/tools/browser-tools.js.map +0 -1
  727. package/dist/tools/contract-tools.d.ts.map +0 -1
  728. package/dist/tools/contract-tools.js.map +0 -1
  729. package/dist/tools/dynamic-tools.d.ts.map +0 -1
  730. package/dist/tools/dynamic-tools.js.map +0 -1
  731. package/dist/tools/error-recovery.d.ts.map +0 -1
  732. package/dist/tools/error-recovery.js.map +0 -1
  733. package/dist/tools/invoke-tool.d.ts.map +0 -1
  734. package/dist/tools/invoke-tool.js.map +0 -1
  735. package/dist/tools/lease-tools.d.ts.map +0 -1
  736. package/dist/tools/lease-tools.js.map +0 -1
  737. package/dist/tools/merge-tools.d.ts.map +0 -1
  738. package/dist/tools/merge-tools.js.map +0 -1
  739. package/dist/tools/observe-tools.d.ts.map +0 -1
  740. package/dist/tools/observe-tools.js.map +0 -1
  741. package/dist/tools/profiles.d.ts.map +0 -1
  742. package/dist/tools/profiles.js.map +0 -1
  743. package/dist/tools/query-paginate.d.ts.map +0 -1
  744. package/dist/tools/query-paginate.js.map +0 -1
  745. package/dist/tools/read-tools.d.ts.map +0 -1
  746. package/dist/tools/read-tools.js.map +0 -1
  747. package/dist/tools/snapshot-delta.d.ts.map +0 -1
  748. package/dist/tools/snapshot-delta.js.map +0 -1
  749. package/dist/tools/tool-invoker.d.ts.map +0 -1
  750. package/dist/tools/tool-invoker.js.map +0 -1
  751. package/dist/tools/tool-kit.d.ts.map +0 -1
  752. package/dist/tools/tool-kit.js.map +0 -1
  753. package/dist/tools/tool-names.d.ts.map +0 -1
  754. package/dist/tools/tool-names.js.map +0 -1
  755. package/dist/tools/tools-helpers.d.ts.map +0 -1
  756. package/dist/tools/tools-helpers.js.map +0 -1
  757. package/dist/tools/tools.d.ts.map +0 -1
  758. package/dist/tools/tools.js.map +0 -1
  759. package/dist/update/update-checker.d.ts.map +0 -1
  760. package/dist/update/update-checker.js.map +0 -1
  761. package/dist/update/updater.d.ts.map +0 -1
  762. package/dist/update/updater.js.map +0 -1
  763. package/dist/visual/visual-diff.d.ts.map +0 -1
  764. package/dist/visual/visual-diff.js.map +0 -1
  765. package/dist/visual/visual-store.d.ts.map +0 -1
  766. package/dist/visual/visual-store.js.map +0 -1
  767. package/dist/visual/visual-tools.d.ts.map +0 -1
  768. package/dist/visual/visual-tools.js.map +0 -1
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The feedback channel — the one place in Reticle that sends words someone wrote.
3
+ *
4
+ * Reticle is built for agents, and until now nothing closed the loop: when a tool misbehaved, or a
5
+ * verification came back undecidable, or an observer simply could not see the thing that mattered,
6
+ * that knowledge died in the agent's context window. This module is the return path. An agent files a
7
+ * report through `reticle_feedback` when a tool fails it; a human files one through `reticle
8
+ * feedback` with a rating and their own words.
9
+ *
10
+ * Three properties are non-negotiable here, because free text is a different privacy class from the
11
+ * event counters the rest of telemetry sends:
12
+ *
13
+ * 1. NEVER PASSIVE. There is no code path that emits feedback on its own. Every event is the direct
14
+ * result of an explicit call someone made carrying content they authored. Nothing is scraped
15
+ * from the app, the DOM, the network log, or the repo.
16
+ * 2. REDACTED BEFORE THE WIRE. `redactFeedbackText` strips the credential/PII shapes that leak into
17
+ * a pasted trace even when the author meant no harm. It runs client-side, so the redaction is
18
+ * auditable in this repo rather than promised in a policy.
19
+ * 3. INDEPENDENTLY DISABLE-ABLE. `RETICLE_FEEDBACK=0` kills the channel while leaving anonymous
20
+ * adoption metrics on — the setting an org wants when counters are fine but prose is not. Every
21
+ * existing switch (`RETICLE_TELEMETRY=0`, `DO_NOT_TRACK`, `reticle telemetry disable`) still
22
+ * disables it too, since it rides the same emitter.
23
+ */
24
+ import { type Feedback } from '@reticlehq/core';
25
+ import { type SessionFacts } from './feedback-context.js';
26
+ /** Kills the feedback channel ONLY — adoption counters keep flowing. */
27
+ export declare const FEEDBACK_ENV = "RETICLE_FEEDBACK";
28
+ /** What replaces a redacted match. Visible on purpose: a reader must see that something was removed. */
29
+ export declare const REDACTED = "[redacted]";
30
+ export interface Redaction {
31
+ text: string;
32
+ /** Which rules fired, deduped. Surfaced back to the author so a redaction is never silent. */
33
+ removed: string[];
34
+ }
35
+ /** Strip credential/PII shapes and cap the length. Pure — the tests read like a spec of what leaks. */
36
+ export declare function redactFeedbackText(input: string, max: number): Redaction;
37
+ /** True when the feedback channel is switched off on its own (the emitter's switches apply as well). */
38
+ export declare function feedbackDisabled(env?: NodeJS.ProcessEnv): boolean;
39
+ /** What the author supplies; the environment context is detected, never asked for. */
40
+ export type FeedbackInput = Pick<Feedback, 'source' | 'kind' | 'text' | 'trace' | 'rating' | 'need' | 'impact' | 'currentApproach' | 'model'>;
41
+ export interface FeedbackReceipt {
42
+ /** False when a kill switch is on — the report was DROPPED, and the caller is told so plainly. */
43
+ sent: boolean;
44
+ reason?: string;
45
+ /** Which redaction rules fired. Empty when nothing needed removing. */
46
+ redacted: string[];
47
+ /** The exact context that went with it, echoed back so the send is never a black box. */
48
+ context: Partial<Feedback>;
49
+ }
50
+ /**
51
+ * Redact, validate, and emit one feedback report. Returns a receipt rather than throwing: a feedback
52
+ * send that fails must never take down the tool call that reported the failure — that would punish
53
+ * the exact behaviour we are trying to encourage.
54
+ */
55
+ export declare function submitFeedback(input: FeedbackInput, opts?: {
56
+ cwd?: string;
57
+ session?: SessionFacts;
58
+ env?: NodeJS.ProcessEnv;
59
+ }): Promise<FeedbackReceipt>;
60
+ /**
61
+ * The receipt's context PLUS the fields the emitter stamps on every event regardless of kind — the
62
+ * reticle version, the OS, and whether this is CI. They are the single most-asked question of any bug
63
+ * report ("what version?"), so they are echoed here rather than left as an invisible claim: what the
64
+ * CLI prints is then genuinely everything that goes.
65
+ */
66
+ export declare function describeFeedbackPayload(context: Partial<Feedback>): Record<string, unknown>;
@@ -0,0 +1,175 @@
1
+ /**
2
+ * The feedback channel — the one place in Reticle that sends words someone wrote.
3
+ *
4
+ * Reticle is built for agents, and until now nothing closed the loop: when a tool misbehaved, or a
5
+ * verification came back undecidable, or an observer simply could not see the thing that mattered,
6
+ * that knowledge died in the agent's context window. This module is the return path. An agent files a
7
+ * report through `reticle_feedback` when a tool fails it; a human files one through `reticle
8
+ * feedback` with a rating and their own words.
9
+ *
10
+ * Three properties are non-negotiable here, because free text is a different privacy class from the
11
+ * event counters the rest of telemetry sends:
12
+ *
13
+ * 1. NEVER PASSIVE. There is no code path that emits feedback on its own. Every event is the direct
14
+ * result of an explicit call someone made carrying content they authored. Nothing is scraped
15
+ * from the app, the DOM, the network log, or the repo.
16
+ * 2. REDACTED BEFORE THE WIRE. `redactFeedbackText` strips the credential/PII shapes that leak into
17
+ * a pasted trace even when the author meant no harm. It runs client-side, so the redaction is
18
+ * auditable in this repo rather than promised in a policy.
19
+ * 3. INDEPENDENTLY DISABLE-ABLE. `RETICLE_FEEDBACK=0` kills the channel while leaving anonymous
20
+ * adoption metrics on — the setting an org wants when counters are fine but prose is not. Every
21
+ * existing switch (`RETICLE_TELEMETRY=0`, `DO_NOT_TRACK`, `reticle telemetry disable`) still
22
+ * disables it too, since it rides the same emitter.
23
+ */
24
+ import { FeedbackSchema, FEEDBACK_TEXT_MAX, FEEDBACK_TRACE_MAX, FEEDBACK_FIELD_MAX, TelemetryEventKind, } from '@reticlehq/core';
25
+ import { platform } from 'node:os';
26
+ import { getTelemetry } from './telemetry.js';
27
+ import { SERVER_VERSION } from '../server-version.js';
28
+ import { feedbackContext } from './feedback-context.js';
29
+ /** Kills the feedback channel ONLY — adoption counters keep flowing. */
30
+ export const FEEDBACK_ENV = 'RETICLE_FEEDBACK';
31
+ /** What replaces a redacted match. Visible on purpose: a reader must see that something was removed. */
32
+ export const REDACTED = '[redacted]';
33
+ /**
34
+ * The shapes that leak. Ordered most-specific first — a URL carrying inline credentials must be
35
+ * caught as a URL before the bare-token rule chews the middle out of it.
36
+ *
37
+ * This is a net, not a proof. It cannot catch a secret that looks like an ordinary word, which is
38
+ * exactly why the tool description tells the agent not to paste app source or user data in the first
39
+ * place. Defense in depth: instruct first, redact second, cap third.
40
+ */
41
+ const REDACTIONS = [
42
+ // scheme://user:pass@host — the credential is in the authority section.
43
+ { pattern: /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi, label: 'url-credentials' },
44
+ { pattern: /\b[\w.%+-]+@[\w.-]+\.[a-z]{2,}\b/gi, label: 'email' },
45
+ // Credential assignments: the KEY stays (it is the useful part), the VALUE goes. The auth SCHEME
46
+ // (`Bearer`, `Basic`, `Token`) is consumed as part of the value, not left as the value — matching
47
+ // only `\S+` after the separator ate the word "Bearer" and published the secret right behind it.
48
+ {
49
+ pattern: /\b(authorization|api[-_]?key|secret|token|password|passwd|pwd)\b(?:\s*[:=]\s*|\s+)(?:(?:bearer|basic|token|digest)\s+)?\S+/gi,
50
+ label: 'credential-assignment',
51
+ },
52
+ // Vendor key formats that are self-identifying (sk-…, ghp_…, AKIA…, xoxb-…, eyJ… JWTs).
53
+ { pattern: /\b(?:sk|pk|rk)-[A-Za-z0-9_-]{16,}\b/g, label: 'vendor-key' },
54
+ { pattern: /\bgh[pousr]_[A-Za-z0-9]{20,}\b/g, label: 'github-token' },
55
+ { pattern: /\bAKIA[0-9A-Z]{16}\b/g, label: 'aws-key' },
56
+ { pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, label: 'slack-token' },
57
+ { pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g, label: 'jwt' },
58
+ // Home directories carry the account name, and a trace is full of them.
59
+ { pattern: /(?:\/Users\/|\/home\/|[A-Z]:\\Users\\)[^\s/\\:"']+/g, label: 'home-path' },
60
+ ];
61
+ /** Strip credential/PII shapes and cap the length. Pure — the tests read like a spec of what leaks. */
62
+ export function redactFeedbackText(input, max) {
63
+ const removed = new Set();
64
+ let text = input;
65
+ for (const { pattern, label } of REDACTIONS) {
66
+ text = text.replace(pattern, (_match, ...groups) => {
67
+ removed.add(label);
68
+ // A rule with a leading capture keeps it (the scheme, the `api_key=` key) so the reader still
69
+ // sees WHAT was removed, not just that something was.
70
+ const prefix = typeof groups[0] === 'string' ? groups[0] : '';
71
+ return `${prefix}${REDACTED}`;
72
+ });
73
+ }
74
+ return { text: text.slice(0, max), removed: [...removed] };
75
+ }
76
+ /** True when the feedback channel is switched off on its own (the emitter's switches apply as well). */
77
+ export function feedbackDisabled(env = process.env) {
78
+ const value = (env[FEEDBACK_ENV] ?? '').toLowerCase();
79
+ return value === '0' || value === 'false' || value === 'off' || value === 'no';
80
+ }
81
+ /**
82
+ * The fields an author writes, and therefore the fields that must be redacted. ONE list, used both to
83
+ * redact and to assemble — so a new field cannot be added to one and missed by the other.
84
+ *
85
+ * `model` is deliberately included: it is agent-supplied text like the rest, and while a model name
86
+ * is not sensitive, exempting it would re-introduce the "which fields are safe?" judgement call that
87
+ * caused the original gap.
88
+ */
89
+ const AUTHOR_WRITTEN_FIELDS = new Set([
90
+ 'text',
91
+ 'trace',
92
+ 'need',
93
+ 'impact',
94
+ 'currentApproach',
95
+ 'model',
96
+ ]);
97
+ /** Per-field caps; anything unlisted uses the standard field cap. */
98
+ const FIELD_CAPS = {
99
+ text: FEEDBACK_TEXT_MAX,
100
+ trace: FEEDBACK_TRACE_MAX,
101
+ model: 64,
102
+ };
103
+ /**
104
+ * Redact, validate, and emit one feedback report. Returns a receipt rather than throwing: a feedback
105
+ * send that fails must never take down the tool call that reported the failure — that would punish
106
+ * the exact behaviour we are trying to encourage.
107
+ */
108
+ export async function submitFeedback(input, opts = {}) {
109
+ const env = opts.env ?? process.env;
110
+ const context = feedbackContext(opts.cwd ?? process.cwd(), opts.session);
111
+ // Redact EVERY author-written field, derived from the input rather than listed.
112
+ //
113
+ // The first version named `text` and `trace` explicitly. When `need`, `impact` and
114
+ // `currentApproach` were added later they silently bypassed redaction entirely — three new
115
+ // free-text fields going to the wire raw, and a `currentApproach` reading "hardcoding the token
116
+ // sk-…" would have shipped the token. Enumerating the fields to protect is the same class of
117
+ // mistake as hand-copying an enum: correct on the day it is written, quietly wrong at the next
118
+ // addition. Deriving the set means a sixth field is covered the moment it exists.
119
+ const redactions = new Map();
120
+ for (const [key, value] of Object.entries(input)) {
121
+ if (typeof value !== 'string' || value === '')
122
+ continue;
123
+ if (!AUTHOR_WRITTEN_FIELDS.has(key))
124
+ continue;
125
+ redactions.set(key, redactFeedbackText(value, FIELD_CAPS[key] ?? FEEDBACK_FIELD_MAX));
126
+ }
127
+ const body = redactions.get('text') ?? { text: '', removed: [] };
128
+ const redacted = [...new Set([...redactions.values()].flatMap((r) => r.removed))];
129
+ if (feedbackDisabled(env)) {
130
+ return { sent: false, reason: `feedback is disabled by ${FEEDBACK_ENV}`, redacted, context };
131
+ }
132
+ const telemetry = getTelemetry();
133
+ if (!telemetry.enabled) {
134
+ return {
135
+ sent: false,
136
+ reason: 'telemetry is disabled on this machine, so feedback has nowhere to go',
137
+ redacted,
138
+ context,
139
+ };
140
+ }
141
+ const parsed = FeedbackSchema.safeParse({
142
+ source: input.source,
143
+ kind: input.kind,
144
+ // Every author-written field, redacted. Built from the map so nothing can be forgotten here
145
+ // either — the field list exists in exactly one place.
146
+ ...Object.fromEntries([...redactions].filter(([, r]) => r.text !== '').map(([key, r]) => [key, r.text])),
147
+ text: body.text,
148
+ ...(input.rating !== undefined ? { rating: input.rating } : {}),
149
+ ...context,
150
+ });
151
+ if (!parsed.success) {
152
+ return {
153
+ sent: false,
154
+ reason: parsed.error.issues[0]?.message ?? 'invalid feedback',
155
+ redacted,
156
+ context,
157
+ };
158
+ }
159
+ await telemetry.emit(TelemetryEventKind.FEEDBACK_SUBMITTED, { feedback: parsed.data });
160
+ return { sent: true, redacted, context };
161
+ }
162
+ /**
163
+ * The receipt's context PLUS the fields the emitter stamps on every event regardless of kind — the
164
+ * reticle version, the OS, and whether this is CI. They are the single most-asked question of any bug
165
+ * report ("what version?"), so they are echoed here rather than left as an invisible claim: what the
166
+ * CLI prints is then genuinely everything that goes.
167
+ */
168
+ export function describeFeedbackPayload(context) {
169
+ return {
170
+ ...context,
171
+ version: SERVER_VERSION,
172
+ os: platform(),
173
+ ci: process.env['CI'] !== undefined,
174
+ };
175
+ }
@@ -0,0 +1,21 @@
1
+ import { GitState, RepoForge } from '@reticlehq/core';
2
+ export interface GitFacts {
3
+ /** none | local_only (init'd, never pushed) | remote (has an origin). */
4
+ state: GitState;
5
+ /** The NORMALIZED origin — hashed by the caller, never sent raw. Absent unless state is `remote`. */
6
+ origin?: string;
7
+ /** Which forge hosts it, bucketed. Absent unless state is `remote`. */
8
+ forge?: RepoForge;
9
+ }
10
+ /** `git@github.com:Acme/Web.git` / `https://u:p@github.com/Acme/Web` → `github.com/acme/web`. */
11
+ export declare const normalizeGitOrigin: (url: string) => string;
12
+ /** Bucket a normalized origin by its host. Unknown hosts are `self_hosted` — never the host itself. */
13
+ export declare function forgeOf(normalizedOrigin: string): RepoForge;
14
+ type FileReader = (path: string) => string;
15
+ type PathExists = (path: string) => boolean;
16
+ /**
17
+ * Walk up from `cwd` looking for a `.git`, and report what is there. Never throws: an unreadable or
18
+ * malformed config reports the state we could confirm rather than failing a startup path.
19
+ */
20
+ export declare function gitFacts(cwd: string, read?: FileReader, exists?: PathExists): GitFacts;
21
+ export {};
@@ -0,0 +1,109 @@
1
+ /**
2
+ * What we can honestly know about a project's git setup, read from `.git/` on disk.
3
+ *
4
+ * This exists to make three counting questions answerable and, just as importantly, to make it
5
+ * visible when they are NOT answerable:
6
+ *
7
+ * - how many users does one project have? (distinct anonymousId per projectId)
8
+ * - how many projects does one user have? (distinct projectId per anonymousId)
9
+ * - how many people work alone vs on a shared repo?
10
+ *
11
+ * All three depend on `projectId` meaning the same thing on two different machines, which is only
12
+ * true when it was derived from a git ORIGIN. Outside a repo, or in a repo nobody has pushed, the
13
+ * fingerprint falls back to a hash of the directory path — and two teammates on the same unpushed
14
+ * project then look like two unrelated projects. That is not a bug we can fix (there is nothing
15
+ * shared to hash), so instead every event reports WHICH source it used, and the analytics can filter
16
+ * to the rows where "users per project" is a real number instead of quietly averaging in the ones
17
+ * where it is always 1.
18
+ *
19
+ * Read from `.git/config` directly rather than by shelling out to `git`: this runs on the CLI's
20
+ * startup path, where a ~30ms subprocess spawn would tax every single `reticle` command, and it must
21
+ * work on a machine with no `git` binary installed at all.
22
+ */
23
+ import { readFileSync, statSync } from 'node:fs';
24
+ import { dirname, join } from 'node:path';
25
+ import { GitState, RepoForge } from '@reticlehq/core';
26
+ /** How far up the tree to look for a `.git` before giving up. Deep monorepos are still well inside. */
27
+ const MAX_PARENT_WALK = 20;
28
+ /**
29
+ * The public forges we name. Everything else reports `self_hosted` WITHOUT its hostname — an internal
30
+ * git host is often `git.<company>.com`, which would identify the company outright and is exactly the
31
+ * covert identification the telemetry policy promises not to do. The bucket alone is the useful
32
+ * signal anyway: self-hosted git is a strong enterprise tell, which is the question actually being
33
+ * asked.
34
+ */
35
+ const PUBLIC_FORGES = [
36
+ ['github.com', RepoForge.GITHUB],
37
+ ['gitlab.com', RepoForge.GITLAB],
38
+ ['bitbucket.org', RepoForge.BITBUCKET],
39
+ ['dev.azure.com', RepoForge.AZURE],
40
+ ['git.sr.ht', RepoForge.SOURCEHUT],
41
+ ['codeberg.org', RepoForge.CODEBERG],
42
+ ];
43
+ /** `git@github.com:Acme/Web.git` / `https://u:p@github.com/Acme/Web` → `github.com/acme/web`. */
44
+ export const normalizeGitOrigin = (url) => url
45
+ .trim()
46
+ .replace(/^[a-z][a-z0-9+.-]*:\/\/[^@/]*@/i, '') // strip scheme + any inline credentials
47
+ .replace(/^[a-z][a-z0-9+.-]*:\/\//i, '') // strip a bare scheme
48
+ .replace(/^[^@/]+@/, '') // strip `git@` from the scp-style form
49
+ .replace(/:/g, '/') // scp-style `host:path` → `host/path`
50
+ // Trailing slashes BEFORE the `.git` suffix: a url written `…/web.git/` would otherwise keep its
51
+ // `.git` and count as a different project from the same repo cloned without the slash.
52
+ .replace(/\/+$/, '')
53
+ .replace(/\.git$/i, '')
54
+ .replace(/\/+$/, '')
55
+ .toLowerCase();
56
+ /** Bucket a normalized origin by its host. Unknown hosts are `self_hosted` — never the host itself. */
57
+ export function forgeOf(normalizedOrigin) {
58
+ const host = normalizedOrigin.split('/')[0] ?? '';
59
+ for (const [domain, forge] of PUBLIC_FORGES) {
60
+ // `ssh.dev.azure.com` and `www.github.com` are the same forge; match on suffix, not equality.
61
+ if (host === domain || host.endsWith(`.${domain}`))
62
+ return forge;
63
+ }
64
+ return RepoForge.SELF_HOSTED;
65
+ }
66
+ const defaultRead = (path) => readFileSync(path, 'utf8');
67
+ const defaultExists = (path) => {
68
+ try {
69
+ statSync(path);
70
+ return true;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ };
76
+ /**
77
+ * Walk up from `cwd` looking for a `.git`, and report what is there. Never throws: an unreadable or
78
+ * malformed config reports the state we could confirm rather than failing a startup path.
79
+ */
80
+ export function gitFacts(cwd, read = defaultRead, exists = defaultExists) {
81
+ let dir = cwd;
82
+ for (let depth = 0; depth < MAX_PARENT_WALK; depth += 1) {
83
+ const gitDir = join(dir, '.git');
84
+ if (exists(gitDir)) {
85
+ let config = '';
86
+ try {
87
+ config = read(join(gitDir, 'config'));
88
+ }
89
+ catch {
90
+ // A `.git` with no readable config is still a repo — report it as one rather than as absent.
91
+ return { state: GitState.LOCAL_ONLY };
92
+ }
93
+ // The url line inside the [remote "origin"] section — the first url after that header wins.
94
+ const section = config.split(/\[remote\s+"origin"\]/)[1];
95
+ const url = section?.match(/^\s*url\s*=\s*(.+)$/m)?.[1];
96
+ if (url === undefined)
97
+ return { state: GitState.LOCAL_ONLY };
98
+ const origin = normalizeGitOrigin(url);
99
+ if (origin === '')
100
+ return { state: GitState.LOCAL_ONLY };
101
+ return { state: GitState.REMOTE, origin, forge: forgeOf(origin) };
102
+ }
103
+ const parent = dirname(dir);
104
+ if (parent === dir)
105
+ break; // hit the filesystem root
106
+ dir = parent;
107
+ }
108
+ return { state: GitState.NONE };
109
+ }
@@ -0,0 +1,22 @@
1
+ import { UsageContextKind, type Identity } from '@reticlehq/core';
2
+ /** Re-exported so the CLI has one import for the whole feature; the shape itself lives in core. */
3
+ export { UsageContextKind };
4
+ export type { Identity };
5
+ export declare function readIdentity(file?: string): Identity | undefined;
6
+ export declare function saveIdentity(identity: Identity, file?: string): void;
7
+ export declare function clearIdentity(file?: string): void;
8
+ /**
9
+ * What identifying yourself actually does, in plain words, shown BEFORE anything is sent.
10
+ *
11
+ * The second sentence is the one that matters and the one a consent notice usually omits: the
12
+ * identity is keyed to the same anonymous id the previous events carried, so opting in links the
13
+ * usage history that was already collected. That is exactly what makes it useful to us, which is
14
+ * exactly why the user has to be told before they choose, not after.
15
+ */
16
+ export declare const IDENTIFY_NOTICE: string;
17
+ /**
18
+ * Report an identity. Emitted as its own event so it is trivially separable from the anonymous
19
+ * stream — a distinct name is what lets the analytics side hold it under a different retention rule,
20
+ * or drop it entirely, without touching the adoption metrics.
21
+ */
22
+ export declare function submitIdentity(identity: Identity): Promise<boolean>;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * `reticle identify` — the ONLY way Reticle ever learns who you are, and it is a thing you type.
3
+ *
4
+ * The product question behind this is real: which of these anonymous ids are companies who would pay
5
+ * for support, an enterprise licence, or a design-partner slot? The tempting answer is to infer it —
6
+ * match a git remote against a company domain, sniff an email out of `git config`, resolve an npm org.
7
+ * Reticle does none of that, and the refusal is deliberate rather than squeamish:
8
+ *
9
+ * - it would contradict a promise made in four places (README, usage, enterprise FAQ, telemetry
10
+ * policy) that project names, git remotes and account identifiers are never sent;
11
+ * - covert identification of a data subject is not "anonymous usage metrics", so it would also
12
+ * break the legal basis the policy states — legitimate interest, minimized to the listed fields;
13
+ * - and it is worse at the actual job. A scraped lead is a cold email from a tool the recipient
14
+ * trusted, which is the fastest way to turn an advocate into someone who runs
15
+ * `reticle telemetry disable` and tells their team to do the same. A self-identified one already
16
+ * wants to talk to you.
17
+ *
18
+ * So this is opt-in, explicit, reversible, and it tells the user exactly what it links before it
19
+ * sends anything.
20
+ */
21
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
22
+ import { homedir } from 'node:os';
23
+ import { join } from 'node:path';
24
+ import { TelemetryEventKind, UsageContextKind } from '@reticlehq/core';
25
+ import { getTelemetry } from './telemetry.js';
26
+ const RETICLE_DIR = join(homedir(), '.reticle');
27
+ /** Persisted so the identity survives shells and is attached to later sessions — and so it can be shown back. */
28
+ const IDENTITY_FILE = join(RETICLE_DIR, 'identity.json');
29
+ /** Re-exported so the CLI has one import for the whole feature; the shape itself lives in core. */
30
+ export { UsageContextKind };
31
+ export function readIdentity(file = IDENTITY_FILE) {
32
+ try {
33
+ return JSON.parse(readFileSync(file, 'utf8'));
34
+ }
35
+ catch {
36
+ return undefined;
37
+ }
38
+ }
39
+ export function saveIdentity(identity, file = IDENTITY_FILE) {
40
+ mkdirSync(RETICLE_DIR, { recursive: true });
41
+ writeFileSync(file, JSON.stringify(identity, null, 2), 'utf8');
42
+ }
43
+ export function clearIdentity(file = IDENTITY_FILE) {
44
+ rmSync(file, { force: true });
45
+ }
46
+ /**
47
+ * What identifying yourself actually does, in plain words, shown BEFORE anything is sent.
48
+ *
49
+ * The second sentence is the one that matters and the one a consent notice usually omits: the
50
+ * identity is keyed to the same anonymous id the previous events carried, so opting in links the
51
+ * usage history that was already collected. That is exactly what makes it useful to us, which is
52
+ * exactly why the user has to be told before they choose, not after.
53
+ */
54
+ export const IDENTIFY_NOTICE = [
55
+ 'This sends the details you type here to the Reticle maintainers, so we can contact you and',
56
+ "understand how teams use Reticle. It is linked to this machine's anonymous id, which means it",
57
+ 'also connects the anonymous usage already recorded from this machine to what you enter now.',
58
+ 'Nothing about your app, your code, or your repository is included, and nothing else changes.',
59
+ 'Undo it any time with `reticle identify --forget` (that stops future sends and deletes the local file;',
60
+ 'email support@reticlehq.com to have what was already sent removed).',
61
+ ].join('\n');
62
+ /**
63
+ * Report an identity. Emitted as its own event so it is trivially separable from the anonymous
64
+ * stream — a distinct name is what lets the analytics side hold it under a different retention rule,
65
+ * or drop it entirely, without touching the adoption metrics.
66
+ */
67
+ export async function submitIdentity(identity) {
68
+ const telemetry = getTelemetry();
69
+ if (!telemetry.enabled)
70
+ return false;
71
+ await telemetry.emit(TelemetryEventKind.IDENTIFIED, { identity });
72
+ return true;
73
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * How `reticle init` went.
3
+ *
4
+ * The onboarding funnel had no instrumentation at all, which meant the two most different failure
5
+ * modes were indistinguishable: someone whose setup died on a missing dependency looked exactly like
6
+ * someone who installed the package and never ran the command. One is a bug we can fix; the other is
7
+ * a marketing problem. Both showed up as silence.
8
+ *
9
+ * `reticle init` runs as a one-shot CLI command that exits immediately, so the send is DETACHED — the
10
+ * same treatment `cli_command_run` gets, for the same reason: an in-process fetch would keep the
11
+ * event loop alive and tax the command by most of a second.
12
+ */
13
+ import { type InitOutcome } from '@reticlehq/core';
14
+ /** Classified init failures — our own vocabulary, never a raw error or a path. */
15
+ export declare const InitFailure: {
16
+ /** Run outside a project root. The single most common first-run mistake. */
17
+ readonly NO_PACKAGE_JSON: "no_package_json";
18
+ /** The package manager failed: offline, a locked registry, a broken install. */
19
+ readonly DEPENDENCY_INSTALL: "dependency_install";
20
+ /** The `claude mcp add` step failed — the CLI is missing or refused. Reticle installs but is unreachable. */
21
+ readonly MCP_REGISTRATION: "mcp_registration";
22
+ readonly OTHER: "other";
23
+ };
24
+ export type InitFailure = (typeof InitFailure)[keyof typeof InitFailure];
25
+ /** Report one init outcome. Best-effort; setup must never fail because a metric did. */
26
+ export declare function reportInitOutcome(init: InitOutcome): void;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * How `reticle init` went.
3
+ *
4
+ * The onboarding funnel had no instrumentation at all, which meant the two most different failure
5
+ * modes were indistinguishable: someone whose setup died on a missing dependency looked exactly like
6
+ * someone who installed the package and never ran the command. One is a bug we can fix; the other is
7
+ * a marketing problem. Both showed up as silence.
8
+ *
9
+ * `reticle init` runs as a one-shot CLI command that exits immediately, so the send is DETACHED — the
10
+ * same treatment `cli_command_run` gets, for the same reason: an in-process fetch would keep the
11
+ * event loop alive and tax the command by most of a second.
12
+ */
13
+ import { TelemetryEventKind } from '@reticlehq/core';
14
+ import { getTelemetry } from './telemetry.js';
15
+ /** Classified init failures — our own vocabulary, never a raw error or a path. */
16
+ export const InitFailure = {
17
+ /** Run outside a project root. The single most common first-run mistake. */
18
+ NO_PACKAGE_JSON: 'no_package_json',
19
+ /** The package manager failed: offline, a locked registry, a broken install. */
20
+ DEPENDENCY_INSTALL: 'dependency_install',
21
+ /** The `claude mcp add` step failed — the CLI is missing or refused. Reticle installs but is unreachable. */
22
+ MCP_REGISTRATION: 'mcp_registration',
23
+ OTHER: 'other',
24
+ };
25
+ /** Report one init outcome. Best-effort; setup must never fail because a metric did. */
26
+ export function reportInitOutcome(init) {
27
+ try {
28
+ void getTelemetry().emit(TelemetryEventKind.INIT_COMPLETED, { init, detach: true });
29
+ }
30
+ catch {
31
+ /* a metric must never break `reticle init` */
32
+ }
33
+ }
@@ -0,0 +1,6 @@
1
+ import type { MachineSnapshot } from '@reticlehq/core';
2
+ /**
3
+ * Sample the machine. Never throws — this is called from a crash handler, where the one unacceptable
4
+ * outcome is making the crash worse.
5
+ */
6
+ export declare function machineSnapshot(): MachineSnapshot | undefined;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * What the machine looked like at a moment worth remembering.
3
+ *
4
+ * "Out of memory" and "our bug" produce identical-looking stack traces and are completely different
5
+ * problems — one is a docs/limits issue on the user's side, the other is ours to fix. Without this,
6
+ * every crash report arrived with that ambiguity baked in and no way to resolve it after the fact.
7
+ *
8
+ * Sampled at MOMENTS — a crash, the end of a session — never per tool call. `os.loadavg()` and
9
+ * `process.memoryUsage()` are cheap but not free, and taking them two hundred times a session to
10
+ * answer a question only ever asked about the bad moments would be a continuous cost for an
11
+ * occasional need.
12
+ *
13
+ * Nothing here describes the person: it is our own process's footprint plus coarse machine capacity.
14
+ * No hostname, no username, no disk paths, no process list.
15
+ */
16
+ import { cpus, freemem, loadavg, totalmem } from 'node:os';
17
+ const MB = 1024 * 1024;
18
+ /**
19
+ * Sample the machine. Never throws — this is called from a crash handler, where the one unacceptable
20
+ * outcome is making the crash worse.
21
+ */
22
+ export function machineSnapshot() {
23
+ try {
24
+ const memory = process.memoryUsage();
25
+ return {
26
+ rssMb: Math.round(memory.rss / MB),
27
+ heapUsedMb: Math.round(memory.heapUsed / MB),
28
+ freeMemMb: Math.round(freemem() / MB),
29
+ totalMemMb: Math.round(totalmem() / MB),
30
+ // ×100 so it stays an integer property rather than a float. Windows always reports 0 here,
31
+ // which is a platform fact rather than an idle machine — read it alongside `os`.
32
+ load1x100: Math.max(0, Math.round((loadavg()[0] ?? 0) * 100)),
33
+ cpuCount: cpus().length,
34
+ };
35
+ }
36
+ catch {
37
+ return undefined;
38
+ }
39
+ }
@@ -0,0 +1,5 @@
1
+ export declare function markDaemonStart(now: number): void;
2
+ /** Report one client attaching. Best-effort; a metric must never affect whether a client connects. */
3
+ export declare function reportMcpConnected(client?: string, now?: () => number): void;
4
+ /** Tests only. */
5
+ export declare function resetMcpConnections(): void;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * When an MCP client actually attaches.
3
+ *
4
+ * This is the signal that separates "Reticle is installed and the daemon is running" from "a person
5
+ * is using it". A daemon can sit up for days with no agent ever attaching — which looks like healthy
6
+ * adoption in `daemon_started` and is in fact an onboarding failure nobody would think to report.
7
+ *
8
+ * It also exposes reconnect CHURN. A client whose transport keeps dropping reattaches every few
9
+ * minutes, and in every other metric that is indistinguishable from enthusiastic use: more sessions,
10
+ * more connects, more activity. The `reconnect` flag is what tells those two stories apart.
11
+ */
12
+ import { TelemetryEventKind } from '@reticlehq/core';
13
+ import { getTelemetry } from './telemetry.js';
14
+ let connectsSeen = 0;
15
+ /** Set when the daemon starts, so the FIRST connect can report how long Reticle sat unused. */
16
+ let daemonStartedAt;
17
+ export function markDaemonStart(now) {
18
+ daemonStartedAt = now;
19
+ connectsSeen = 0;
20
+ }
21
+ /** Report one client attaching. Best-effort; a metric must never affect whether a client connects. */
22
+ export function reportMcpConnected(client, now = () => Date.now()) {
23
+ try {
24
+ const reconnect = connectsSeen > 0;
25
+ connectsSeen += 1;
26
+ void getTelemetry().emit(TelemetryEventKind.MCP_CLIENT_CONNECTED, {
27
+ connection: {
28
+ reconnect,
29
+ // A large value on the FIRST connect is the interesting case: Reticle was started and then
30
+ // sat there. On a reconnect it is just how long the daemon has been up.
31
+ daemonAgeMs: daemonStartedAt === undefined ? 0 : Math.max(0, now() - daemonStartedAt),
32
+ ...(client !== undefined ? { client } : {}),
33
+ },
34
+ });
35
+ }
36
+ catch {
37
+ /* never let a metric interfere with a client attaching */
38
+ }
39
+ }
40
+ /** Tests only. */
41
+ export function resetMcpConnections() {
42
+ connectsSeen = 0;
43
+ daemonStartedAt = undefined;
44
+ }