@reticlehq/server 3.6.0 → 3.7.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 (614) hide show
  1. package/SKILL.md +122 -123
  2. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  3. package/dist/command/cli/adhoc-suite.js +42 -7
  4. package/dist/command/cli/adhoc-verdict.d.ts +18 -2
  5. package/dist/command/cli/adhoc-verdict.js +70 -6
  6. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  7. package/dist/command/cli/answers/gate-exit.js +45 -0
  8. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  9. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  10. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  11. package/dist/command/cli/auth/device-flow.js +17 -0
  12. package/dist/command/cli/cli-doctor.js +14 -0
  13. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  14. package/dist/command/cli/cli-flow-commands.js +28 -105
  15. package/dist/command/cli/cli-kill.js +3 -2
  16. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  17. package/dist/command/cli/cli-parse-grammar.js +75 -0
  18. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  19. package/dist/command/cli/cli-parse-verify.js +18 -0
  20. package/dist/command/cli/cli-parse.d.ts +19 -28
  21. package/dist/command/cli/cli-parse.js +82 -182
  22. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  23. package/dist/command/cli/cli-update-commands.js +61 -9
  24. package/dist/command/cli/cli-usage.d.ts +33 -0
  25. package/dist/command/cli/cli-usage.js +287 -0
  26. package/dist/command/cli/cli-verify.d.ts +34 -4
  27. package/dist/command/cli/cli-verify.js +81 -12
  28. package/dist/command/cli/cloud-cli.d.ts +13 -0
  29. package/dist/command/cli/cloud-cli.js +145 -333
  30. package/dist/command/cli/cloud-kit.d.ts +12 -0
  31. package/dist/command/cli/cloud-kit.js +41 -2
  32. package/dist/command/cli/cloud-link.d.ts +57 -0
  33. package/dist/command/cli/cloud-link.js +308 -0
  34. package/dist/command/cli/cloud-login.d.ts +15 -1
  35. package/dist/command/cli/cloud-login.js +67 -13
  36. package/dist/command/cli/context-command.d.ts +1 -0
  37. package/dist/command/cli/context-command.js +33 -0
  38. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  39. package/dist/command/cli/daemon-start-options.js +24 -3
  40. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  41. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  42. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  43. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  44. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  45. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  46. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  47. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  48. package/dist/command/cli/known-regression.d.ts +13 -0
  49. package/dist/command/cli/known-regression.js +34 -0
  50. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  51. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  52. package/dist/command/cli/lifecycle/daemon-lifecycle.js +11 -2
  53. package/dist/command/cli/mcp-command.d.ts +6 -0
  54. package/dist/command/cli/mcp-command.js +13 -5
  55. package/dist/command/cli/ports/port-holder.js +1 -1
  56. package/dist/command/cli/project-name.d.ts +29 -1
  57. package/dist/command/cli/project-name.js +107 -2
  58. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  59. package/dist/command/cli/setup-mcp-cli.js +29 -8
  60. package/dist/command/cli/status/status-lines.d.ts +1 -0
  61. package/dist/command/cli/status/status-lines.js +47 -2
  62. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  63. package/dist/command/cli/status/workspace-links.js +29 -0
  64. package/dist/command/cli/try-command.d.ts +96 -0
  65. package/dist/command/cli/try-command.js +362 -0
  66. package/dist/command/cli/tutorial.d.ts +0 -100
  67. package/dist/command/cli/tutorial.js +0 -178
  68. package/dist/command/cli/verify-results.d.ts +19 -0
  69. package/dist/command/cli/verify-results.js +29 -0
  70. package/dist/command/cli-onboarding.d.ts +0 -11
  71. package/dist/command/cli-onboarding.js +0 -15
  72. package/dist/command/cli.d.ts +14 -0
  73. package/dist/command/cli.js +103 -83
  74. package/dist/command/daemon/daemon-resilience.js +4 -4
  75. package/dist/command/daemon/daemon-resolve.d.ts +9 -1
  76. package/dist/command/daemon/daemon-resolve.js +49 -10
  77. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  78. package/dist/command/setup/bringup/bridge-port.js +13 -3
  79. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  80. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  81. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  82. package/dist/command/setup/init/agent-restart.js +28 -0
  83. package/dist/command/setup/init/init-port.d.ts +10 -1
  84. package/dist/command/setup/init/init-port.js +22 -2
  85. package/dist/command/setup/init/init-runtime.d.ts +12 -2
  86. package/dist/command/setup/init/init-runtime.js +96 -37
  87. package/dist/command/setup/node-effects.d.ts +2 -0
  88. package/dist/command/setup/node-effects.js +36 -8
  89. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  90. package/dist/command/setup/probe/existing-app.js +14 -0
  91. package/dist/command/setup/remaining-steps.js +1 -1
  92. package/dist/command/setup/run-setup.d.ts +29 -9
  93. package/dist/command/setup/run-setup.js +34 -28
  94. package/dist/command/setup/setup-command.d.ts +23 -0
  95. package/dist/command/setup/setup-command.js +57 -4
  96. package/dist/command/setup/setup-mcp.js +25 -2
  97. package/dist/command/setup/tauri-signing.d.ts +19 -0
  98. package/dist/command/setup/tauri-signing.js +79 -0
  99. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  100. package/dist/command/setup/terminal/listeners.js +37 -6
  101. package/dist/command/update/update-nudge.d.ts +9 -0
  102. package/dist/command/update/update-nudge.js +1 -1
  103. package/dist/command/update/updater.js +11 -15
  104. package/dist/command/version/version-nudge.js +3 -0
  105. package/dist/command/version/version-skew.d.ts +20 -1
  106. package/dist/command/version/version-skew.js +38 -2
  107. package/dist/features/crawl/crawl.js +14 -1
  108. package/dist/features/exhaust/ledger.d.ts +14 -14
  109. package/dist/features/harness/drive-report.d.ts +39 -5
  110. package/dist/features/harness/drive-report.js +271 -54
  111. package/dist/features/harness/drive-runs.d.ts +120 -0
  112. package/dist/features/harness/drive-runs.js +289 -0
  113. package/dist/features/harness/drivers.d.ts +1 -1
  114. package/dist/features/harness/drivers.js +1 -1
  115. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  116. package/dist/features/harness/explore/console-pages.js +146 -0
  117. package/dist/features/harness/explore/disparity.d.ts +19 -0
  118. package/dist/features/harness/explore/disparity.js +71 -0
  119. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  120. package/dist/features/harness/explore/fake-app.js +49 -0
  121. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  122. package/dist/features/harness/explore/goal-search.js +144 -0
  123. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  124. package/dist/features/harness/explore/page-tree.js +148 -0
  125. package/dist/features/harness/explore/site-map.d.ts +34 -0
  126. package/dist/features/harness/explore/site-map.js +150 -0
  127. package/dist/features/harness/goals.d.ts +68 -7
  128. package/dist/features/harness/goals.js +289 -36
  129. package/dist/features/harness/harness.d.ts +30 -1
  130. package/dist/features/harness/harness.js +141 -7
  131. package/dist/features/harness/platform/local-apps.d.ts +36 -3
  132. package/dist/features/harness/platform/local-apps.js +81 -5
  133. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  134. package/dist/features/harness/platform/persona-credentials.js +69 -0
  135. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  136. package/dist/features/harness/platform/platform-drives.js +114 -0
  137. package/dist/features/harness/platform/refusal.d.ts +52 -0
  138. package/dist/features/harness/platform/refusal.js +71 -0
  139. package/dist/features/harness/platform/remote-drive.d.ts +8 -2
  140. package/dist/features/harness/platform/remote-drive.js +22 -9
  141. package/dist/features/harness/platform/script.d.ts +57 -11
  142. package/dist/features/harness/platform/script.js +144 -12
  143. package/dist/features/harness/platform/server-driver.d.ts +17 -4
  144. package/dist/features/harness/platform/server-driver.js +29 -26
  145. package/dist/features/harness/platform-config.d.ts +38 -5
  146. package/dist/features/harness/platform-config.js +93 -8
  147. package/dist/features/harness/route-guess.d.ts +13 -0
  148. package/dist/features/harness/route-guess.js +49 -0
  149. package/dist/features/harness/script/script-run.d.ts +30 -1
  150. package/dist/features/harness/script/script-run.js +355 -48
  151. package/dist/features/license/license.d.ts +2 -2
  152. package/dist/features/visual/step-shots.d.ts +31 -0
  153. package/dist/features/visual/step-shots.js +231 -0
  154. package/dist/features/visual/visual-tools.js +22 -14
  155. package/dist/hooks/client-directory.d.ts +18 -0
  156. package/dist/hooks/client-directory.js +57 -0
  157. package/dist/hooks/coding-agents.d.ts +34 -0
  158. package/dist/hooks/coding-agents.js +117 -0
  159. package/dist/hooks/driven-by.d.ts +21 -2
  160. package/dist/hooks/driven-by.js +42 -2
  161. package/dist/hooks/hook-bus.d.ts +4 -0
  162. package/dist/hooks/hook-bus.js +18 -0
  163. package/dist/index.d.ts +1 -0
  164. package/dist/index.js +26 -183
  165. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  166. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  167. package/dist/judgement/capsule/causal-summary.js +33 -0
  168. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  169. package/dist/judgement/runs/artifact/build-verification-run.js +20 -4
  170. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  171. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  172. package/dist/judgement/runs/artifact/replay-mapping.js +25 -9
  173. package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
  174. package/dist/judgement/runs/artifact/run-store.js +175 -8
  175. package/dist/judgement/runs/context-tools.js +59 -1
  176. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  177. package/dist/judgement/runs/default-run-id.js +16 -0
  178. package/dist/judgement/runs/drive-run.d.ts +53 -5
  179. package/dist/judgement/runs/drive-run.js +234 -20
  180. package/dist/judgement/runs/resume.d.ts +44 -0
  181. package/dist/judgement/runs/resume.js +137 -0
  182. package/dist/judgement/runs/reticle-runner.js +5 -2
  183. package/dist/judgement/runs/runner-port.d.ts +5 -1
  184. package/dist/judgement/runs/runner-port.js +8 -2
  185. package/dist/judgement/runs/verification-sync.d.ts +2 -0
  186. package/dist/judgement/runs/verification-sync.js +36 -15
  187. package/dist/language/flows/decision.js +2 -1
  188. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  189. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  190. package/dist/language/flows/flow-anchor.d.ts +7 -2
  191. package/dist/language/flows/flow-anchor.js +10 -3
  192. package/dist/language/flows/flow-intent.d.ts +1 -0
  193. package/dist/language/flows/flow-journey.d.ts +6 -0
  194. package/dist/language/flows/flow-journey.js +20 -0
  195. package/dist/language/flows/flow-learning.d.ts +4 -0
  196. package/dist/language/flows/flow-learning.js +37 -3
  197. package/dist/language/flows/flow-replay-run.js +16 -18
  198. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  199. package/dist/language/flows/flow-replay.d.ts +18 -1
  200. package/dist/language/flows/flow-replay.js +22 -7
  201. package/dist/language/flows/flow-result.d.ts +22 -1
  202. package/dist/language/flows/flow-result.js +47 -2
  203. package/dist/language/flows/flow-step-runners.d.ts +2 -0
  204. package/dist/language/flows/flow-step-runners.js +12 -6
  205. package/dist/language/flows/flow-store-for-session.js +5 -1
  206. package/dist/language/flows/flow-tools.d.ts +10 -0
  207. package/dist/language/flows/flow-tools.js +61 -62
  208. package/dist/language/flows/flows.d.ts +16 -1
  209. package/dist/language/flows/flows.js +69 -10
  210. package/dist/language/flows/narrow-write.d.ts +7 -0
  211. package/dist/language/flows/narrow-write.js +36 -1
  212. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  213. package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
  214. package/dist/language/flows/recording/tape/recordings.js +60 -10
  215. package/dist/language/flows/replay.js +29 -6
  216. package/dist/language/flows/single-replay.d.ts +7 -0
  217. package/dist/language/flows/single-replay.js +26 -0
  218. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  219. package/dist/language/flows/verify-change-tools.js +200 -193
  220. package/dist/memory/cloud/cloud-config.d.ts +10 -1
  221. package/dist/memory/cloud/cloud-config.js +19 -5
  222. package/dist/memory/cloud/cloud-sync.js +3 -3
  223. package/dist/memory/cloud/harness-config.d.ts +49 -0
  224. package/dist/memory/cloud/harness-config.js +16 -20
  225. package/dist/memory/cloud/memory-scope.d.ts +17 -0
  226. package/dist/memory/cloud/memory-scope.js +22 -0
  227. package/dist/memory/cloud/sync-cycle.d.ts +32 -4
  228. package/dist/memory/cloud/sync-cycle.js +113 -12
  229. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  230. package/dist/memory/cloud/sync-daemon.js +114 -4
  231. package/dist/memory/cloud/sync-disk.js +26 -2
  232. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  233. package/dist/memory/cloud/sync-screenshots.js +105 -0
  234. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  235. package/dist/memory/cloud/unsynced-roots.js +166 -0
  236. package/dist/memory/impact/account-watch.d.ts +16 -1
  237. package/dist/memory/impact/account-watch.js +26 -1
  238. package/dist/memory/impact/impact-store.d.ts +1 -4
  239. package/dist/memory/impact/impact-store.js +32 -42
  240. package/dist/memory/intent/inline-intent.d.ts +1 -0
  241. package/dist/memory/intent/intent-shard-store.js +16 -4
  242. package/dist/memory/intent/intent-shard.d.ts +12 -0
  243. package/dist/memory/intent/intent-store.d.ts +1 -0
  244. package/dist/memory/intent/intent-tools.js +42 -2
  245. package/dist/memory/intent/open-intents.d.ts +6 -0
  246. package/dist/memory/intent/open-intents.js +10 -1
  247. package/dist/memory/intent/settled-words.d.ts +24 -0
  248. package/dist/memory/intent/settled-words.js +130 -0
  249. package/dist/memory/journal/drive-flow.d.ts +16 -0
  250. package/dist/memory/journal/drive-flow.js +34 -2
  251. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  252. package/dist/memory/journal/drive-run-flush.js +20 -5
  253. package/dist/memory/journal/journal-recorder.js +46 -3
  254. package/dist/memory/journal/on-disk/retention.d.ts +5 -0
  255. package/dist/memory/journal/on-disk/retention.js +27 -2
  256. package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
  257. package/dist/memory/journal/session-end.d.ts +15 -1
  258. package/dist/memory/journal/session-end.js +38 -7
  259. package/dist/memory/project/artifact-root-resolver.js +33 -5
  260. package/dist/memory/project/artifact-root.d.ts +4 -3
  261. package/dist/memory/project/artifact-root.js +2 -2
  262. package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
  263. package/dist/memory/project/dir/reticle-dir.js +23 -2
  264. package/dist/memory/project/link-directory.d.ts +15 -0
  265. package/dist/memory/project/link-directory.js +44 -0
  266. package/dist/memory/project/root-claims.d.ts +6 -0
  267. package/dist/memory/project/root-claims.js +39 -0
  268. package/dist/memory/project/session-root.d.ts +2 -0
  269. package/dist/memory/project/session-root.js +9 -1
  270. package/dist/memory/project/sync-status.d.ts +46 -0
  271. package/dist/memory/project/sync-status.js +135 -1
  272. package/dist/memory/recall/memory-tools.js +46 -3
  273. package/dist/memory/recall/platform-memory.d.ts +34 -0
  274. package/dist/memory/recall/platform-memory.js +139 -0
  275. package/dist/memory/recall/project-memory.js +36 -8
  276. package/dist/portal/bridge/bridge.d.ts +9 -5
  277. package/dist/portal/bridge/bridge.js +66 -23
  278. package/dist/portal/bridge/harness-request.d.ts +23 -0
  279. package/dist/portal/bridge/harness-request.js +27 -0
  280. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  281. package/dist/portal/bridge/wrong-path.js +35 -0
  282. package/dist/portal/input/network-mock-tools.js +11 -2
  283. package/dist/portal/input/real-input.d.ts +2 -0
  284. package/dist/portal/input/real-input.js +13 -10
  285. package/dist/portal/pool/browser-pool.d.ts +48 -0
  286. package/dist/portal/pool/browser-pool.js +120 -2
  287. package/dist/portal/pool/context-permissions.d.ts +33 -0
  288. package/dist/portal/pool/context-permissions.js +33 -0
  289. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  290. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  291. package/dist/portal/pool/playwright-launcher.d.ts +27 -5
  292. package/dist/portal/pool/playwright-launcher.js +59 -14
  293. package/dist/portal/pool/pool-contract.d.ts +21 -1
  294. package/dist/portal/session/agent-link.d.ts +8 -0
  295. package/dist/portal/session/agent-link.js +17 -0
  296. package/dist/portal/session/command-payload.js +6 -1
  297. package/dist/portal/session/daemon-answers.d.ts +3 -3
  298. package/dist/portal/session/daemon-answers.js +4 -2
  299. package/dist/portal/session/dev-server/dev-command.d.ts +9 -0
  300. package/dist/portal/session/dev-server/dev-command.js +27 -1
  301. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  302. package/dist/portal/session/facts/observed-state.js +46 -3
  303. package/dist/portal/session/human/live-control.d.ts +9 -2
  304. package/dist/portal/session/human/live-control.js +12 -3
  305. package/dist/portal/session/live-control-tools.js +82 -13
  306. package/dist/portal/session/narration-args.d.ts +5 -0
  307. package/dist/portal/session/narration-args.js +17 -0
  308. package/dist/portal/session/no-session-diagnosis.d.ts +1 -1
  309. package/dist/portal/session/no-session-diagnosis.js +31 -9
  310. package/dist/portal/session/no-session-next-action.d.ts +20 -0
  311. package/dist/portal/session/no-session-next-action.js +134 -61
  312. package/dist/portal/session/no-session-watch.js +179 -22
  313. package/dist/portal/session/presence/session-lease.js +1 -1
  314. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  315. package/dist/portal/session/recorded-gaps.js +251 -0
  316. package/dist/portal/session/session-health.d.ts +11 -0
  317. package/dist/portal/session/session-health.js +3 -1
  318. package/dist/portal/session/session-info.js +2 -1
  319. package/dist/portal/session/session-manager.d.ts +18 -0
  320. package/dist/portal/session/session-manager.js +54 -3
  321. package/dist/portal/session/session-successor.d.ts +8 -0
  322. package/dist/portal/session/session-successor.js +1 -1
  323. package/dist/portal/session/session.d.ts +15 -28
  324. package/dist/portal/session/session.js +60 -61
  325. package/dist/portal/session/timing/command-timeout.js +25 -1
  326. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  327. package/dist/portal/session/timing/wall-clock.js +1 -1
  328. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  329. package/dist/portal/session/zero-install-first-call.js +88 -0
  330. package/dist/start-options.d.ts +7 -1
  331. package/dist/start-wiring.d.ts +63 -0
  332. package/dist/start-wiring.js +169 -0
  333. package/dist/status-payload.d.ts +13 -1
  334. package/dist/status-payload.js +13 -1
  335. package/dist/surface/http-server.js +7 -1
  336. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  337. package/dist/surface/mcp/attach-memory.js +12 -1
  338. package/dist/surface/mcp/mcp-proxy.d.ts +4 -0
  339. package/dist/surface/mcp/mcp-proxy.js +29 -8
  340. package/dist/surface/mcp/mcp.d.ts +23 -0
  341. package/dist/surface/mcp/mcp.js +34 -4
  342. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  343. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  344. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  345. package/dist/surface/mcp/server-instructions.js +22 -14
  346. package/dist/surface/mcp/shared-params.js +1 -1
  347. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  348. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  349. package/dist/surface/tools/account-tool.d.ts +22 -0
  350. package/dist/surface/tools/account-tool.js +157 -0
  351. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  352. package/dist/surface/tools/act/act-danger.js +38 -1
  353. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  354. package/dist/surface/tools/act/act-observation.js +57 -0
  355. package/dist/surface/tools/act/act-preflight.js +25 -2
  356. package/dist/surface/tools/act/act-target.js +8 -3
  357. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  358. package/dist/surface/tools/act/resolve-target.js +18 -3
  359. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  360. package/dist/surface/tools/act/screen-request.js +113 -0
  361. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  362. package/dist/surface/tools/act/sequence-grade.js +13 -2
  363. package/dist/surface/tools/act-sequence-tool.js +136 -27
  364. package/dist/surface/tools/act-tools.d.ts +0 -9
  365. package/dist/surface/tools/act-tools.js +48 -34
  366. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  367. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  368. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  369. package/dist/surface/tools/agent/app-notes.js +48 -0
  370. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  371. package/dist/surface/tools/agent/build-staleness.js +62 -0
  372. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  373. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  374. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  375. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  376. package/dist/surface/tools/agent/notices.d.ts +50 -0
  377. package/dist/surface/tools/agent/notices.js +152 -0
  378. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  379. package/dist/surface/tools/agent/reteach.js +50 -0
  380. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  381. package/dist/surface/tools/args/alias-args.js +10 -0
  382. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  383. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  384. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  385. package/dist/surface/tools/assert/assert-source.js +40 -0
  386. package/dist/surface/tools/assert/assert-verdict.js +25 -15
  387. package/dist/surface/tools/browser-tools.js +43 -1
  388. package/dist/surface/tools/chat-drives.d.ts +75 -0
  389. package/dist/surface/tools/chat-drives.js +265 -21
  390. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  391. package/dist/surface/tools/coverage-tools.js +2 -53
  392. package/dist/surface/tools/dynamic-tools.js +29 -1
  393. package/dist/surface/tools/empty-session-list.d.ts +10 -0
  394. package/dist/surface/tools/empty-session-list.js +45 -5
  395. package/dist/surface/tools/error-recovery.d.ts +8 -0
  396. package/dist/surface/tools/error-recovery.js +69 -5
  397. package/dist/surface/tools/explore-tools.d.ts +23 -2
  398. package/dist/surface/tools/explore-tools.js +377 -74
  399. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  400. package/dist/surface/tools/feedback-tools.js +4 -3
  401. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  402. package/dist/surface/tools/gap-novelty.js +8 -1
  403. package/dist/surface/tools/harness-explore.d.ts +52 -73
  404. package/dist/surface/tools/harness-explore.js +177 -146
  405. package/dist/surface/tools/harness-gate.d.ts +88 -0
  406. package/dist/surface/tools/harness-gate.js +235 -0
  407. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  408. package/dist/surface/tools/harness-hunt.js +215 -0
  409. package/dist/surface/tools/harness-plan.d.ts +5 -0
  410. package/dist/surface/tools/harness-plan.js +7 -0
  411. package/dist/surface/tools/harness-script.d.ts +22 -0
  412. package/dist/surface/tools/harness-script.js +256 -38
  413. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  414. package/dist/surface/tools/harness-tab-guard.js +27 -0
  415. package/dist/surface/tools/harness-toolset.d.ts +8 -0
  416. package/dist/surface/tools/harness-toolset.js +27 -4
  417. package/dist/surface/tools/human-notes.d.ts +16 -0
  418. package/dist/surface/tools/human-notes.js +27 -0
  419. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  420. package/dist/surface/tools/invoke-tool.js +220 -93
  421. package/dist/surface/tools/lease-hint.js +26 -5
  422. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  423. package/dist/surface/tools/lease-permissions.js +73 -0
  424. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  425. package/dist/surface/tools/lease-readiness.js +57 -0
  426. package/dist/surface/tools/lease-seed.d.ts +20 -0
  427. package/dist/surface/tools/lease-seed.js +45 -1
  428. package/dist/surface/tools/lease-tools.d.ts +10 -1
  429. package/dist/surface/tools/lease-tools.js +119 -69
  430. package/dist/surface/tools/live-call-text.js +2 -2
  431. package/dist/surface/tools/merge-tools.js +42 -2
  432. package/dist/surface/tools/merged-name-redirect.js +4 -0
  433. package/dist/surface/tools/next-step.d.ts +11 -1
  434. package/dist/surface/tools/next-step.js +73 -18
  435. package/dist/surface/tools/observe-tools.js +43 -5
  436. package/dist/surface/tools/platform-moment.d.ts +60 -0
  437. package/dist/surface/tools/platform-moment.js +132 -4
  438. package/dist/surface/tools/read-tools.js +65 -14
  439. package/dist/surface/tools/reticle-result.d.ts +120 -0
  440. package/dist/surface/tools/reticle-result.js +364 -0
  441. package/dist/surface/tools/tool-kit.d.ts +68 -2
  442. package/dist/surface/tools/tool-kit.js +73 -1
  443. package/dist/surface/tools/tools.js +25 -13
  444. package/dist/telemetry/account-envelope.d.ts +7 -0
  445. package/dist/telemetry/account-envelope.js +61 -0
  446. package/dist/telemetry/agent-client.d.ts +15 -0
  447. package/dist/telemetry/agent-client.js +57 -0
  448. package/dist/telemetry/app-instrumented.js +9 -2
  449. package/dist/telemetry/argument-shape.d.ts +7 -0
  450. package/dist/telemetry/argument-shape.js +86 -1
  451. package/dist/telemetry/automation-hint.d.ts +2 -3
  452. package/dist/telemetry/automation-hint.js +33 -8
  453. package/dist/telemetry/cli-telemetry.js +7 -2
  454. package/dist/telemetry/daemon-telemetry.js +3 -0
  455. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  456. package/dist/telemetry/error-fingerprint.js +61 -5
  457. package/dist/telemetry/feedback-cli.d.ts +0 -13
  458. package/dist/telemetry/feedback-cli.js +0 -77
  459. package/dist/telemetry/feedback.d.ts +13 -0
  460. package/dist/telemetry/feedback.js +183 -17
  461. package/dist/telemetry/harness-run.d.ts +18 -0
  462. package/dist/telemetry/harness-run.js +80 -0
  463. package/dist/telemetry/hud-events.d.ts +16 -0
  464. package/dist/telemetry/hud-events.js +27 -0
  465. package/dist/telemetry/hud-metrics.d.ts +27 -6
  466. package/dist/telemetry/hud-metrics.js +99 -25
  467. package/dist/telemetry/init-telemetry.js +2 -2
  468. package/dist/telemetry/install-source.d.ts +13 -25
  469. package/dist/telemetry/install-source.js +44 -3
  470. package/dist/telemetry/mcp-connection.d.ts +0 -14
  471. package/dist/telemetry/mcp-connection.js +5 -1
  472. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  473. package/dist/telemetry/onboarding-firsts.js +81 -6
  474. package/dist/telemetry/platform-linked.d.ts +5 -0
  475. package/dist/telemetry/platform-linked.js +32 -0
  476. package/dist/telemetry/project-profile.js +5 -3
  477. package/dist/telemetry/proxy-telemetry.js +4 -1
  478. package/dist/telemetry/session-metrics.d.ts +15 -4
  479. package/dist/telemetry/session-metrics.js +88 -52
  480. package/dist/telemetry/telemetry.d.ts +26 -2
  481. package/dist/telemetry/telemetry.js +102 -21
  482. package/dist/telemetry/verification-of.d.ts +3 -1
  483. package/dist/telemetry/verification-of.js +12 -4
  484. package/dist/wire-journal.d.ts +2 -2
  485. package/dist/wire-journal.js +16 -5
  486. package/docs/README.md +2 -2
  487. package/docs/actions.mdx +6 -3
  488. package/docs/adapters.md +1 -1
  489. package/docs/agent-cheatsheet.md +24 -27
  490. package/docs/architecture.md +5 -5
  491. package/docs/autodrive.md +13 -12
  492. package/docs/benchmarks.md +5 -5
  493. package/docs/best-practices.mdx +27 -9
  494. package/docs/capabilities.mdx +14 -16
  495. package/docs/cli/affected.mdx +1 -1
  496. package/docs/cli/cloud.mdx +54 -75
  497. package/docs/cli/doctor.mdx +8 -3
  498. package/docs/cli/drive.mdx +12 -12
  499. package/docs/cli/feedback.mdx +3 -3
  500. package/docs/cli/gate.mdx +7 -2
  501. package/docs/cli/help.mdx +50 -55
  502. package/docs/cli/init.mdx +32 -15
  503. package/docs/cli/license.mdx +12 -8
  504. package/docs/cli/mcp.mdx +4 -4
  505. package/docs/cli/open.mdx +3 -3
  506. package/docs/cli/report.mdx +4 -2
  507. package/docs/cli/restart.mdx +2 -2
  508. package/docs/cli/rollback.mdx +14 -8
  509. package/docs/cli/serve.mdx +4 -4
  510. package/docs/cli/setup.mdx +23 -0
  511. package/docs/cli/status.mdx +13 -4
  512. package/docs/cli/stop.mdx +67 -8
  513. package/docs/cli/try.mdx +62 -0
  514. package/docs/cli/update.mdx +4 -3
  515. package/docs/cli/verify.mdx +17 -6
  516. package/docs/cli/version.mdx +3 -2
  517. package/docs/cli.mdx +110 -41
  518. package/docs/debugging.md +3 -3
  519. package/docs/deploy-checks.md +1 -1
  520. package/docs/desktop.mdx +5 -3
  521. package/docs/enterprise.md +11 -10
  522. package/docs/environment.mdx +5 -2
  523. package/docs/faq.mdx +3 -3
  524. package/docs/first-drive.md +5 -4
  525. package/docs/flows.md +35 -27
  526. package/docs/for-agents.md +4 -5
  527. package/docs/frameworks.mdx +32 -21
  528. package/docs/getting-started.md +66 -64
  529. package/docs/human-control.md +15 -14
  530. package/docs/index.mdx +15 -43
  531. package/docs/install-agentic.mdx +22 -37
  532. package/docs/install-manual.mdx +22 -12
  533. package/docs/instrumentation.mdx +5 -3
  534. package/docs/integration-patterns.md +7 -7
  535. package/docs/license-activation.mdx +1 -1
  536. package/docs/multi-agent-testing.md +24 -6
  537. package/docs/packages/babel-plugin.mdx +4 -2
  538. package/docs/packages/browser.mdx +16 -10
  539. package/docs/packages/core.mdx +12 -5
  540. package/docs/packages/electron.mdx +3 -2
  541. package/docs/packages/engine.mdx +1 -1
  542. package/docs/packages/eslint-plugin.mdx +18 -12
  543. package/docs/packages/next.mdx +8 -7
  544. package/docs/packages/open-verification.mdx +1 -1
  545. package/docs/packages/server.mdx +5 -5
  546. package/docs/packages/tauri.mdx +8 -8
  547. package/docs/packages/test.mdx +4 -10
  548. package/docs/packages/vite-plugin.mdx +11 -4
  549. package/docs/packages.mdx +11 -15
  550. package/docs/platform-integration.md +6 -5
  551. package/docs/predicates.mdx +40 -24
  552. package/docs/quickstart.mdx +58 -29
  553. package/docs/required-checks.md +8 -7
  554. package/docs/reticle-manual.md +15 -5
  555. package/docs/skill-file.mdx +17 -79
  556. package/docs/skill-setup.md +9 -9
  557. package/docs/skill.md +200 -0
  558. package/docs/system-map.md +7 -7
  559. package/docs/telemetry.md +22 -24
  560. package/docs/testing.md +4 -4
  561. package/docs/token-efficiency.md +12 -12
  562. package/docs/tools/act-and-wait.mdx +9 -2
  563. package/docs/tools/act-sequence.mdx +6 -7
  564. package/docs/tools/act.mdx +2 -2
  565. package/docs/tools/assert.mdx +18 -17
  566. package/docs/tools/console.mdx +9 -9
  567. package/docs/tools/inspect.mdx +16 -7
  568. package/docs/tools/look.mdx +24 -0
  569. package/docs/tools/navigate.mdx +5 -3
  570. package/docs/tools/network.mdx +2 -2
  571. package/docs/tools/observe.mdx +6 -6
  572. package/docs/tools/overview.mdx +34 -33
  573. package/docs/tools/query.mdx +5 -5
  574. package/docs/tools/session-and-feedback.mdx +13 -4
  575. package/docs/tools/sessions.mdx +8 -8
  576. package/docs/tools/snapshot.mdx +6 -5
  577. package/docs/tools/state.mdx +9 -9
  578. package/docs/tools/tools-and-run.mdx +26 -24
  579. package/docs/tools/verify.mdx +28 -0
  580. package/docs/tools/wait-for.mdx +8 -4
  581. package/docs/troubleshooting.mdx +21 -6
  582. package/docs/usage.md +51 -45
  583. package/docs/use-cases.mdx +3 -3
  584. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  585. package/docs/vs-playwright-mcp.mdx +3 -1
  586. package/docs/what-is-recorded.md +7 -5
  587. package/docs/what-is-reticle.mdx +2 -2
  588. package/docs/why-reticle.mdx +1 -1
  589. package/package.json +6 -5
  590. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  591. package/dist/command/cli/demo/demo-page.js +0 -249
  592. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  593. package/dist/command/cli/demo/demo-run.js +0 -138
  594. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  595. package/dist/judgement/hunt/hunt-report.js +0 -84
  596. package/dist/language/flows/buddy-status.d.ts +0 -25
  597. package/dist/language/flows/buddy-status.js +0 -32
  598. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  599. package/dist/language/flows/change/watch-batcher.js +0 -19
  600. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  601. package/dist/memory/cloud/harness-offer.js +0 -145
  602. package/dist/surface/tools/feature-capture.d.ts +0 -151
  603. package/dist/surface/tools/feature-capture.js +0 -235
  604. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  605. package/dist/surface/tools/tool-hit-rate.js +0 -90
  606. package/dist/telemetry/harness-drive.d.ts +0 -4
  607. package/dist/telemetry/harness-drive.js +0 -35
  608. package/dist/telemetry/identify.d.ts +0 -22
  609. package/dist/telemetry/identify.js +0 -73
  610. package/docs/cli/capsules.mdx +0 -70
  611. package/docs/cli/hunt.mdx +0 -73
  612. package/docs/cli/identify.mdx +0 -76
  613. package/docs/cli/kill.mdx +0 -91
  614. package/docs/cli/watch.mdx +0 -62
@@ -40,8 +40,13 @@ const VARIABLE_PARTS = [
40
40
  // ── Then the grouping rules ──────────────────────────────────────────────────────────────────
41
41
  /"[^"]*"|'[^']*'|`[^`]*`/g, // quoted values — names, selectors, snippets
42
42
  /\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, // URLs
43
+ // Windows paths run to the end of the message: a directory name may hold a space, and
44
+ // `C:\Users\Jane Doe\…` cut at the first space sent the surname.
45
+ /(?:\\\\\?\\)?[A-Za-z]:[\\/].*$/g,
46
+ /~[\\/]\S*/g, // home-relative paths
43
47
  /(?:\/[\w.-]+){2,}\/?/g, // POSIX-ish paths
44
- /[A-Za-z]:\\[^\s]*/g, // Windows paths
48
+ /\b\d{1,3}(?:\.\d{1,3}){3}(?::\d+)?\b/g, // IPv4 (+ port)
49
+ /\b[\w-]+(?:\.[\w-]+)+\b/g, // hostnames and other dotted names
45
50
  /\b[0-9a-f]{8,}\b/gi, // hex ids, hashes, uuids-without-dashes
46
51
  /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, // uuids
47
52
  /\d+/g, // any remaining number — ports, counts, timeouts
@@ -71,16 +76,67 @@ const VARIABLE_PARTS = [
71
76
  * for a reason unrelated to this one.
72
77
  */
73
78
  const MAX_SKELETON_INPUT = 1024;
74
- /** The skeleton of a message: variable parts blanked, whitespace collapsed, length bounded. */
75
- export function errorSkeleton(message) {
79
+ /** Variable parts blanked, whitespace collapsed, length bounded. The GROUPING basis; never sent. */
80
+ function redactedShape(message) {
76
81
  let skeleton = message.slice(0, MAX_SKELETON_INPUT);
77
82
  for (const pattern of VARIABLE_PARTS)
78
83
  skeleton = skeleton.replace(pattern, '*');
79
84
  return skeleton.replace(/\s+/g, ' ').trim().slice(0, 200);
80
85
  }
86
+ /**
87
+ * Sentences Reticle itself authors, and the fixed text sent for each. The OUTPUT is always the
88
+ * label, never the matched message, so text appended to one of ours cannot ride along.
89
+ */
90
+ const RETICLE_MESSAGES = [
91
+ { match: /^no browser session connected\b/i, label: 'no browser session connected' },
92
+ { match: /^multiple sessions connected\b/i, label: 'multiple sessions connected' },
93
+ { match: /^no connected session with id\b/i, label: 'no connected session with id *' },
94
+ { match: /^no baseline named\b/i, label: 'no baseline named *' },
95
+ { match: /^no (?:active|compiled) recording named\b/i, label: 'no recording named *' },
96
+ { match: /no longer resolves to an element/i, label: 'ref * no longer resolves to an element' },
97
+ { match: /^session disconnected$/i, label: 'session disconnected' },
98
+ { match: /^command '[^']*' timed out after\b/i, label: 'command * timed out after *' },
99
+ {
100
+ match: /did not resolve in current page/i,
101
+ label: 'flow step * did not resolve in current page',
102
+ },
103
+ {
104
+ match: /potentially destructive (?:\w+ )*(?:action|tool) blocked/i,
105
+ label: 'potentially destructive action blocked',
106
+ },
107
+ { match: /^pairing token is required\b/i, label: 'pairing token is required' },
108
+ { match: /no <option> with value/i, label: 'no <option> with value *' },
109
+ { match: /cannot hover without a real pointer/i, label: 'cannot hover without a real pointer' },
110
+ { match: /browser pool (?:unavailable|is shut down)/i, label: 'browser pool unavailable' },
111
+ { match: /Chromium is not installed/i, label: 'Chromium is not installed' },
112
+ { match: /^act failed$/i, label: 'act failed' },
113
+ ];
114
+ /** A Node error code (`ENOENT`, `ERR_INVALID_ARG_TYPE`): an identifier Node defines, never data. */
115
+ const NODE_ERROR_CODE = /\b(?:E[A-Z]{2,}|ERR_[A-Z_]{2,})\b/;
116
+ /** The built-in error classes. A custom class name is the app's own word, so it is not kept. */
117
+ const BUILTIN_ERROR_CLASS = /^(?:Error|TypeError|RangeError|SyntaxError|ReferenceError|EvalError|URIError|AggregateError|AbortError|TimeoutError|DOMException|ZodError)\b/;
118
+ /**
119
+ * What an error message may say on the wire, and it is ALLOW-listed: a sentence Reticle authors
120
+ * (sent as our own fixed label), else the bare Node error code or built-in class plus the
121
+ * fingerprint, else the fingerprint alone.
122
+ *
123
+ * It used to be the message with known-variable parts blanked, which is a deny-list, and a
124
+ * deny-list loses: a hostname after `getaddrinfo ENOTFOUND`, a Windows home directory with a space
125
+ * in it, a `~` path and a person's name in free text all reached the wire. Nothing written by
126
+ * anybody else survives this function, because it never echoes its input.
127
+ */
128
+ export function errorSkeleton(message) {
129
+ const head = message.slice(0, MAX_SKELETON_INPUT).trim();
130
+ for (const { match, label } of RETICLE_MESSAGES)
131
+ if (match.test(head))
132
+ return label;
133
+ const fingerprint = `#${fingerprintError(message)}`;
134
+ const code = BUILTIN_ERROR_CLASS.exec(head)?.[0] ?? NODE_ERROR_CODE.exec(head)?.[0];
135
+ return code === undefined ? fingerprint : `${code} ${fingerprint}`;
136
+ }
81
137
  /** A stable, opaque group key for an error message. Same defect ⇒ same key, on every machine. */
82
138
  export function fingerprintError(message) {
83
- return createHash('sha256').update(errorSkeleton(message)).digest('hex').slice(0, 12);
139
+ return createHash('sha256').update(redactedShape(message)).digest('hex').slice(0, 12);
84
140
  }
85
141
  /**
86
142
  * Frames from a stack trace that belong to RETICLE, reduced to `basename:line`.
@@ -121,7 +177,7 @@ export function fingerprintCrash(errorType, stack, message) {
121
177
  const frames = reticleFrames(stack);
122
178
  const basis = frames.length > 0
123
179
  ? `${errorType}|${frames.join('|')}`
124
- : `${errorType}|${errorSkeleton(message)}`;
180
+ : `${errorType}|${redactedShape(message)}`;
125
181
  return createHash('sha256').update(basis).digest('hex').slice(0, 12);
126
182
  }
127
183
  /** The error's constructor name (`TypeError`), or `Unknown` for a thrown non-Error. */
@@ -15,19 +15,6 @@ import { TelemetryAction } from '../command/cli/cli-parse.js';
15
15
  * show you the payload is asking for trust it has not earned.
16
16
  */
17
17
  export declare function handleFeedback(text: string, rating: number | undefined, bug: boolean, feedbackKind?: string, agent?: boolean): Promise<void>;
18
- /**
19
- * `reticle identify` — opt-in, and it shows the consent notice before it sends anything.
20
- *
21
- * Deliberately NOT interactive: a prompt that appears in the middle of someone's work is pressure,
22
- * and this is the one command where the user must be choosing freely. They type what they want to
23
- * share, or they never run it at all.
24
- */
25
- export declare function handleIdentify(parsed: {
26
- context?: string;
27
- company?: string;
28
- email?: string;
29
- forget: boolean;
30
- }): Promise<void>;
31
18
  /**
32
19
  * `reticle telemetry [status|enable|disable]` — the user-facing control for anonymous usage metrics.
33
20
  * `disable` persists a machine-wide opt-out (survives shells, unlike RETICLE_TELEMETRY=0); `status`
@@ -3,7 +3,6 @@ import { AGENT_FLAG, BUG_FLAG, FEEDBACK_KINDS, KIND_FLAG, RATING_FLAG, } from '.
3
3
  import { describeFeedbackPayload, submitFeedback } from './feedback.js';
4
4
  import { describeTelemetry, setTelemetryEnabled } from './telemetry.js';
5
5
  import { TelemetryAction } from '../command/cli/cli-parse.js';
6
- import { clearIdentity, IDENTIFY_NOTICE, readIdentity, saveIdentity, submitIdentity, UsageContextKind, } from './identify.js';
7
6
  /**
8
7
  * `reticle feedback [--rating 1-5] [--bug] "what happened"` — the feedback channel as a command.
9
8
  *
@@ -49,82 +48,6 @@ export async function handleFeedback(text, rating, bug, feedbackKind, agent = fa
49
48
  line(receipt.sent
50
49
  ? 'thanks your feedback is in. it genuinely changes what gets built next.'
51
50
  : `not sent ${receipt.reason ?? 'unknown reason'}`);
52
- for (const extra of identifyInvite(agent))
53
- line(extra);
54
- }
55
- /**
56
- * Offer a HUMAN a way to be replied to — printed after the receipt, never as a prompt.
57
- *
58
- * Feedback is anonymous by design and stays that way: the report has already been sent by the time
59
- * this prints, so nothing here gates or delays it. This is an offer, not a question.
60
- *
61
- * It routes through `reticle identify`, which already does consented identity properly — it prints
62
- * what it will send, states that identifying links this machine's prior anonymous history to that
63
- * identity, and has `--forget`. Capturing an address inline on `feedback_submitted` instead would
64
- * put PII on the anonymous event stream and break what `docs/telemetry.md` promises in public:
65
- * "no domain sniffing, no email inference" and "no personal data is collected".
66
- *
67
- * Only for humans (an agent has no email), and only when nobody has identified yet — so somebody
68
- * who declined is never asked twice.
69
- */
70
- function identifyInvite(agent) {
71
- if (agent)
72
- return [];
73
- try {
74
- if (readIdentity() !== undefined)
75
- return [];
76
- }
77
- catch {
78
- return []; // unreadable identity file: say nothing rather than risk asking twice
79
- }
80
- return [
81
- '',
82
- 'want a reply? `reticle identify --context <company|side_project|oss|learning> --email you@example.com`',
83
- ' optional, and it tells you exactly what it sends before sending it.',
84
- ];
85
- }
86
- /**
87
- * `reticle identify` — opt-in, and it shows the consent notice before it sends anything.
88
- *
89
- * Deliberately NOT interactive: a prompt that appears in the middle of someone's work is pressure,
90
- * and this is the one command where the user must be choosing freely. They type what they want to
91
- * share, or they never run it at all.
92
- */
93
- export async function handleIdentify(parsed) {
94
- const line = (s) => {
95
- process.stdout.write(`${s}\n`);
96
- };
97
- if (parsed.forget) {
98
- clearIdentity();
99
- line('forgotten the local identity file is deleted; nothing further is sent.');
100
- line(' to have what was already sent removed, email support@reticlehq.com');
101
- return;
102
- }
103
- const context = Object.values(UsageContextKind).find((k) => k === parsed.context);
104
- if (context === undefined) {
105
- const existing = readIdentity();
106
- if (existing !== undefined)
107
- line(`current ${JSON.stringify(existing)}`);
108
- line(`usage: reticle identify --context <${Object.values(UsageContextKind).join('|')}>`);
109
- line(' [--company "Acme"] [--email you@acme.com] [--forget]');
110
- line('');
111
- line(IDENTIFY_NOTICE);
112
- process.exitCode = existing === undefined ? 1 : 0;
113
- return;
114
- }
115
- const identity = {
116
- context,
117
- ...(parsed.company !== undefined ? { company: parsed.company } : {}),
118
- ...(parsed.email !== undefined ? { email: parsed.email } : {}),
119
- };
120
- line(IDENTIFY_NOTICE);
121
- line('');
122
- line(`sending ${JSON.stringify(identity)}`);
123
- saveIdentity(identity);
124
- const sent = await submitIdentity(identity);
125
- line(sent
126
- ? 'thanks saved and sent. we may reach out; `reticle identify --forget` undoes this.'
127
- : 'not sent telemetry is disabled on this machine, so it was saved locally only.');
128
51
  }
129
52
  /**
130
53
  * `reticle telemetry [status|enable|disable]` — the user-facing control for anonymous usage metrics.
@@ -22,6 +22,7 @@
22
22
  * disables it too, since it rides the same emitter.
23
23
  */
24
24
  import { type Feedback } from '@reticlehq/core/telemetry';
25
+ import { type Telemetry } from './telemetry.js';
25
26
  import { type SessionFacts } from './feedback-context.js';
26
27
  /** Kills the feedback channel ONLY — adoption counters keep flowing. */
27
28
  export declare const FEEDBACK_ENV = "RETICLE_FEEDBACK";
@@ -34,6 +35,12 @@ interface Redaction {
34
35
  }
35
36
  /** Strip credential/PII shapes and cap the length. Pure — the tests read like a spec of what leaks. */
36
37
  export declare function redactFeedbackText(input: string, max: number): Redaction;
38
+ /**
39
+ * A trace reduced to Reticle's own words, in order: which tools were called and what verdict each
40
+ * gave. The raw trace is the call/response trail, and the responses carry the page's text and what
41
+ * was typed into it, which no redaction rule can tell from prose. So nothing else is kept.
42
+ */
43
+ export declare function summarizeTrace(trace: string): string;
37
44
  /** True when the feedback channel is switched off on its own (the emitter's switches apply as well). */
38
45
  export declare function feedbackDisabled(env?: NodeJS.ProcessEnv): boolean;
39
46
  /** What the author supplies; the environment context is detected, never asked for. */
@@ -89,6 +96,12 @@ export declare function submitFeedback(input: FeedbackInput, opts?: {
89
96
  */
90
97
  background?: boolean;
91
98
  }): Promise<FeedbackReceipt>;
99
+ /**
100
+ * Retry what the outbox holds: the receipt for an undelivered report promises "It will be retried",
101
+ * and until this ran on daemon start nothing ever read the outbox back. Bounded, sequential, and
102
+ * best-effort; a report the endpoint does not accept stays queued. Returns how many were delivered.
103
+ */
104
+ export declare function drainFeedbackOutbox(telemetry?: Telemetry, home?: string): Promise<number>;
92
105
  /**
93
106
  * The receipt's context PLUS the fields the emitter stamps on every event regardless of kind — the
94
107
  * reticle version, the OS, and whether this is CI. They are the single most-asked question of any bug
@@ -22,18 +22,77 @@
22
22
  * disables it too, since it rides the same emitter.
23
23
  */
24
24
  import { FeedbackSchema, FEEDBACK_TEXT_MAX, FEEDBACK_TRACE_MAX, FEEDBACK_FIELD_MAX, TelemetryEventKind, } from '@reticlehq/core/telemetry';
25
- import { platform } from 'node:os';
25
+ import { homedir, platform } from 'node:os';
26
26
  import { getTelemetry } from './telemetry.js';
27
27
  import { noteFeedbackUndelivered } from './feedback-delivery.js';
28
28
  import { isReticleSourceCheckout } from './dev-repo.js';
29
29
  import { saveFeedbackLocally } from './feedback-local.js';
30
30
  import { SERVER_VERSION } from '../command/version/identity/server-version.js';
31
31
  import { feedbackContext } from './feedback-context.js';
32
- import { markDelivered, outboxPath, queueFeedback } from './feedback-outbox.js';
32
+ import { markDelivered, outboxPath, queueFeedback, readOutbox } from './feedback-outbox.js';
33
33
  /** Kills the feedback channel ONLY — adoption counters keep flowing. */
34
34
  export const FEEDBACK_ENV = 'RETICLE_FEEDBACK';
35
35
  /** What replaces a redacted match. Visible on purpose: a reader must see that something was removed. */
36
36
  export const REDACTED = '[redacted]';
37
+ /** This machine, as a host: the app under test, never anybody's infrastructure. Port allowed. */
38
+ const LOCAL_HOST = /^(?:localhost|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|0\.0\.0\.0|\[::1\])(?::\d+)?$/i;
39
+ /** A dotted name ending in one of these is a source file, not a host. */
40
+ const FILE_EXTENSIONS = new Set([
41
+ 'ts',
42
+ 'tsx',
43
+ 'mts',
44
+ 'cts',
45
+ 'js',
46
+ 'jsx',
47
+ 'mjs',
48
+ 'cjs',
49
+ 'json',
50
+ 'md',
51
+ 'mdx',
52
+ 'css',
53
+ 'scss',
54
+ 'html',
55
+ 'vue',
56
+ 'svelte',
57
+ 'astro',
58
+ 'py',
59
+ 'rs',
60
+ 'go',
61
+ 'yml',
62
+ 'yaml',
63
+ 'toml',
64
+ 'lock',
65
+ 'log',
66
+ 'txt',
67
+ 'map',
68
+ 'sh',
69
+ 'env',
70
+ 'd',
71
+ ]);
72
+ /** Top-level domains common enough that a one-dot name ending in one is a host. */
73
+ const COMMON_TLDS = new Set([
74
+ 'com',
75
+ 'net',
76
+ 'org',
77
+ 'io',
78
+ 'dev',
79
+ 'app',
80
+ 'co',
81
+ 'ai',
82
+ 'cloud',
83
+ 'internal',
84
+ 'local',
85
+ 'corp',
86
+ 'lan',
87
+ 'site',
88
+ 'tech',
89
+ 'xyz',
90
+ 'us',
91
+ 'uk',
92
+ 'de',
93
+ 'in',
94
+ 'eu',
95
+ ]);
37
96
  /**
38
97
  * The shapes that leak. Ordered most-specific first — a URL carrying inline credentials must be
39
98
  * caught as a URL before the bare-token rule chews the middle out of it.
@@ -45,6 +104,15 @@ export const REDACTED = '[redacted]';
45
104
  const REDACTIONS = [
46
105
  // scheme://user:pass@host — the credential is in the authority section.
47
106
  { pattern: /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+:[^\s/@]+@/gi, label: 'url-credentials' },
107
+ // A URL keeps its scheme, and its host and path ONLY when the host is this machine (the app under
108
+ // test, which is what a report is about). Any other host is a staging site, a customer's domain
109
+ // or an internal service, so it goes with its path. The query and fragment always go: that is
110
+ // where ids, emails and tokens ride.
111
+ {
112
+ pattern: /\b([a-z][a-z0-9+.-]*:\/\/)([^\s/?#"'<>`]+)([^\s?#"'<>`]*)(?:[?#][^\s"'<>`]*)?/gi,
113
+ label: 'url',
114
+ replace: (_m, scheme = '', host = '', path = '') => LOCAL_HOST.test(host) ? `${scheme}${host}${path}` : `${scheme}${REDACTED}`,
115
+ },
48
116
  { pattern: /\b[\w.%+-]+@[\w.-]+\.[a-z]{2,}\b/gi, label: 'email' },
49
117
  // Credential assignments: the KEY stays (it is the useful part), the VALUE goes. The auth SCHEME
50
118
  // (`Bearer`, `Basic`, `Token`) is consumed as part of the value, not left as the value — matching
@@ -59,24 +127,72 @@ const REDACTIONS = [
59
127
  { pattern: /\bAKIA[0-9A-Z]{16}\b/g, label: 'aws-key' },
60
128
  { pattern: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, label: 'slack-token' },
61
129
  { pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g, label: 'jwt' },
62
- // Home directories carry the account name, and a trace is full of them.
63
- { pattern: /(?:\/Users\/|\/home\/|[A-Z]:\\Users\\)[^\s/\\:"']+/g, label: 'home-path' },
130
+ // Home directories carry the account name, and a trace is full of them. The name runs to the next
131
+ // separator, quote or line end, NOT the next space: `C:\Users\Jane Doe\…` stopped at the space and
132
+ // sent the surname. Then the rest of the path goes with it. Over-redacting a sentence that follows
133
+ // a bare home directory is the price, and it is the right way round.
134
+ {
135
+ pattern: /(?:\\\\\?\\)?(?:\/Users\/|\/home\/|[A-Za-z]:[\\/]Users[\\/])[^\\/\r\n"'`]+(?:[\\/][^\s\\/"'`]*)*/g,
136
+ label: 'home-path',
137
+ },
138
+ // Any other absolute path: a Windows one (segments may hold spaces when a separator follows)...
139
+ {
140
+ pattern: /(?:\\\\\?\\)?\b[A-Za-z]:[\\/](?:[^\\/\r\n"'`<>|*?]+[\\/])*[^\s\\/"'`<>|*?]*/g,
141
+ label: 'path',
142
+ },
143
+ // ...a home-relative one, and a POSIX one of two or more segments. A path is a directory layout,
144
+ // and a directory layout names clients, projects and people.
145
+ { pattern: /~[\\/][^\s"'`]*/g, label: 'path' },
146
+ { pattern: /(?<![\w.~])\/[\w.@+-]+(?:\/[\w.@+-]+)+\/?/g, label: 'path' },
147
+ {
148
+ pattern: /\b\d{1,3}(?:\.\d{1,3}){3}\b/g,
149
+ label: 'ip',
150
+ replace: (ip) => (LOCAL_HOST.test(ip) ? ip : REDACTED),
151
+ },
152
+ // Hostnames: a staging site, an internal service, a customer's domain. A dotted name is a host when
153
+ // it has two or more dots or ends in a common top-level domain, and never when it ends in a source
154
+ // file's extension — `vite.config.ts` is what a report is about, `db.internal.acme.com` is not.
155
+ {
156
+ pattern: /\b(?:[a-z0-9-]+\.)+[a-z][a-z0-9-]*\b/gi,
157
+ label: 'hostname',
158
+ replace: (name) => {
159
+ const labels = name.toLowerCase().split('.');
160
+ const last = labels[labels.length - 1] ?? '';
161
+ if (FILE_EXTENSIONS.has(last))
162
+ return name;
163
+ return labels.length > 2 || COMMON_TLDS.has(last) ? REDACTED : name;
164
+ },
165
+ },
64
166
  ];
65
167
  /** Strip credential/PII shapes and cap the length. Pure — the tests read like a spec of what leaks. */
66
168
  export function redactFeedbackText(input, max) {
67
169
  const removed = new Set();
68
170
  let text = input;
69
- for (const { pattern, label } of REDACTIONS) {
70
- text = text.replace(pattern, (_match, ...groups) => {
71
- removed.add(label);
171
+ for (const { pattern, label, replace } of REDACTIONS) {
172
+ text = text.replace(pattern, (match, ...groups) => {
173
+ const captures = groups.map((g) => ('string' === typeof g ? g : ''));
72
174
  // A rule with a leading capture keeps it (the scheme, the `api_key=` key) so the reader still
73
175
  // sees WHAT was removed, not just that something was.
74
- const prefix = 'string' === typeof groups[0] ? groups[0] : '';
75
- return `${prefix}${REDACTED}`;
176
+ const out = replace === undefined ? `${captures[0] ?? ''}${REDACTED}` : replace(match, ...captures);
177
+ if (out !== match)
178
+ removed.add(label);
179
+ return out;
76
180
  });
77
181
  }
78
182
  return { text: text.slice(0, max), removed: [...removed] };
79
183
  }
184
+ /** Our words in a trace: tool names and the verdict vocabulary. Nothing else is kept. */
185
+ const TRACE_WORDS = /\breticle_[a-z_]+\b|\b(?:verified|yes|no|unknown|no-fault|ok|passed|failed|refused|error|timeout)\b/gi;
186
+ /**
187
+ * A trace reduced to Reticle's own words, in order: which tools were called and what verdict each
188
+ * gave. The raw trace is the call/response trail, and the responses carry the page's text and what
189
+ * was typed into it, which no redaction rule can tell from prose. So nothing else is kept.
190
+ */
191
+ export function summarizeTrace(trace) {
192
+ return (trace.match(TRACE_WORDS) ?? []).join(' ').slice(0, FEEDBACK_TRACE_MAX);
193
+ }
194
+ /** The removal label when a trace lost anything to `summarizeTrace`. */
195
+ const TRACE_VALUES_LABEL = 'trace-values';
80
196
  /** True when the feedback channel is switched off on its own (the emitter's switches apply as well). */
81
197
  export function feedbackDisabled(env = process.env) {
82
198
  const value = (env[FEEDBACK_ENV] ?? '').toLowerCase();
@@ -98,6 +214,7 @@ const AUTHOR_WRITTEN_FIELDS = new Set([
98
214
  'currentApproach',
99
215
  'model',
100
216
  ]);
217
+ const TRACE_FIELD = 'trace';
101
218
  /** Per-field caps; anything unlisted uses the standard field cap. */
102
219
  const FIELD_CAPS = {
103
220
  text: FEEDBACK_TEXT_MAX,
@@ -120,14 +237,7 @@ export async function submitFeedback(input, opts = {}) {
120
237
  // sk-…" would have shipped the token. Enumerating the fields to protect is the same class of
121
238
  // mistake as hand-copying an enum: correct on the day it is written, quietly wrong at the next
122
239
  // addition. Deriving the set means a sixth field is covered the moment it exists.
123
- const redactions = new Map();
124
- for (const [key, value] of Object.entries(input)) {
125
- if (typeof value !== 'string' || '' === value)
126
- continue;
127
- if (!AUTHOR_WRITTEN_FIELDS.has(key))
128
- continue;
129
- redactions.set(key, redactFeedbackText(value, FIELD_CAPS[key] ?? FEEDBACK_FIELD_MAX));
130
- }
240
+ const redactions = redactAuthorFields(input);
131
241
  const body = redactions.get('text') ?? { text: '', removed: [] };
132
242
  const redacted = [...new Set([...redactions.values()].flatMap((r) => r.removed))];
133
243
  if (feedbackDisabled(env)) {
@@ -231,6 +341,62 @@ export async function submitFeedback(input, opts = {}) {
231
341
  context,
232
342
  };
233
343
  }
344
+ /**
345
+ * Every author-written field of a report, redacted under the CURRENT rules. One function for the
346
+ * send and for the outbox drain, so a report queued under older, weaker rules is re-redacted before
347
+ * it finally goes.
348
+ */
349
+ function redactAuthorFields(input) {
350
+ const redactions = new Map();
351
+ for (const [key, value] of Object.entries(input)) {
352
+ if (typeof value !== 'string' || '' === value)
353
+ continue;
354
+ if (!AUTHOR_WRITTEN_FIELDS.has(key))
355
+ continue;
356
+ if (TRACE_FIELD === key) {
357
+ const summary = summarizeTrace(value);
358
+ redactions.set(key, {
359
+ text: summary,
360
+ removed: summary === value ? [] : [TRACE_VALUES_LABEL],
361
+ });
362
+ continue;
363
+ }
364
+ redactions.set(key, redactFeedbackText(value, FIELD_CAPS[key] ?? FEEDBACK_FIELD_MAX));
365
+ }
366
+ return redactions;
367
+ }
368
+ /** Reports one daemon start retries. A backlog drains over several starts, never in one burst. */
369
+ const OUTBOX_DRAIN_MAX = 5;
370
+ /**
371
+ * Retry what the outbox holds: the receipt for an undelivered report promises "It will be retried",
372
+ * and until this ran on daemon start nothing ever read the outbox back. Bounded, sequential, and
373
+ * best-effort; a report the endpoint does not accept stays queued. Returns how many were delivered.
374
+ */
375
+ export async function drainFeedbackOutbox(telemetry = getTelemetry(), home = homedir()) {
376
+ if (!telemetry.enabled || feedbackDisabled())
377
+ return 0;
378
+ let delivered = 0;
379
+ for (const entry of readOutbox(home).slice(0, OUTBOX_DRAIN_MAX)) {
380
+ const queued = FeedbackSchema.safeParse(entry.payload);
381
+ // A payload that cannot pass the schema can never be sent; it stays where a person can read it.
382
+ if (!queued.success)
383
+ continue;
384
+ const fields = Object.fromEntries([...redactAuthorFields(queued.data)].map(([key, r]) => [key, r.text]));
385
+ const parsed = FeedbackSchema.safeParse({ ...queued.data, ...fields });
386
+ if (!parsed.success)
387
+ continue;
388
+ try {
389
+ if (await telemetry.emit(TelemetryEventKind.FEEDBACK_SUBMITTED, { feedback: parsed.data })) {
390
+ markDelivered(entry.id, home);
391
+ delivered += 1;
392
+ }
393
+ }
394
+ catch {
395
+ /* stays queued for the next start */
396
+ }
397
+ }
398
+ return delivered;
399
+ }
234
400
  /**
235
401
  * The receipt's context PLUS the fields the emitter stamps on every event regardless of kind — the
236
402
  * reticle version, the OS, and whether this is CI. They are the single most-asked question of any bug
@@ -0,0 +1,18 @@
1
+ import { HarnessRunSource, type HarnessRun } from '@reticlehq/core/telemetry';
2
+ import { DriveOrigin, DriveStatus } from '../features/harness/drive-runs.js';
3
+ import { type Telemetry } from './telemetry.js';
4
+ export interface HarnessRunStart {
5
+ source: HarnessRunSource;
6
+ hosted: boolean;
7
+ }
8
+ /** Who started it. A saved plan is a plan whoever pressed Run. */
9
+ export declare function harnessRunSource(origin: DriveOrigin, planId: string | undefined): HarnessRunSource;
10
+ /** How a finished run ended, from what the registry recorded. */
11
+ export declare function harnessRunEnd(status: DriveStatus, result: Record<string, unknown> | undefined): Pick<HarnessRun, 'outcome' | 'journeys' | 'replayed'>;
12
+ /** Report the run's start, run it, report its end, and hand back exactly what it did. */
13
+ export declare function reportHarnessRun<T extends {
14
+ status: DriveStatus;
15
+ result: Record<string, unknown>;
16
+ }>(start: HarnessRunStart, run: () => Promise<T>, refused: (error: unknown) => boolean, telemetry?: Pick<Telemetry, 'emit'>): Promise<T>;
17
+ /** A run the gate refused before it could start: still somebody who asked for one. */
18
+ export declare function reportHarnessBlocked(start: HarnessRunStart, telemetry?: Pick<Telemetry, 'emit'>): void;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * `harness_run`: the Harness funnel. One `started` and one `completed` per run, whoever started it.
3
+ *
4
+ * Emitted around the drive itself (`startDrive`'s run), not read off the tool answer: a drive started
5
+ * from the HUD is never polled by an agent, and a drive whose daemon is asked again later answers
6
+ * from disk, so only the run's own start and end see every run exactly once.
7
+ *
8
+ * A drive the gate refuses before it starts is still a run somebody asked for, and reports as a
9
+ * `started` + `completed: blocked` pair, so the funnel's denominator is everyone who pressed Run.
10
+ */
11
+ import { asRecord } from '@reticlehq/core';
12
+ import { JourneyBy } from '@reticlehq/core/artifacts';
13
+ import { HarnessRunOutcome, HarnessRunPhase, HarnessRunSource, TelemetryEventKind, countBucket, } from '@reticlehq/core/telemetry';
14
+ import { DriveOrigin, DriveStatus } from '../features/harness/drive-runs.js';
15
+ import { getTelemetry } from './telemetry.js';
16
+ const SOURCE_OF = {
17
+ [DriveOrigin.AGENT]: HarnessRunSource.AGENT,
18
+ [DriveOrigin.HUD]: HarnessRunSource.HUD,
19
+ [DriveOrigin.CHAT]: HarnessRunSource.DASHBOARD,
20
+ [DriveOrigin.TRY]: HarnessRunSource.CLI_TRY,
21
+ };
22
+ /** Who started it. A saved plan is a plan whoever pressed Run. */
23
+ export function harnessRunSource(origin, planId) {
24
+ return planId === undefined ? SOURCE_OF[origin] : HarnessRunSource.PLAN;
25
+ }
26
+ /** How a finished run ended, from what the registry recorded. */
27
+ export function harnessRunEnd(status, result) {
28
+ const journeys = Array.isArray(result?.['journeys']) ? result['journeys'] : undefined;
29
+ const replayed = (journeys ?? []).filter((j) => JourneyBy.REPLAY === asRecord(j)['by']).length;
30
+ const outcome = DriveStatus.REFUSED === status
31
+ ? HarnessRunOutcome.BLOCKED
32
+ : DriveStatus.BROKEN === status
33
+ ? HarnessRunOutcome.FAILED
34
+ : DriveStatus.STOPPED === status
35
+ ? HarnessRunOutcome.STOPPED
36
+ : true === result?.['proved']
37
+ ? HarnessRunOutcome.PROVED
38
+ : HarnessRunOutcome.NOT_PROVED;
39
+ // An unplanned drive is one journey; a refused one drove none.
40
+ const count = journeys?.length ?? (HarnessRunOutcome.BLOCKED === outcome ? 0 : 1);
41
+ return { outcome, journeys: countBucket(count), replayed: countBucket(replayed) };
42
+ }
43
+ function emit(telemetry, harness) {
44
+ try {
45
+ void telemetry.emit(TelemetryEventKind.HARNESS_RUN, { harness });
46
+ }
47
+ catch {
48
+ /* a metric may never change a drive */
49
+ }
50
+ }
51
+ /** Report the run's start, run it, report its end, and hand back exactly what it did. */
52
+ export async function reportHarnessRun(start, run, refused, telemetry = getTelemetry()) {
53
+ emit(telemetry, { phase: HarnessRunPhase.STARTED, ...start });
54
+ try {
55
+ const done = await run();
56
+ emit(telemetry, {
57
+ phase: HarnessRunPhase.COMPLETED,
58
+ ...start,
59
+ ...harnessRunEnd(done.status, done.result),
60
+ });
61
+ return done;
62
+ }
63
+ catch (error) {
64
+ emit(telemetry, {
65
+ phase: HarnessRunPhase.COMPLETED,
66
+ ...start,
67
+ ...harnessRunEnd(refused(error) ? DriveStatus.REFUSED : DriveStatus.BROKEN, undefined),
68
+ });
69
+ throw error;
70
+ }
71
+ }
72
+ /** A run the gate refused before it could start: still somebody who asked for one. */
73
+ export function reportHarnessBlocked(start, telemetry = getTelemetry()) {
74
+ emit(telemetry, { phase: HarnessRunPhase.STARTED, ...start });
75
+ emit(telemetry, {
76
+ phase: HarnessRunPhase.COMPLETED,
77
+ ...start,
78
+ ...harnessRunEnd(DriveStatus.REFUSED, undefined),
79
+ });
80
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The HUD's own events: `hud_viewed` when a page is opened, `hud_signin_prompted` when a sign-in or
3
+ * link ask is shown. The windowed summary (`hudPanelMs`, `hudJourney`) says how long and in what
4
+ * order; these say how often and by whom, which a window summed across a session cannot.
5
+ *
6
+ * Sent by the daemon, like every HUD measure, so every opt-out applies, and only from the names the
7
+ * wire schema already narrowed. The dedupe (per tab, per page or surface) lives in `HudMetrics`.
8
+ */
9
+ import type { HudUseData } from '@reticlehq/core';
10
+ import { type Telemetry } from './telemetry.js';
11
+ /** Count one HUD use from one tab, and send the events it amounts to. */
12
+ export declare function reportHudUse(use: HudUseData, tab: string, telemetry?: Pick<Telemetry, 'emit'>): void;
13
+ /** The tab went into the background or came back: its HUD time pauses while it is hidden. */
14
+ export declare function noteHudTabHidden(tab: string, hidden: boolean): void;
15
+ /** The tab went away. */
16
+ export declare function noteHudTabClosed(tab: string): void;
@@ -0,0 +1,27 @@
1
+ import { TelemetryEventKind, countBucket } from '@reticlehq/core/telemetry';
2
+ import { getSessionMetrics } from './session-metrics.js';
3
+ import { getTelemetry } from './telemetry.js';
4
+ /** Count one HUD use from one tab, and send the events it amounts to. */
5
+ export function reportHudUse(use, tab, telemetry = getTelemetry()) {
6
+ const signals = getSessionMetrics().recordHudUse(use, tab);
7
+ const tabs = countBucket(signals.tabs);
8
+ try {
9
+ if (signals.viewed !== undefined)
10
+ void telemetry.emit(TelemetryEventKind.HUD_VIEWED, { hud: { view: signals.viewed, tabs } });
11
+ if (signals.prompted !== undefined)
12
+ void telemetry.emit(TelemetryEventKind.HUD_SIGNIN_PROMPTED, {
13
+ hud: { surface: signals.prompted, tabs },
14
+ });
15
+ }
16
+ catch {
17
+ /* a metric may never change behaviour */
18
+ }
19
+ }
20
+ /** The tab went into the background or came back: its HUD time pauses while it is hidden. */
21
+ export function noteHudTabHidden(tab, hidden) {
22
+ getSessionMetrics().setHudTabHidden(tab, hidden);
23
+ }
24
+ /** The tab went away. */
25
+ export function noteHudTabClosed(tab) {
26
+ getSessionMetrics().closeHudTab(tab);
27
+ }