@reticlehq/server 3.7.0 → 3.8.1

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 (578) hide show
  1. package/SKILL.md +59 -68
  2. package/bin/reticle.js +9 -2
  3. package/dist/command/cli/adhoc-suite.js +1 -1
  4. package/dist/command/cli/adhoc-verdict.d.ts +12 -0
  5. package/dist/command/cli/adhoc-verdict.js +62 -4
  6. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  7. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  8. package/dist/command/cli/auth/cloud-session.d.ts +11 -19
  9. package/dist/command/cli/auth/cloud-session.js +23 -0
  10. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  11. package/dist/command/cli/cli-doctor.js +66 -21
  12. package/dist/command/cli/cli-flow-commands.js +53 -11
  13. package/dist/command/cli/cli-kill.d.ts +8 -0
  14. package/dist/command/cli/cli-kill.js +43 -3
  15. package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
  16. package/dist/command/cli/cli-parse-feedback.js +13 -1
  17. package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
  18. package/dist/command/cli/cli-parse-grammar.js +1 -6
  19. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  20. package/dist/command/cli/cli-parse-serve.js +124 -0
  21. package/dist/command/cli/cli-parse.d.ts +12 -11
  22. package/dist/command/cli/cli-parse.js +100 -123
  23. package/dist/command/cli/cli-usage.d.ts +0 -11
  24. package/dist/command/cli/cli-usage.js +43 -16
  25. package/dist/command/cli/cli-verify.d.ts +1 -1
  26. package/dist/command/cli/cli-verify.js +29 -14
  27. package/dist/command/cli/cloud-cli.js +27 -9
  28. package/dist/command/cli/cloud-kit.js +3 -3
  29. package/dist/command/cli/cloud-link.d.ts +1 -20
  30. package/dist/command/cli/cloud-link.js +2 -0
  31. package/dist/command/cli/cloud-login.d.ts +6 -2
  32. package/dist/command/cli/cloud-login.js +13 -41
  33. package/dist/command/cli/config/checkout.d.ts +10 -0
  34. package/dist/command/cli/config/checkout.js +78 -0
  35. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  36. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  37. package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
  38. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  39. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  40. package/dist/command/cli/drive/drive-attach.d.ts +5 -0
  41. package/dist/command/cli/drive/drive-attach.js +21 -1
  42. package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
  43. package/dist/command/cli/hook/codex-transcript.js +224 -0
  44. package/dist/command/cli/hook/episode-structure.d.ts +24 -0
  45. package/dist/command/cli/hook/episode-structure.js +138 -0
  46. package/dist/command/cli/hook/hook-command.d.ts +9 -0
  47. package/dist/command/cli/hook/hook-command.js +211 -0
  48. package/dist/command/cli/hook/hook-fast.d.ts +31 -0
  49. package/dist/command/cli/hook/hook-fast.js +136 -0
  50. package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
  51. package/dist/command/cli/hook/prompt-hook.js +199 -0
  52. package/dist/command/cli/hook/tool-hook.d.ts +21 -0
  53. package/dist/command/cli/hook/tool-hook.js +259 -0
  54. package/dist/command/cli/launch/cli-launch.d.ts +2 -0
  55. package/dist/command/cli/launch/cli-launch.js +22 -2
  56. package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
  57. package/dist/command/cli/mcp-command.d.ts +9 -0
  58. package/dist/command/cli/mcp-command.js +127 -41
  59. package/dist/command/cli/open-navigate.d.ts +43 -0
  60. package/dist/command/cli/open-navigate.js +85 -0
  61. package/dist/command/cli/ports/port-holder.d.ts +16 -4
  62. package/dist/command/cli/ports/port-holder.js +58 -12
  63. package/dist/command/cli/ports/resolve/cli-port.js +18 -2
  64. package/dist/command/cli/project-name.d.ts +1 -7
  65. package/dist/command/cli/project-name.js +1 -0
  66. package/dist/command/cli/report-command.d.ts +8 -2
  67. package/dist/command/cli/report-command.js +95 -18
  68. package/dist/command/cli/status-fields.d.ts +9 -2
  69. package/dist/command/cli/status-fields.js +148 -4
  70. package/dist/command/cli/try-command.d.ts +3 -4
  71. package/dist/command/cli/try-command.js +6 -11
  72. package/dist/command/cli/verify-results.d.ts +4 -1
  73. package/dist/command/cli/verify-results.js +3 -1
  74. package/dist/command/cli.d.ts +1 -7
  75. package/dist/command/cli.js +79 -160
  76. package/dist/command/daemon/daemon-resilience.d.ts +6 -1
  77. package/dist/command/daemon/daemon-resilience.js +31 -18
  78. package/dist/command/daemon/daemon.d.ts +11 -0
  79. package/dist/command/daemon/daemon.js +70 -2
  80. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
  81. package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
  82. package/dist/command/daemon/wake-decision.js +4 -2
  83. package/dist/command/daemon/win32-escape.d.ts +32 -0
  84. package/dist/command/daemon/win32-escape.js +119 -0
  85. package/dist/command/setup/agent-configs.d.ts +9 -0
  86. package/dist/command/setup/agent-configs.js +9 -0
  87. package/dist/command/setup/auto-approve.d.ts +10 -3
  88. package/dist/command/setup/auto-approve.js +51 -3
  89. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  90. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  91. package/dist/command/setup/bringup/ensure-daemon.js +4 -7
  92. package/dist/command/setup/init/init-host.js +6 -0
  93. package/dist/command/setup/init/init-port.js +5 -4
  94. package/dist/command/setup/init/init-runtime.js +7 -1
  95. package/dist/command/setup/node-effects.d.ts +8 -0
  96. package/dist/command/setup/node-effects.js +36 -4
  97. package/dist/command/setup/probe/dev-port.d.ts +26 -0
  98. package/dist/command/setup/probe/dev-port.js +117 -0
  99. package/dist/command/setup/probe/page-probe.d.ts +1 -1
  100. package/dist/command/setup/probe/page-probe.js +11 -3
  101. package/dist/command/setup/remaining-steps.d.ts +0 -7
  102. package/dist/command/setup/remaining-steps.js +3 -2
  103. package/dist/command/setup/run-setup.d.ts +11 -0
  104. package/dist/command/setup/run-setup.js +33 -5
  105. package/dist/command/setup/setup-command.d.ts +2 -0
  106. package/dist/command/setup/setup-command.js +22 -4
  107. package/dist/command/update/updater.d.ts +1 -6
  108. package/dist/command/update/updater.js +4 -5
  109. package/dist/command/update/version-seen.d.ts +24 -0
  110. package/dist/command/update/version-seen.js +65 -0
  111. package/dist/command/version/peer-announce.d.ts +9 -1
  112. package/dist/command/version/peer-announce.js +25 -2
  113. package/dist/command/version/sdk-fix.d.ts +5 -6
  114. package/dist/command/version/sdk-fix.js +17 -32
  115. package/dist/command/version/version-skew.d.ts +16 -1
  116. package/dist/command/version/version-skew.js +84 -10
  117. package/dist/features/crawl/crawl-tools.js +2 -2
  118. package/dist/features/crawl/crawl.js +2 -0
  119. package/dist/features/exhaust/ledger.d.ts +15 -96
  120. package/dist/features/exhaust/ledger.js +3 -3
  121. package/dist/features/harness/drive-runs.d.ts +28 -4
  122. package/dist/features/harness/drive-runs.js +99 -7
  123. package/dist/features/harness/drivers.d.ts +1 -1
  124. package/dist/features/harness/drivers.js +1 -1
  125. package/dist/features/harness/harness.d.ts +5 -0
  126. package/dist/features/harness/harness.js +24 -12
  127. package/dist/features/harness/platform/platform-drives.d.ts +7 -1
  128. package/dist/features/harness/platform/platform-drives.js +12 -7
  129. package/dist/features/harness/platform/refusal.d.ts +1 -1
  130. package/dist/features/harness/platform/refusal.js +4 -4
  131. package/dist/features/harness/platform/remote-drive.js +70 -28
  132. package/dist/features/harness/platform/server-driver.js +22 -1
  133. package/dist/features/harness/platform-config.d.ts +1 -10
  134. package/dist/features/harness/platform-config.js +0 -20
  135. package/dist/features/license/license.d.ts +2 -14
  136. package/dist/features/visual/step-shots.d.ts +33 -1
  137. package/dist/features/visual/step-shots.js +155 -1
  138. package/dist/features/visual/visual-tools.js +12 -4
  139. package/dist/hooks/coding-agents.d.ts +6 -0
  140. package/dist/hooks/coding-agents.js +24 -3
  141. package/dist/hooks/episode-stamp.d.ts +32 -0
  142. package/dist/hooks/episode-stamp.js +61 -0
  143. package/dist/hooks/hook-commands.js +19 -9
  144. package/dist/index.d.ts +5 -1
  145. package/dist/index.js +66 -24
  146. package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
  147. package/dist/judgement/app-graph/journal-steps.js +92 -0
  148. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  149. package/dist/judgement/domain/domain-model.js +1 -10
  150. package/dist/judgement/domain/domain-tools.js +4 -2
  151. package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
  152. package/dist/judgement/runs/artifact/run-store.js +153 -28
  153. package/dist/judgement/runs/default-run-id.d.ts +3 -1
  154. package/dist/judgement/runs/default-run-id.js +15 -3
  155. package/dist/judgement/runs/drive-run.d.ts +3 -3
  156. package/dist/judgement/runs/drive-run.js +11 -7
  157. package/dist/judgement/runs/run-ledger.d.ts +21 -0
  158. package/dist/judgement/runs/run-ledger.js +143 -0
  159. package/dist/judgement/runs/runner-port.d.ts +1 -1
  160. package/dist/judgement/runs/runner-port.js +8 -2
  161. package/dist/judgement/runs/verification-sync.d.ts +4 -3
  162. package/dist/judgement/runs/verification-sync.js +27 -5
  163. package/dist/language/flows/affected-tools.js +2 -1
  164. package/dist/language/flows/annotate-notes/annotate.js +8 -3
  165. package/dist/language/flows/annotate-tools.js +1 -1
  166. package/dist/language/flows/change/affected.d.ts +8 -0
  167. package/dist/language/flows/change/affected.js +20 -7
  168. package/dist/language/flows/decision.js +19 -4
  169. package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
  170. package/dist/language/flows/fields/flow-secret-field.js +67 -5
  171. package/dist/language/flows/flow-anchor.d.ts +5 -0
  172. package/dist/language/flows/flow-anchor.js +4 -0
  173. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  174. package/dist/language/flows/flow-cross-step.js +9 -0
  175. package/dist/language/flows/flow-expect-grammar.js +15 -10
  176. package/dist/language/flows/flow-intent.js +6 -1
  177. package/dist/language/flows/flow-journey.d.ts +8 -0
  178. package/dist/language/flows/flow-journey.js +13 -0
  179. package/dist/language/flows/flow-lease.d.ts +27 -0
  180. package/dist/language/flows/flow-lease.js +59 -0
  181. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  182. package/dist/language/flows/flow-replay-run.js +111 -310
  183. package/dist/language/flows/flow-replay.js +21 -19
  184. package/dist/language/flows/flow-replayable.d.ts +38 -0
  185. package/dist/language/flows/flow-replayable.js +179 -0
  186. package/dist/language/flows/flow-start-path.d.ts +108 -0
  187. package/dist/language/flows/flow-start-path.js +313 -0
  188. package/dist/language/flows/flow-step-runners.d.ts +23 -2
  189. package/dist/language/flows/flow-step-runners.js +191 -32
  190. package/dist/language/flows/flow-store-for-session.d.ts +8 -1
  191. package/dist/language/flows/flow-store-for-session.js +6 -0
  192. package/dist/language/flows/flow-tools.d.ts +2 -23
  193. package/dist/language/flows/flow-tools.js +63 -113
  194. package/dist/language/flows/flows.d.ts +4 -6
  195. package/dist/language/flows/flows.js +90 -15
  196. package/dist/language/flows/heal-run.d.ts +10 -4
  197. package/dist/language/flows/heal-run.js +26 -9
  198. package/dist/language/flows/recording/flake.d.ts +3 -27
  199. package/dist/language/flows/recording/flake.js +1 -1
  200. package/dist/language/flows/recording/recording-backtrack.js +1 -4
  201. package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
  202. package/dist/language/flows/recording/tape/recordings.js +9 -3
  203. package/dist/language/flows/replay.d.ts +25 -5
  204. package/dist/language/flows/replay.js +83 -16
  205. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  206. package/dist/language/flows/suite/coverage.d.ts +9 -0
  207. package/dist/language/flows/suite/coverage.js +12 -1
  208. package/dist/language/flows/suite-selection.d.ts +25 -0
  209. package/dist/language/flows/suite-selection.js +41 -9
  210. package/dist/machine/git-tracks.d.ts +6 -0
  211. package/dist/machine/git-tracks.js +36 -0
  212. package/dist/memory/cloud/background-sync.d.ts +25 -0
  213. package/dist/memory/cloud/background-sync.js +79 -0
  214. package/dist/memory/cloud/cloud-config.d.ts +12 -1
  215. package/dist/memory/cloud/cloud-config.js +39 -13
  216. package/dist/memory/cloud/cloud-sync.d.ts +3 -24
  217. package/dist/memory/cloud/cloud-sync.js +5 -2
  218. package/dist/memory/cloud/harness-config.d.ts +0 -7
  219. package/dist/memory/cloud/memory-scope.d.ts +19 -0
  220. package/dist/memory/cloud/memory-scope.js +48 -0
  221. package/dist/memory/cloud/sync-answer.d.ts +43 -0
  222. package/dist/memory/cloud/sync-answer.js +42 -0
  223. package/dist/memory/cloud/sync-cycle.d.ts +40 -10
  224. package/dist/memory/cloud/sync-cycle.js +97 -144
  225. package/dist/memory/cloud/sync-daemon.d.ts +50 -3
  226. package/dist/memory/cloud/sync-daemon.js +473 -83
  227. package/dist/memory/cloud/sync-describe.d.ts +28 -0
  228. package/dist/memory/cloud/sync-describe.js +92 -0
  229. package/dist/memory/cloud/sync-disk.d.ts +9 -1
  230. package/dist/memory/cloud/sync-disk.js +137 -33
  231. package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
  232. package/dist/memory/cloud/sync-flow-versions.js +42 -0
  233. package/dist/memory/impact/impact-store.js +32 -15
  234. package/dist/memory/intent/intent-shard.d.ts +41 -266
  235. package/dist/memory/intent/intent-tools.js +20 -61
  236. package/dist/memory/intent/record-request.d.ts +27 -0
  237. package/dist/memory/intent/record-request.js +88 -0
  238. package/dist/memory/intent/settled-words.js +9 -1
  239. package/dist/memory/journal/drive-flow.d.ts +3 -0
  240. package/dist/memory/journal/drive-flow.js +11 -41
  241. package/dist/memory/journal/envelope-store.js +1 -1
  242. package/dist/memory/journal/envelope.d.ts +6 -154
  243. package/dist/memory/journal/episode-log.d.ts +107 -0
  244. package/dist/memory/journal/episode-log.js +302 -0
  245. package/dist/memory/journal/journal-recorder.d.ts +7 -0
  246. package/dist/memory/journal/journal-recorder.js +22 -9
  247. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  248. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  249. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
  250. package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
  251. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
  252. package/dist/memory/journal/self-observation.js +3 -1
  253. package/dist/memory/journal/session-end.js +23 -9
  254. package/dist/memory/journal/session-journal.js +39 -20
  255. package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
  256. package/dist/memory/project/artifact-root-resolver.js +68 -23
  257. package/dist/memory/project/artifact-root.d.ts +17 -3
  258. package/dist/memory/project/artifact-root.js +47 -9
  259. package/dist/memory/project/fs/fs-port.d.ts +5 -0
  260. package/dist/memory/project/fs/fs-port.js +13 -0
  261. package/dist/memory/project/learned-routes.d.ts +3 -4
  262. package/dist/memory/project/learned-routes.js +3 -11
  263. package/dist/memory/project/link-directory.js +5 -2
  264. package/dist/memory/project/root-claims.d.ts +3 -1
  265. package/dist/memory/project/root-claims.js +41 -7
  266. package/dist/memory/project/session-root.d.ts +1 -1
  267. package/dist/memory/project/session-root.js +1 -15
  268. package/dist/memory/project/sync-status.js +5 -6
  269. package/dist/memory/recall/memory-tools.js +2 -2
  270. package/dist/memory/recall/platform-memory.d.ts +3 -1
  271. package/dist/memory/recall/platform-memory.js +9 -1
  272. package/dist/memory/recall/project-memory.js +15 -19
  273. package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
  274. package/dist/portal/bridge/auth-failure-reason.js +19 -0
  275. package/dist/portal/bridge/bridge.d.ts +19 -4
  276. package/dist/portal/bridge/bridge.js +150 -177
  277. package/dist/portal/bridge/harness-request.d.ts +15 -0
  278. package/dist/portal/bridge/harness-request.js +19 -0
  279. package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
  280. package/dist/portal/bridge/origin/origin-follow.js +110 -0
  281. package/dist/portal/bridge/pairing-token.d.ts +6 -0
  282. package/dist/portal/bridge/pairing-token.js +47 -16
  283. package/dist/portal/bridge/protocol-skew.d.ts +27 -2
  284. package/dist/portal/bridge/protocol-skew.js +66 -2
  285. package/dist/portal/bridge/session-nonces.d.ts +46 -0
  286. package/dist/portal/bridge/session-nonces.js +72 -0
  287. package/dist/portal/input/viewport-tools.d.ts +31 -0
  288. package/dist/portal/input/viewport-tools.js +106 -15
  289. package/dist/portal/pool/bounded-close.d.ts +23 -0
  290. package/dist/portal/pool/bounded-close.js +38 -0
  291. package/dist/portal/pool/browser-pool.d.ts +44 -39
  292. package/dist/portal/pool/browser-pool.js +247 -95
  293. package/dist/portal/pool/context-permissions.d.ts +9 -1
  294. package/dist/portal/pool/context-permissions.js +26 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +37 -0
  296. package/dist/portal/pool/lease-emulation.js +29 -0
  297. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  298. package/dist/portal/pool/playwright-launcher.js +74 -7
  299. package/dist/portal/pool/pool-contract.d.ts +23 -1
  300. package/dist/portal/pool/pool-lease.d.ts +128 -0
  301. package/dist/portal/pool/pool-lease.js +49 -0
  302. package/dist/portal/pool/zero-install.d.ts +8 -1
  303. package/dist/portal/pool/zero-install.js +24 -2
  304. package/dist/portal/production/production-activation.d.ts +136 -0
  305. package/dist/portal/production/production-activation.js +173 -0
  306. package/dist/portal/production/production-drive.d.ts +52 -0
  307. package/dist/portal/production/production-drive.js +301 -0
  308. package/dist/portal/production/production-hello.d.ts +23 -0
  309. package/dist/portal/production/production-hello.js +23 -0
  310. package/dist/portal/realm/web-realm.js +42 -15
  311. package/dist/portal/session/control-envelope.d.ts +1 -1
  312. package/dist/portal/session/dev-server/served-document.d.ts +0 -5
  313. package/dist/portal/session/dev-server/served-document.js +6 -8
  314. package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
  315. package/dist/portal/session/first-run-wiring.d.ts +3 -36
  316. package/dist/portal/session/first-run-wiring.js +10 -103
  317. package/dist/portal/session/live-control-tools.js +61 -19
  318. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  319. package/dist/portal/session/no-session-next-action.js +40 -15
  320. package/dist/portal/session/no-session-watch.d.ts +7 -0
  321. package/dist/portal/session/no-session-watch.js +67 -23
  322. package/dist/portal/session/output-budget.d.ts +10 -0
  323. package/dist/portal/session/output-budget.js +16 -0
  324. package/dist/portal/session/presence/session-lease.d.ts +2 -0
  325. package/dist/portal/session/presence/session-lease.js +8 -0
  326. package/dist/portal/session/recorded-gaps.d.ts +15 -11
  327. package/dist/portal/session/recorded-gaps.js +39 -18
  328. package/dist/portal/session/serving-directory.d.ts +24 -2
  329. package/dist/portal/session/serving-directory.js +93 -5
  330. package/dist/portal/session/session-info.d.ts +26 -0
  331. package/dist/portal/session/session-info.js +20 -0
  332. package/dist/portal/session/session-manager.d.ts +35 -3
  333. package/dist/portal/session/session-manager.js +69 -14
  334. package/dist/portal/session/session-successor.js +1 -9
  335. package/dist/portal/session/session-tools.js +22 -4
  336. package/dist/portal/session/session.d.ts +10 -10
  337. package/dist/portal/session/session.js +37 -29
  338. package/dist/portal/session/zero-install-first-call.d.ts +7 -2
  339. package/dist/portal/session/zero-install-first-call.js +43 -20
  340. package/dist/start-wiring.d.ts +2 -2
  341. package/dist/start-wiring.js +17 -3
  342. package/dist/status-payload.d.ts +11 -1
  343. package/dist/status-payload.js +7 -1
  344. package/dist/surface/agent-presence-grace.d.ts +11 -0
  345. package/dist/surface/agent-presence-grace.js +34 -0
  346. package/dist/surface/http-server.d.ts +12 -1
  347. package/dist/surface/http-server.js +64 -15
  348. package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
  349. package/dist/surface/mcp/faults/mcp-outage.js +19 -1
  350. package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
  351. package/dist/surface/mcp/mcp-proxy.js +194 -267
  352. package/dist/surface/mcp/mcp.d.ts +20 -3
  353. package/dist/surface/mcp/mcp.js +88 -25
  354. package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
  355. package/dist/surface/mcp/proxy/drive-calls.js +114 -5
  356. package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
  357. package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
  358. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
  359. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
  360. package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
  361. package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
  362. package/dist/surface/mcp/server-instructions.js +35 -16
  363. package/dist/surface/mcp/shared-params.d.ts +8 -0
  364. package/dist/surface/mcp/shared-params.js +15 -1
  365. package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
  366. package/dist/surface/mcp/sse-frame-parser.js +18 -0
  367. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  368. package/dist/surface/mcp/surface-vocabulary.js +13 -0
  369. package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
  370. package/dist/surface/mcp/tool-catalog-cache.js +14 -4
  371. package/dist/surface/tools/account-tool.d.ts +4 -3
  372. package/dist/surface/tools/account-tool.js +20 -31
  373. package/dist/surface/tools/act/act-danger.d.ts +2 -0
  374. package/dist/surface/tools/act/act-danger.js +41 -14
  375. package/dist/surface/tools/act/act-observation.d.ts +11 -0
  376. package/dist/surface/tools/act/act-observation.js +33 -0
  377. package/dist/surface/tools/act/act-preflight.js +10 -3
  378. package/dist/surface/tools/act/act-sequence-retry.js +2 -1
  379. package/dist/surface/tools/act/act-target.js +19 -5
  380. package/dist/surface/tools/act/durable.js +1 -1
  381. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
  382. package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
  383. package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
  384. package/dist/surface/tools/act/unsettled-find.js +71 -0
  385. package/dist/surface/tools/act-sequence-tool.js +53 -24
  386. package/dist/surface/tools/act-tools.d.ts +2 -3
  387. package/dist/surface/tools/act-tools.js +49 -47
  388. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  389. package/dist/surface/tools/agent/for-the-agent.js +41 -3
  390. package/dist/surface/tools/assert/assert-grade.js +8 -3
  391. package/dist/surface/tools/assert/assert-verdict.js +4 -2
  392. package/dist/surface/tools/browser-tools.js +7 -4
  393. package/dist/surface/tools/chat-drives.js +50 -25
  394. package/dist/surface/tools/coverage-tools.js +1 -1
  395. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  396. package/dist/surface/tools/dynamic-tools.js +89 -34
  397. package/dist/surface/tools/empty-session-list.d.ts +18 -25
  398. package/dist/surface/tools/empty-session-list.js +67 -38
  399. package/dist/surface/tools/error-recovery.d.ts +17 -7
  400. package/dist/surface/tools/error-recovery.js +53 -20
  401. package/dist/surface/tools/explore-tools.d.ts +10 -0
  402. package/dist/surface/tools/explore-tools.js +72 -19
  403. package/dist/surface/tools/feedback-tools.js +23 -2
  404. package/dist/surface/tools/gap-novelty.d.ts +6 -0
  405. package/dist/surface/tools/gap-novelty.js +9 -0
  406. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  407. package/dist/surface/tools/harness-explore.d.ts +1 -1
  408. package/dist/surface/tools/harness-explore.js +6 -4
  409. package/dist/surface/tools/harness-gate.d.ts +43 -21
  410. package/dist/surface/tools/harness-gate.js +55 -81
  411. package/dist/surface/tools/harness-script.d.ts +2 -0
  412. package/dist/surface/tools/harness-script.js +11 -6
  413. package/dist/surface/tools/harness-toolset.js +3 -4
  414. package/dist/surface/tools/invoke-tool.d.ts +0 -8
  415. package/dist/surface/tools/invoke-tool.js +164 -178
  416. package/dist/surface/tools/lease-hint.d.ts +9 -0
  417. package/dist/surface/tools/lease-hint.js +22 -3
  418. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  419. package/dist/surface/tools/lease-readiness.d.ts +55 -0
  420. package/dist/surface/tools/lease-readiness.js +150 -2
  421. package/dist/surface/tools/lease-tools.d.ts +3 -75
  422. package/dist/surface/tools/lease-tools.js +124 -188
  423. package/dist/surface/tools/map-tools.d.ts +20 -0
  424. package/dist/surface/tools/map-tools.js +145 -0
  425. package/dist/surface/tools/merge-tools.js +11 -7
  426. package/dist/surface/tools/next-step.js +6 -3
  427. package/dist/surface/tools/observe-tools.js +46 -35
  428. package/dist/surface/tools/platform-moment.d.ts +3 -12
  429. package/dist/surface/tools/platform-moment.js +12 -24
  430. package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
  431. package/dist/surface/tools/read/complete-snapshot.js +13 -2
  432. package/dist/surface/tools/read/query-paginate.js +6 -0
  433. package/dist/surface/tools/read/query-shape.d.ts +9 -0
  434. package/dist/surface/tools/read/query-shape.js +15 -0
  435. package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
  436. package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
  437. package/dist/surface/tools/read-tools.js +5 -5
  438. package/dist/surface/tools/real-input-attempt.d.ts +11 -0
  439. package/dist/surface/tools/real-input-attempt.js +206 -38
  440. package/dist/surface/tools/reconcile-tools.js +21 -8
  441. package/dist/surface/tools/reticle-result.d.ts +3 -0
  442. package/dist/surface/tools/reticle-result.js +8 -1
  443. package/dist/surface/tools/run-report.d.ts +22 -0
  444. package/dist/surface/tools/run-report.js +141 -0
  445. package/dist/surface/tools/session-ports.d.ts +57 -0
  446. package/dist/surface/tools/session-ports.js +102 -0
  447. package/dist/surface/tools/tool-kit.d.ts +58 -4
  448. package/dist/surface/tools/tool-kit.js +140 -6
  449. package/dist/surface/tools/tool-surface.d.ts +2 -0
  450. package/dist/surface/tools/tool-surface.js +45 -0
  451. package/dist/surface/tools/tools.js +49 -87
  452. package/dist/telemetry/automation-hint.d.ts +5 -0
  453. package/dist/telemetry/automation-hint.js +7 -0
  454. package/dist/telemetry/cli-telemetry.d.ts +22 -0
  455. package/dist/telemetry/cli-telemetry.js +80 -11
  456. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  457. package/dist/telemetry/daemon-telemetry.js +9 -2
  458. package/dist/telemetry/feedback-cli.d.ts +1 -1
  459. package/dist/telemetry/feedback-cli.js +8 -3
  460. package/dist/telemetry/feedback.d.ts +1 -1
  461. package/dist/telemetry/feedback.js +51 -4
  462. package/dist/telemetry/harness-run.d.ts +3 -3
  463. package/dist/telemetry/harness-run.js +18 -7
  464. package/dist/telemetry/hud-events.d.ts +1 -1
  465. package/dist/telemetry/hud-metrics.d.ts +6 -3
  466. package/dist/telemetry/hud-metrics.js +20 -8
  467. package/dist/telemetry/install-source.js +1 -1
  468. package/dist/telemetry/mcp-connection.d.ts +1 -1
  469. package/dist/telemetry/mcp-connection.js +21 -2
  470. package/dist/telemetry/onboarding-firsts.d.ts +6 -1
  471. package/dist/telemetry/onboarding-firsts.js +41 -1
  472. package/dist/telemetry/proxy-telemetry.d.ts +42 -0
  473. package/dist/telemetry/proxy-telemetry.js +70 -1
  474. package/dist/telemetry/session-metrics.d.ts +1 -3
  475. package/dist/telemetry/session-metrics.js +16 -12
  476. package/dist/telemetry/telemetry.d.ts +9 -1
  477. package/dist/telemetry/telemetry.js +16 -1
  478. package/dist/telemetry/verification-of.d.ts +3 -1
  479. package/dist/telemetry/verification-of.js +7 -1
  480. package/dist/wire-journal.js +12 -2
  481. package/docs/README.md +4 -2
  482. package/docs/actions.mdx +7 -6
  483. package/docs/adapters.md +2 -1
  484. package/docs/agent-cheatsheet.md +19 -5
  485. package/docs/architecture.md +13 -10
  486. package/docs/autodrive.md +6 -5
  487. package/docs/benchmarks.md +2 -2
  488. package/docs/capabilities.mdx +1 -1
  489. package/docs/cli/affected.mdx +1 -1
  490. package/docs/cli/cloud.mdx +6 -6
  491. package/docs/cli/doctor.mdx +3 -1
  492. package/docs/cli/feedback.mdx +11 -7
  493. package/docs/cli/gate.mdx +1 -1
  494. package/docs/cli/help.mdx +1 -1
  495. package/docs/cli/init.mdx +20 -16
  496. package/docs/cli/mcp.mdx +5 -2
  497. package/docs/cli/open.mdx +5 -2
  498. package/docs/cli/report.mdx +1 -1
  499. package/docs/cli/restart.mdx +1 -1
  500. package/docs/cli/rollback.mdx +4 -4
  501. package/docs/cli/serve.mdx +7 -5
  502. package/docs/cli/setup.mdx +1 -1
  503. package/docs/cli/status.mdx +6 -2
  504. package/docs/cli/stop.mdx +3 -3
  505. package/docs/cli/telemetry.mdx +5 -1
  506. package/docs/cli/try.mdx +8 -8
  507. package/docs/cli/update.mdx +8 -5
  508. package/docs/cli/verify.mdx +12 -5
  509. package/docs/cli/version.mdx +1 -1
  510. package/docs/cli.mdx +10 -6
  511. package/docs/debugging.md +1 -1
  512. package/docs/deploy-checks.md +8 -6
  513. package/docs/desktop.mdx +14 -18
  514. package/docs/enterprise.md +6 -6
  515. package/docs/environment.mdx +5 -3
  516. package/docs/faq.mdx +9 -6
  517. package/docs/first-drive.md +19 -9
  518. package/docs/flows.md +3 -4
  519. package/docs/for-agents.md +1 -1
  520. package/docs/frameworks.mdx +34 -11
  521. package/docs/getting-started.md +46 -29
  522. package/docs/http-transport.md +2 -2
  523. package/docs/human-control.md +8 -8
  524. package/docs/index.mdx +2 -2
  525. package/docs/install-agentic.mdx +18 -19
  526. package/docs/install-manual.mdx +8 -4
  527. package/docs/integration-patterns.md +5 -5
  528. package/docs/multi-agent-testing.md +7 -5
  529. package/docs/packages/browser.mdx +34 -2
  530. package/docs/packages/core.mdx +2 -1
  531. package/docs/packages/electron.mdx +15 -3
  532. package/docs/packages/eslint-plugin.mdx +1 -1
  533. package/docs/packages/next.mdx +17 -5
  534. package/docs/packages/react.mdx +8 -1
  535. package/docs/packages/server.mdx +3 -3
  536. package/docs/packages/tauri.mdx +3 -3
  537. package/docs/packages/vite-plugin.mdx +1 -1
  538. package/docs/packages.mdx +19 -6
  539. package/docs/platform-integration.md +12 -4
  540. package/docs/predicates.mdx +18 -7
  541. package/docs/production-mode.md +108 -0
  542. package/docs/prompt-capture.md +99 -0
  543. package/docs/quickstart.mdx +14 -12
  544. package/docs/recipes.mdx +9 -8
  545. package/docs/required-checks.md +3 -2
  546. package/docs/skill-file.mdx +4 -3
  547. package/docs/skill-setup.md +2 -2
  548. package/docs/skill.md +62 -70
  549. package/docs/state-files.md +1 -0
  550. package/docs/state-management.mdx +11 -9
  551. package/docs/system-map.md +14 -13
  552. package/docs/telemetry.md +32 -24
  553. package/docs/testing.md +9 -5
  554. package/docs/tools/act-and-wait.mdx +17 -13
  555. package/docs/tools/act-sequence.mdx +40 -66
  556. package/docs/tools/act.mdx +7 -5
  557. package/docs/tools/assert.mdx +1 -1
  558. package/docs/tools/look.mdx +1 -1
  559. package/docs/tools/navigate.mdx +1 -1
  560. package/docs/tools/network.mdx +13 -11
  561. package/docs/tools/overview.mdx +3 -3
  562. package/docs/tools/query.mdx +3 -3
  563. package/docs/tools/session-and-feedback.mdx +9 -6
  564. package/docs/tools/sessions.mdx +7 -0
  565. package/docs/tools/snapshot.mdx +9 -7
  566. package/docs/tools/tools-and-run.mdx +11 -10
  567. package/docs/tools/verify.mdx +1 -1
  568. package/docs/troubleshooting.mdx +21 -9
  569. package/docs/usage.md +58 -43
  570. package/docs/use-cases.mdx +2 -2
  571. package/docs/vs-chrome-devtools-mcp.mdx +5 -5
  572. package/docs/vs-playwright-mcp.mdx +5 -4
  573. package/docs/what-is-recorded.md +12 -7
  574. package/docs/what-is-reticle.mdx +2 -2
  575. package/docs/why-reticle.mdx +1 -1
  576. package/package.json +9 -12
  577. package/dist/command/dev/stale-issue-guard.d.ts +0 -34
  578. package/dist/command/dev/stale-issue-guard.js +0 -69
@@ -439,3 +439,48 @@ export function filterTools(tools, surface) {
439
439
  // every other MCP server the user has connected. surface-sizes.test.ts enforces it.
440
440
  return tools.filter((t) => CORE_TOOL_NAMES.has(t.name) || EXTENDED_TOOL_NAMES.has(t.name));
441
441
  }
442
+ /**
443
+ * The MCP annotations of each Reticle tool: whether it changes anything, and whether it reaches
444
+ * past this machine. A client can decide approval from them: Codex's `writes` mode asks only
445
+ * for the tools that are not read-only.
446
+ *
447
+ * Read-only means that the tool changes neither the app nor the project's files. A tool that is
448
+ * not in the list is treated as a write, which is the safe side. No Reticle tool deletes data
449
+ * the user owns, so `destructiveHint` is always false.
450
+ */
451
+ const READ_ONLY = new Set([
452
+ ReticleTool.SESSIONS,
453
+ ReticleTool.LOOK,
454
+ ReticleTool.SNAPSHOT,
455
+ ReticleTool.QUERY,
456
+ ReticleTool.INSPECT,
457
+ ReticleTool.OBSERVE,
458
+ ReticleTool.LINEAGE,
459
+ ReticleTool.WAIT_FOR,
460
+ ReticleTool.NETWORK,
461
+ ReticleTool.CONSOLE,
462
+ ReticleTool.ANIMATIONS,
463
+ ReticleTool.ASSERT,
464
+ ReticleTool.STATE,
465
+ ReticleTool.CAPABILITIES,
466
+ ReticleTool.CONTEXT,
467
+ ReticleTool.MAP,
468
+ ReticleTool.MEMORY,
469
+ ReticleTool.TOOLS,
470
+ ]);
471
+ /** Tools that can send data off this machine or open any URL. */
472
+ const OPEN_WORLD = new Set([
473
+ ReticleTool.NAVIGATE,
474
+ ReticleTool.SESSION,
475
+ ReticleTool.VERIFY,
476
+ ReticleTool.EXPLORE,
477
+ ReticleTool.FEEDBACK,
478
+ ReticleTool.RUN,
479
+ ]);
480
+ export function toolAnnotations(name) {
481
+ return {
482
+ readOnlyHint: READ_ONLY.has(name),
483
+ destructiveHint: false,
484
+ openWorldHint: OPEN_WORLD.has(name),
485
+ };
486
+ }
@@ -1,14 +1,16 @@
1
1
  import { TESTID_FOUND_UNDER_SCHEMA } from './query-hint-schema.js';
2
2
  import { z } from 'zod';
3
- import { EMPTY_SESSION_LIST_OUTPUT, emptySessionList, wireCallerBesideLiveSessions, } from './empty-session-list.js';
4
- import { AttrNamesSchema, EventType, QueryBy, ReticleCommand, SnapshotMode } from '@reticlehq/core';
3
+ import { EMPTY_SESSION_LIST_OUTPUT, emptySessionList, nextStepBesideLiveSessions, } from './empty-session-list.js';
4
+ import { AttrNamesSchema, QueryBy, ReticleCommand, SnapshotMode } from '@reticlehq/core';
5
5
  import { ReticleTool } from '@reticlehq/core';
6
6
  import { withSizeCost } from '../../portal/session/output-budget.js';
7
7
  import { applySnapshotDelta, SnapshotCache } from './read/snapshot-delta.js';
8
+ import { noteUnmountedRoot } from './read/snapshot-unmounted-note.js';
8
9
  import { asNumber, asRecord, asString } from '@reticlehq/core';
9
10
  import { countSchema } from './args/numeric-bounds.js';
10
- import { normalizeQueryArgs } from './read/query-shape.js';
11
+ import { emptyQueryRefusal, normalizeQueryArgs } from './read/query-shape.js';
11
12
  import { shapeQueryResult } from './read/query-windowed.js';
13
+ import { withUnsettledFind } from './act/unsettled-find.js';
12
14
  /**
13
15
  * The query strategies, derived from the enum in core — never retyped.
14
16
  *
@@ -28,6 +30,7 @@ import { BROWSER_TOOLS } from './browser-tools.js';
28
30
  import { FLOW_TOOLS } from '../../language/flows/flow-tools.js';
29
31
  import { INTENT_TOOLS } from '../../memory/intent/intent-tools.js';
30
32
  import { CONTEXT_TOOLS } from '../../judgement/runs/context-tools.js';
33
+ import { MAP_TOOLS } from './map-tools.js';
31
34
  import { PROJECT_TOOLS } from '../../memory/project/project-tools.js';
32
35
  import { MEMORY_TOOLS } from '../../memory/recall/memory-tools.js';
33
36
  import { RUN_TOOLS } from '../../judgement/runs/run-tools.js';
@@ -75,6 +78,10 @@ export const RAW_TOOLS = withCompactEnvelope([
75
78
  sessionId: z.string(),
76
79
  url: z.string(),
77
80
  projectId: z.string().optional(),
81
+ worktree: z
82
+ .string()
83
+ .optional()
84
+ .describe('The linked git worktree, and its branch, whose dev server served this tab. Absent for the main checkout. A tab of another worktree runs other code: drive the one your change is in.'),
78
85
  title: z.string().optional(),
79
86
  adapters: z.array(z.string()),
80
87
  hasCapabilities: z.boolean(),
@@ -86,6 +93,11 @@ export const RAW_TOOLS = withCompactEnvelope([
86
93
  .string()
87
94
  .optional()
88
95
  .describe("Present only when this page's SDK version differs from the daemon's. A skewed pair connects and then disagrees about tool behaviour — usually surfacing as a bare -32000. Fix it before trusting any verdict from this session."),
96
+ sdkVersion: z.string().optional().describe("The page's SDK version, when it said."),
97
+ sdkBehind: z
98
+ .string()
99
+ .optional()
100
+ .describe('Present only when the page SDK is a minor release or more behind the daemon. The page connects, but newer commands and fixes are not in it. Says how to update it.'),
89
101
  window: z.string().optional().describe('Desktop window label (Tauri: main, setup…).'),
90
102
  documentStatus: z
91
103
  .number()
@@ -136,10 +148,8 @@ export const RAW_TOOLS = withCompactEnvelope([
136
148
  if (0 === sessions.length)
137
149
  return emptySessionList(deps, sessions);
138
150
  // Another project's tab is up. This caller's project may still never have been wired.
139
- const wired = await wireCallerBesideLiveSessions(deps, sessions);
140
- if (wired === undefined)
141
- return { sessions };
142
- return { sessions: await list(), wired };
151
+ const nextStep = nextStepBesideLiveSessions(deps, sessions);
152
+ return nextStep === undefined ? { sessions } : { sessions, next_step: nextStep };
143
153
  },
144
154
  },
145
155
  {
@@ -159,6 +169,14 @@ export const RAW_TOOLS = withCompactEnvelope([
159
169
  .boolean()
160
170
  .optional()
161
171
  .describe('Return only what changed since your last snapshot of the same scope/mode (mode:delta|unchanged). First call (or after a route change) still returns the full tree.'),
172
+ ids: z
173
+ .boolean()
174
+ .optional()
175
+ .describe('Add [testid=…] to each control that carries one: a stable identity for a harness mapping the app. Off by default; it costs tokens.'),
176
+ audit: z
177
+ .boolean()
178
+ .optional()
179
+ .describe('Also measure the page for what a person would see broken: text cut off with no ellipsis, controls drawn over each other, text under WCAG contrast. Returns `audit: [{ kind, ref, what, detail }]`. Off by default; it forces layout.'),
162
180
  ...sessionIdShape,
163
181
  },
164
182
  outputSchema: {
@@ -216,7 +234,7 @@ export const RAW_TOOLS = withCompactEnvelope([
216
234
  note: z
217
235
  .string()
218
236
  .optional()
219
- .describe('Why this result is not what it looks like. Four causes, all of which otherwise read as "the page is empty": a diff computed over a capped tree ("unchanged" is then partial); an interactive-mode tree emptied by leanness; a page whose elements all computed hidden; and an UNMOUNTED app, where the DOM under the scope holds almost nothing — that last one will not improve by waiting, so read reticle_console for an uncaught error instead.'),
237
+ .describe('Why this result is not what it looks like. Four causes, all of which otherwise read as "the page is empty": a diff computed over a capped tree ("unchanged" is then partial); an interactive-mode tree emptied by leanness; a page whose elements all computed hidden; and, on an unscoped snapshot, an UNMOUNTED app whose DOM holds almost nothing — that last one will not improve by waiting, so read reticle_console for an uncaught error instead.'),
220
238
  scopeMissing: z
221
239
  .boolean()
222
240
  .optional()
@@ -239,12 +257,14 @@ export const RAW_TOOLS = withCompactEnvelope([
239
257
  return commandOrThrow(deps, resolved.id, ReticleCommand.SNAPSHOT, {
240
258
  scope: args['scope'],
241
259
  mode,
260
+ ...(true === args['ids'] ? { ids: true } : {}),
261
+ ...(true === args['audit'] ? { audit: true } : {}),
242
262
  }).then((raw) => withSizeCost(noteUnmountedRoot(noteHiddenPage(noteEmptyLeanTree(applySnapshotDelta(raw, {
243
263
  sessionId: resolved.id,
244
264
  scope: asString(args['scope']) ?? '',
245
265
  mode,
246
266
  diff: true === args['diff'],
247
- }, deps.snapshots ?? SNAPSHOT_CACHE), mode), mode), mode, resolved)));
267
+ }, deps.snapshots ?? SNAPSHOT_CACHE), mode), mode), mode, resolved, asString(args['scope']))));
248
268
  },
249
269
  },
250
270
  {
@@ -304,7 +324,7 @@ export const RAW_TOOLS = withCompactEnvelope([
304
324
  states: z.array(z.string()),
305
325
  visible: z.boolean(),
306
326
  attrs: z
307
- .record(z.string())
327
+ .record(z.string(), z.string())
308
328
  .optional()
309
329
  .describe('Present only for attributes requested via `attrs` and found on the element.'),
310
330
  source: z
@@ -361,18 +381,18 @@ export const RAW_TOOLS = withCompactEnvelope([
361
381
  splitText: z
362
382
  .object({
363
383
  ref: z.string().optional(),
384
+ selector: z.string().optional(),
364
385
  role: z.string().optional(),
365
386
  name: z.string().optional(),
366
387
  })
367
388
  .passthrough()
368
389
  .optional()
369
- .describe("Present when a TEXT search missed but the string IS on the page, split across this container's children. Retry as { scope: <ref>, self: true } — no text query can match a string no single element owns."),
390
+ .describe("Present when a TEXT search missed but the string IS on the page, split across this container's children. Retry as { scope: <selector or ref>, self: true } — no text query can match a string no single element owns. The selector is present when the container carries a testid or an id, and can be written before the action runs."),
370
391
  caseMiss: z
371
392
  .string()
372
393
  .optional()
373
394
  .describe('Present when a case-exact TEXT check missed and the page shows the text in another case: what it shows. Retry with ignoreCase: true if the case does not matter.'),
374
- // Declared here for the same reason presentRegions had to be: the browser emits it, and an
375
- // undeclared field is stripped from structuredContent without a word.
395
+ // The browser emits this; undeclared, it would be stripped from structuredContent without a word.
376
396
  nameNearMiss: z
377
397
  .array(z.string())
378
398
  .optional()
@@ -385,6 +405,14 @@ export const RAW_TOOLS = withCompactEnvelope([
385
405
  .object({ bytes: z.number(), tokens: z.number() })
386
406
  .optional()
387
407
  .describe('Estimated size of this result — narrow with `name`/`scope`/`limit` if large.'),
408
+ unsettled: z
409
+ .object({
410
+ reason: z.string(),
411
+ inFlight: z.array(z.string()).optional(),
412
+ lastDomChangeMsAgo: z.number().optional(),
413
+ })
414
+ .optional()
415
+ .describe('Present only on zero matches read while the last act was still landing (a request it started still in flight, or the DOM changed under 500 ms ago). The 0 may only mean not rendered yet: wait instead of concluding it is absent.'),
388
416
  scopeMissing: z
389
417
  .boolean()
390
418
  .optional()
@@ -393,6 +421,10 @@ export const RAW_TOOLS = withCompactEnvelope([
393
421
  handler: (deps, rawArgs) => {
394
422
  // Accept the predicate's named-field spelling too — see query-shape.ts.
395
423
  const args = normalizeQueryArgs(rawArgs);
424
+ const empty = emptyQueryRefusal(args);
425
+ if (empty !== undefined)
426
+ return Promise.reject(empty);
427
+ const session = deps.sessions.resolve(asString(args['sessionId']));
396
428
  return commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.QUERY, {
397
429
  by: args['by'],
398
430
  value: args['value'],
@@ -408,7 +440,7 @@ export const RAW_TOOLS = withCompactEnvelope([
408
440
  // now asserts the payload, because a comment is not a guard.
409
441
  attrs: args['attrs'],
410
442
  self: args['self'],
411
- }).then((result) => withSizeCost(shapeQueryResult(result, args)));
443
+ }).then((result) => withSizeCost(withUnsettledFind(session, shapeQueryResult(result, args))));
412
444
  },
413
445
  },
414
446
  // reticle_inspect: one element in full detail. See inspect-tool.ts.
@@ -418,6 +450,7 @@ export const RAW_TOOLS = withCompactEnvelope([
418
450
  ...CONTRACT_TOOLS,
419
451
  ...INTENT_TOOLS,
420
452
  ...CONTEXT_TOOLS,
453
+ ...MAP_TOOLS,
421
454
  ...DOMAIN_TOOLS,
422
455
  // reticle_flow_save / reticle_flow_list / reticle_flow_load. See flow-tools.ts.
423
456
  ...FLOW_TOOLS,
@@ -519,7 +552,7 @@ export const MERGE_PLANS = [
519
552
  },
520
553
  {
521
554
  name: ReticleTool.VERIFY,
522
- description: 'What is proved, and what is not — by action. Start from a change: { action: "affected" } names which saved flows must re-verify for the files you edited (pass `files`, and/or `since` for a git ref), and "change" goes further and actually replays them, answering with one `verified` plus `because`. `unknown` there is the honest answer when NO saved flow covers the change: nothing ran, so nothing was proved, and it is never reported as green. Without a change to start from: "flows" replays every saved flow for one consolidated suite verdict (deterministic, no LLM per flow), and "coverage" lists the interactive controls you have and have NOT driven this session — an untouched list still holding the controls your change affects means you are not done. "crawl" is the no-script option: it drives every reachable control itself and reports single-channel faults (console errors, failed requests, dead controls) and CONTRADICTIONS, two channels disagreeing about the same click — the false greens a human cannot see, because a human watches the screen and the screen looks correct. "explore" is the one to reach for on a project with NO saved flows: the Reticle Harness drives the app for you on the platform — pass a `persona` and it completes that whole journey — and RECORDS what it drove, so the next run replays it with no model in the loop and none of the driving costs your context. "mutate" grades the FLOW rather than the app: it breaks the endpoint a saved flow declared it depends on and replays it, and a flow that stays GREEN through a broken subject is a click sequence, not a test. "heal" repairs a flow whose LOCATOR drifted (a renamed testid), re-asserting the saved consequence before it writes and refusing when that stops firing — it heals a locator, never an intent. DESTRUCTIVE: crawl and explore really click, and may navigate or mutate state; "mutate" really fails a request on a driven page, and always puts it back.',
555
+ description: 'The Reticle Harness is { action: "explore" }: when the user asks for the Harness, or asks Reticle to drive and verify the app for you, call it and do not drive the app yourself. Every other action says what is proved, and what is not. Start from a change: { action: "affected" } names which saved flows must re-verify for the files you edited (pass `files`, and/or `since` for a git ref), and "change" goes further and actually replays them, answering with one `verified` plus `because`. `unknown` there is the honest answer when NO saved flow covers the change: nothing ran, so nothing was proved, and it is never reported as green. Without a change to start from: "flows" replays every saved flow for one consolidated suite verdict (deterministic, no LLM per flow), and "coverage" lists the interactive controls you have and have NOT driven this session — an untouched list still holding the controls your change affects means you are not done. "crawl" is the no-script option: it drives every reachable control itself and reports single-channel faults (console errors, failed requests, dead controls) and CONTRADICTIONS, two channels disagreeing about the same click — the false greens a human cannot see, because a human watches the screen and the screen looks correct. "explore" is the Reticle Harness: it drives the app for you on the platform — pass a `persona` and it completes that whole journey — and RECORDS what it drove, so the next run replays it with no model in the loop and none of the driving costs your context. "mutate" grades the FLOW rather than the app: it breaks the endpoint a saved flow declared it depends on and replays it, and a flow that stays GREEN through a broken subject is a click sequence, not a test. "heal" repairs a flow whose LOCATOR drifted (a renamed testid), re-asserting the saved consequence before it writes and refusing when that stops firing — it heals a locator, never an intent. DESTRUCTIVE: crawl and explore really click, and may navigate or mutate state; "mutate" really fails a request on a driven page, and always puts it back.',
523
556
  members: {
524
557
  change: ReticleTool.VERIFY_CHANGE,
525
558
  flows: ReticleTool.FLOW_VERIFY,
@@ -601,77 +634,6 @@ function noteEmptyLeanTree(result, mode) {
601
634
  * cannot know why, and a note that guessed would be the same kind of overconfident answer as the
602
635
  * empty tree it replaces.
603
636
  */
604
- /**
605
- * How much DOM there is under the mount container, when the tree is empty and nothing was skipped.
606
- *
607
- * A handful of elements is a container with nothing in it. React's own root div counts as one, and a
608
- * wrapper or two is ordinary, so this is deliberately not `=== 0`.
609
- */
610
- const UNMOUNTED_ROOT_MAX_ELEMENTS = 3;
611
- function crashEvidence(session) {
612
- const since = asRecord(session)['eventsSince'];
613
- if ('function' !== typeof since)
614
- return undefined;
615
- let events;
616
- try {
617
- events = since.call(session, 0);
618
- }
619
- catch {
620
- return undefined;
621
- }
622
- if (!Array.isArray(events))
623
- return undefined;
624
- const errors = events.filter((e) => {
625
- const type = asString(asRecord(e)['type']);
626
- return EventType.CONSOLE_ERROR === type || EventType.ERROR_UNCAUGHT === type;
627
- });
628
- if (0 === errors.length)
629
- return undefined;
630
- const first = errors
631
- .map((e) => asString(asRecord(asRecord(e)['data'])['message']))
632
- .find((m) => undefined !== m && '' !== m);
633
- return { count: errors.length, first: first ?? '' };
634
- }
635
- function noteUnmountedRoot(result, mode, session) {
636
- if (SnapshotMode.STATUS === mode)
637
- return result;
638
- const row = asRecord(result);
639
- if (0 !== asNumber(row['nodes']))
640
- return result;
641
- if (row['note'] !== undefined)
642
- return result;
643
- const elements = asNumber(row['domElements']);
644
- if (elements === undefined || elements > UNMOUNTED_ROOT_MAX_ELEMENTS)
645
- return result;
646
- const mount = `the tree is empty because there is almost nothing in the DOM: ${String(elements)} ` +
647
- `element(s) under this scope. That is a mount container with nothing rendered into it, not a ` +
648
- `page whose contents were skipped — so the app is UNMOUNTED rather than slow, and waiting ` +
649
- `will not change it. `;
650
- // An uncaught error beside an empty mount container is the difference between "has not started"
651
- // and "started and died", which are the two readings of this count and want opposite next moves.
652
- // Nothing here is framework-specific, and deliberately so: the condition is a known mount
653
- // container that holds nothing with an uncaught error beside it, which is as true of a Vue or
654
- // Svelte root as a React one.
655
- const crash = crashEvidence(session);
656
- if (crash !== undefined) {
657
- return {
658
- ...row,
659
- note: mount +
660
- `The app did not merely fail to start — it CRASHED: ${String(crash.count)} uncaught ` +
661
- `error(s) were logged in this session` +
662
- ('' === crash.first ? '' : `, the first: "${crash.first}"`) +
663
- `. Read reticle_console for the rest, and check anything that runs inside a framework ` +
664
- `commit phase. Loading the app again will reproduce it rather than fix it.`,
665
- };
666
- }
667
- return {
668
- ...row,
669
- note: mount +
670
- `An app that was rendering and then stopped has usually thrown: read ` +
671
- `reticle_console for an uncaught error, and check anything that runs inside a framework ` +
672
- `commit phase. If the app has genuinely not started yet, load it and snapshot again.`,
673
- };
674
- }
675
637
  function noteHiddenPage(result, mode) {
676
638
  if (SnapshotMode.STATUS === mode)
677
639
  return result;
@@ -787,7 +749,7 @@ export const MERGED_SURFACE_PLANS = [
787
749
  // lifecycle, where no member is the obvious bare meaning.
788
750
  defaultAction: 'list',
789
751
  description: 'By action: "list" (the default) shows connected tabs; "yield" is MANDATORY before you stop; "tune" hides or moves the HUD; "feedback" reports a problem. ' +
790
- 'In full: "list" is the first call to make, and on a project that has never connected it wires the app and names the files it changed under `wired`; "yield" hands control back to the human (mode: waiting|ask); "tune" takes `hud` (hidden, shown, removed until reload, or a corner) for when the HUD covers a control you must test, and `idleEndMs`; "feedback" files a report; "end", "resume", "messages", "review" and "narrate" manage the session and the human channel.',
752
+ 'In full: "list" is the first call to make, and on a project that has never connected it changes no file: `next_step` names the zero-install lease and the consent question for wiring; "yield" hands control back to the human (mode: waiting|ask); "tune" takes `hud` (hidden, shown, removed until reload, or a corner) for when the HUD covers a control you must test, and `idleEndMs`; "feedback" files a report; "end", "resume", "messages", "review" and "narrate" manage the session and the human channel.',
791
753
  }
792
754
  : plan),
793
755
  ...SURFACE_MERGE_PLANS,
@@ -12,6 +12,11 @@ interface AutomationInput {
12
12
  * here follows.
13
13
  */
14
14
  export declare function resolveAutomationHint(input: AutomationInput): AutomationHint | undefined;
15
+ /**
16
+ * A CI runner: `CI` itself or a vendor's own variable. The one place a command line decides whether
17
+ * it is a pipeline or a person, so a run is credited to somebody whenever nothing says CI.
18
+ */
19
+ export declare function isCiEnv(env: NodeJS.ProcessEnv): boolean;
15
20
  /** The real reading, taken once per process. */
16
21
  export declare function currentAutomationHint(env: NodeJS.ProcessEnv): AutomationHint | undefined;
17
22
  export {};
@@ -80,6 +80,13 @@ export function resolveAutomationHint(input) {
80
80
  return AutomationHint.HOSTED_WORKSPACE;
81
81
  return undefined;
82
82
  }
83
+ /**
84
+ * A CI runner: `CI` itself or a vendor's own variable. The one place a command line decides whether
85
+ * it is a pipeline or a person, so a run is credited to somebody whenever nothing says CI.
86
+ */
87
+ export function isCiEnv(env) {
88
+ return declared(env, ['CI', ...CI_VENDOR_ENV]);
89
+ }
83
90
  /** The real reading, taken once per process. */
84
91
  export function currentAutomationHint(env) {
85
92
  return resolveAutomationHint({
@@ -1,3 +1,25 @@
1
+ /**
2
+ * The one telemetry event a human directly causes: they typed a `reticle` command.
3
+ *
4
+ * Lives in its own module so `cli.ts` stays a dispatcher, and so the `_daemon` exclusion below sits
5
+ * next to the explanation of why it exists rather than buried in a startup function.
6
+ */
7
+ import { TelemetryActor } from '@reticlehq/core/telemetry';
1
8
  /** True when this command represents a person typing something. Exported for the gate. */
2
9
  export declare function isHumanCliCommand(command: string): boolean;
10
+ /**
11
+ * Who ran the command. A coding agent runs `reticle gate`, `init` and `verify` through a shell, and
12
+ * it marks the processes it spawns (see `envAgentClient`). Without the marker it is a person.
13
+ */
14
+ export declare function cliActorOf(env: NodeJS.ProcessEnv): TelemetryActor;
15
+ /**
16
+ * True when this command reports `reticle_installed`. Exported for its test.
17
+ *
18
+ * A probe (`--version`, `--help`, `telemetry`) on a new machine does not report the install. It
19
+ * leaves a pending file, and the first real command after it claims the report by deleting that
20
+ * file. So the report reads the install source that the machine state holds by then, and a probe
21
+ * with no marker cannot make it `unknown`. A machine with no pending file and no first run has
22
+ * reported its install already.
23
+ */
24
+ export declare function claimInstallReport(command: string, firstRun: boolean, stateDir: string): boolean;
3
25
  export declare function reportCliRun(argv: readonly string[]): void;
@@ -4,10 +4,11 @@
4
4
  * Lives in its own module so `cli.ts` stays a dispatcher, and so the `_daemon` exclusion below sits
5
5
  * next to the explanation of why it exists rather than buried in a startup function.
6
6
  */
7
- import { TelemetryEventKind } from '@reticlehq/core/telemetry';
8
- import { DAEMON_INNER_COMMAND, knownCommand } from '../command/cli/cli-parse.js';
7
+ import { TelemetryActor, TelemetryEventKind } from '@reticlehq/core/telemetry';
8
+ import { DAEMON_INNER_COMMAND, PROBE_COMMANDS, knownCommand } from '../command/cli/cli-parse.js';
9
9
  import { getTelemetry } from './telemetry.js';
10
10
  import { drainInstallTrace } from './install-trace.js';
11
+ import { mkdirSync, unlinkSync, writeFileSync } from 'node:fs';
11
12
  import { homedir } from 'node:os';
12
13
  import { join } from 'node:path';
13
14
  /** Where the installer left its breadcrumbs. Same directory the telemetry id and opt-out live in. */
@@ -15,6 +16,10 @@ const RETICLE_STATE_DIR = process.env['RETICLE_STATE_DIR'] ?? join(homedir(), '.
15
16
  import { describeCliFlags } from './argument-shape.js';
16
17
  import { rememberInstallSource, resolveInstallSource } from './install-source.js';
17
18
  import { installPlatformLinkTelemetry } from './platform-linked.js';
19
+ import { envAgentClient } from './agent-client.js';
20
+ import { noteRunningVersion } from '../command/update/version-seen.js';
21
+ import { wasNudged } from '../command/update/nudge-credit.js';
22
+ import { SERVER_VERSION } from '../command/version/identity/server-version.js';
18
23
  /**
19
24
  * Report that a person ran a `reticle` subcommand.
20
25
  *
@@ -40,6 +45,67 @@ const AGENT_TRANSPORT_COMMAND = 'mcp';
40
45
  export function isHumanCliCommand(command) {
41
46
  return command !== AGENT_TRANSPORT_COMMAND && command !== DAEMON_INNER_COMMAND;
42
47
  }
48
+ /**
49
+ * Who ran the command. A coding agent runs `reticle gate`, `init` and `verify` through a shell, and
50
+ * it marks the processes it spawns (see `envAgentClient`). Without the marker it is a person.
51
+ */
52
+ export function cliActorOf(env) {
53
+ return envAgentClient(env) === undefined ? TelemetryActor.HUMAN : TelemetryActor.AGENT;
54
+ }
55
+ /** Set by a probe on a new machine: the install is not reported yet. */
56
+ const INSTALL_PENDING_FILE = 'install-pending';
57
+ /**
58
+ * True when this command reports `reticle_installed`. Exported for its test.
59
+ *
60
+ * A probe (`--version`, `--help`, `telemetry`) on a new machine does not report the install. It
61
+ * leaves a pending file, and the first real command after it claims the report by deleting that
62
+ * file. So the report reads the install source that the machine state holds by then, and a probe
63
+ * with no marker cannot make it `unknown`. A machine with no pending file and no first run has
64
+ * reported its install already.
65
+ */
66
+ export function claimInstallReport(command, firstRun, stateDir) {
67
+ const pending = join(stateDir, INSTALL_PENDING_FILE);
68
+ if (PROBE_COMMANDS.has(command)) {
69
+ if (firstRun) {
70
+ try {
71
+ mkdirSync(stateDir, { recursive: true });
72
+ writeFileSync(pending, '');
73
+ }
74
+ catch {
75
+ /* an unwritable home: the install is not reported, as with an ephemeral id */
76
+ }
77
+ }
78
+ return false;
79
+ }
80
+ if (firstRun) {
81
+ return true;
82
+ }
83
+ try {
84
+ unlinkSync(pending);
85
+ return true;
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ /**
92
+ * Send `version_changed` when this start runs a different version from the last start on this
93
+ * machine. Every start does this, the daemon too: an upgrade through `npx @reticlehq/server@latest`
94
+ * never runs `reticle update`, so the updater alone saw almost no version move.
95
+ */
96
+ function reportVersionMove() {
97
+ const moved = noteRunningVersion(SERVER_VERSION, RETICLE_STATE_DIR);
98
+ if (moved === undefined) {
99
+ return;
100
+ }
101
+ void getTelemetry().emit(TelemetryEventKind.VERSION_CHANGED, {
102
+ detach: true,
103
+ versionChange: {
104
+ ...moved,
105
+ ...(wasNudged(moved.to, RETICLE_STATE_DIR) ? { nudged: true } : {}),
106
+ },
107
+ });
108
+ }
43
109
  export function reportCliRun(argv) {
44
110
  const firstArg = argv[0];
45
111
  /*
@@ -59,29 +125,32 @@ export function reportCliRun(argv) {
59
125
  drainInstallTrace(RETICLE_STATE_DIR);
60
126
  // Before anything reads it: a channel declared on THIS command outlives it.
61
127
  rememberInstallSource(process.env, RETICLE_STATE_DIR);
62
- if (firstArg === DAEMON_INNER_COMMAND)
128
+ reportVersionMove();
129
+ if (firstArg === DAEMON_INNER_COMMAND) {
63
130
  return;
131
+ }
64
132
  const command = knownCommand(firstArg);
65
133
  const telemetry = getTelemetry();
66
- // FIRST — before the human-command filter. The install happened whichever command ran, and on most
67
- // machines the very first contact is the agent spawning `reticle mcp`, which that filter excludes.
134
+ // FIRST — before the human-command filter. The install happened whichever real command ran, and on
135
+ // most machines the very first contact is the agent spawning `reticle mcp`, which that filter excludes.
68
136
  // Behind the filter this event never fires at all on an install that only ever runs `reticle mcp`.
69
137
  // `detach` so a quick command (`version`/`gate`) exits immediately instead of waiting out the POST.
70
- if (telemetry.firstRun)
138
+ if (claimInstallReport(command, telemetry.firstRun, RETICLE_STATE_DIR)) {
71
139
  void telemetry.emit(TelemetryEventKind.RETICLE_INSTALLED, {
72
140
  detach: true,
73
141
  // WHICH published route brought this machine in. Self-declared by the channel, never inferred
74
142
  // — see install-source.ts for which of the four routes can actually carry the marker.
75
143
  installSource: resolveInstallSource(process.env, RETICLE_STATE_DIR),
76
144
  });
77
- if (!isHumanCliCommand(command))
145
+ }
146
+ if (!isHumanCliCommand(command)) {
78
147
  return;
148
+ }
79
149
  void telemetry.emit(TelemetryEventKind.CLI_COMMAND_RUN, {
80
150
  detach: true,
81
- // No `actor`: with the agent's transport excluded, this event is human BY DEFINITION, so the
82
- // field would be constant here — zero information. `actor` stays where it earns its place:
83
- // verification_completed and bug_found, where it splits the agent's own loop from a human or
84
- // CI-triggered run.
151
+ // The agent's transport (`mcp`) is excluded above, but an agent also runs commands through a
152
+ // shell. `actor` splits those from a command a person typed.
153
+ actor: cliActorOf(process.env),
85
154
  // A fixed, low-cardinality vocabulary WE define, so it is safe to send whole and it is the closest
86
155
  // honest read we have on intent: `verify` and `gate` mean something very different from `status`.
87
156
  // An unrecognized first arg reports as `unknown` rather than being echoed — an echo would put
@@ -5,7 +5,7 @@
5
5
  * It lives apart from `cli.ts` because it has its own timers and its own failure rule — nothing here
6
6
  * may ever be able to fail a daemon start — and because `cli.ts` is a dispatcher.
7
7
  */
8
- import { type SessionSummary } from '@reticlehq/core/telemetry';
8
+ import { DaemonSpawnMethod, type SessionSummary } from '@reticlehq/core/telemetry';
9
9
  /**
10
10
  * How often a running daemon rolls up its window.
11
11
  *
@@ -29,6 +29,8 @@ export declare const SESSION_FLUSH_MS: number;
29
29
  * costs nothing on a daemon that never serves a tool, because only a NON-EMPTY window emits.
30
30
  */
31
31
  export declare const FIRST_FLUSH_MS: number;
32
+ /** How the parent started this daemon, from the env it set. Anything else reads as absent. */
33
+ export declare function daemonSpawnMethod(env?: Readonly<Record<string, string | undefined>>): DaemonSpawnMethod | undefined;
32
34
  /** Stops the timers this installed. Called from the daemon's shutdown path. */
33
35
  interface DaemonTelemetry {
34
36
  /**
@@ -5,7 +5,8 @@
5
5
  * It lives apart from `cli.ts` because it has its own timers and its own failure rule — nothing here
6
6
  * may ever be able to fail a daemon start — and because `cli.ts` is a dispatcher.
7
7
  */
8
- import { TelemetryEventKind } from '@reticlehq/core/telemetry';
8
+ import { DaemonSpawnMethod, TelemetryEventKind, } from '@reticlehq/core/telemetry';
9
+ import { ReticleEnv } from '@reticlehq/core';
9
10
  import { getTelemetry } from './telemetry.js';
10
11
  import { getSessionMetrics } from './session-metrics.js';
11
12
  import { profileProject } from './project-profile.js';
@@ -78,6 +79,11 @@ function withNudgeState(summary) {
78
79
  ...(nudge.offered === undefined ? {} : { updateOffered: nudge.offered }),
79
80
  };
80
81
  }
82
+ /** How the parent started this daemon, from the env it set. Anything else reads as absent. */
83
+ export function daemonSpawnMethod(env = process.env) {
84
+ const value = env[ReticleEnv.SPAWN_METHOD];
85
+ return Object.values(DaemonSpawnMethod).find((method) => method === value);
86
+ }
81
87
  /**
82
88
  * Report the daemon as started, profile the project once, and keep the session counters flushing.
83
89
  * Every timer is `unref`'d so telemetry can never be the reason a daemon refuses to exit.
@@ -91,7 +97,8 @@ export function installDaemonTelemetry(cwd, now = () => Date.now(),
91
97
  */
92
98
  port) {
93
99
  const metrics = getSessionMetrics(now);
94
- void getTelemetry().emit(TelemetryEventKind.DAEMON_STARTED);
100
+ const spawnMethod = daemonSpawnMethod();
101
+ void getTelemetry().emit(TelemetryEventKind.DAEMON_STARTED, spawnMethod === undefined ? undefined : { spawnMethod });
95
102
  // Reports a past send could not deliver. Off the boot path, and never able to throw into it.
96
103
  void drainFeedbackOutbox().catch(() => undefined);
97
104
  // Ask npm whether a newer Reticle exists, so the agent can tell the human. Nothing checked before
@@ -14,7 +14,7 @@ import { TelemetryAction } from '../command/cli/cli-parse.js';
14
14
  * What is sent is PRINTED before it goes, every time. A channel that carries free text and does not
15
15
  * show you the payload is asking for trust it has not earned.
16
16
  */
17
- export declare function handleFeedback(text: string, rating: number | undefined, bug: boolean, feedbackKind?: string, agent?: boolean): Promise<void>;
17
+ export declare function handleFeedback(text: string, rating: number | undefined, bug: boolean, feedbackKind?: string, agent?: boolean, contact?: string): Promise<void>;
18
18
  /**
19
19
  * `reticle telemetry [status|enable|disable]` — the user-facing control for anonymous usage metrics.
20
20
  * `disable` persists a machine-wide opt-out (survives shells, unlike RETICLE_TELEMETRY=0); `status`
@@ -1,5 +1,5 @@
1
1
  import { FeedbackKind, FeedbackSource } from '@reticlehq/core/telemetry';
2
- import { AGENT_FLAG, BUG_FLAG, FEEDBACK_KINDS, KIND_FLAG, RATING_FLAG, } from '../command/cli/cli-parse.js';
2
+ import { AGENT_FLAG, BUG_FLAG, CONTACT_FLAG, FEEDBACK_KINDS, KIND_FLAG, RATING_FLAG, } from '../command/cli/cli-parse.js';
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';
@@ -18,14 +18,15 @@ import { TelemetryAction } from '../command/cli/cli-parse.js';
18
18
  * What is sent is PRINTED before it goes, every time. A channel that carries free text and does not
19
19
  * show you the payload is asking for trust it has not earned.
20
20
  */
21
- export async function handleFeedback(text, rating, bug, feedbackKind, agent = false) {
21
+ export async function handleFeedback(text, rating, bug, feedbackKind, agent = false, contact) {
22
22
  const line = (s) => {
23
23
  process.stdout.write(`${s}\n`);
24
24
  };
25
25
  if ('' === text && rating === undefined) {
26
- line(`usage: reticle feedback [${RATING_FLAG} 1-5] [${BUG_FLAG}] "what worked, what didn't"`);
26
+ line(`usage: reticle feedback [${RATING_FLAG} 1-5] [${BUG_FLAG}] [${CONTACT_FLAG} you@example.com] "what worked, what didn't"`);
27
27
  line(` agents: reticle feedback ${AGENT_FLAG} ${KIND_FLAG} <${FEEDBACK_KINDS.join('|')}> "what happened"`);
28
28
  line(' your words go to the maintainers; nothing from your app is ever included.');
29
+ line(` ${CONTACT_FLAG} adds an address for a reply. It is sent only when you give it.`);
29
30
  process.exitCode = 1;
30
31
  return;
31
32
  }
@@ -40,8 +41,12 @@ export async function handleFeedback(text, rating, bug, feedbackKind, agent = fa
40
41
  // A rating with no words is a real report, but the schema wants text — say what the rating means.
41
42
  text: '' === text ? `rated ${String(rating)}/5 with no comment` : text,
42
43
  ...(rating !== undefined ? { rating } : {}),
44
+ ...(contact !== undefined ? { contact } : {}),
43
45
  });
44
46
  line(`sending ${JSON.stringify(describeFeedbackPayload(receipt.context))}`);
47
+ if (contact !== undefined) {
48
+ line(`contact ${contact} (sent so that the maintainers can answer you)`);
49
+ }
45
50
  if (receipt.redacted.length > 0) {
46
51
  line(`redacted ${receipt.redacted.join(', ')} (removed before sending)`);
47
52
  }
@@ -44,7 +44,7 @@ export declare function summarizeTrace(trace: string): string;
44
44
  /** True when the feedback channel is switched off on its own (the emitter's switches apply as well). */
45
45
  export declare function feedbackDisabled(env?: NodeJS.ProcessEnv): boolean;
46
46
  /** What the author supplies; the environment context is detected, never asked for. */
47
- type FeedbackInput = Pick<Feedback, 'source' | 'kind' | 'text' | 'trace' | 'rating' | 'need' | 'impact' | 'currentApproach' | 'model'>;
47
+ type FeedbackInput = Pick<Feedback, 'source' | 'kind' | 'text' | 'trace' | 'rating' | 'need' | 'impact' | 'currentApproach' | 'model' | 'contact'>;
48
48
  interface FeedbackReceipt {
49
49
  /**
50
50
  * DELIVERY confirmed. Only ever true when the send was awaited and the endpoint accepted it —