@reticlehq/server 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/SKILL.md +30 -28
  2. package/dist/command/cli/adhoc-suite.d.ts +19 -0
  3. package/dist/command/cli/adhoc-suite.js +88 -0
  4. package/dist/command/cli/adhoc-verdict.d.ts +23 -2
  5. package/dist/command/cli/adhoc-verdict.js +18 -10
  6. package/dist/command/cli/auth/device-flow.d.ts +2 -2
  7. package/dist/command/cli/cli-doctor.js +37 -5
  8. package/dist/command/cli/cli-flow-commands.d.ts +2 -1
  9. package/dist/command/cli/cli-kill.js +1 -1
  10. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  11. package/dist/command/cli/cli-parse-grammar.js +7 -0
  12. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  13. package/dist/command/cli/cli-parse-verify.js +86 -13
  14. package/dist/command/cli/cli-parse.d.ts +8 -1
  15. package/dist/command/cli/cli-parse.js +38 -7
  16. package/dist/command/cli/cli-verify.d.ts +59 -0
  17. package/dist/command/cli/cli-verify.js +131 -19
  18. package/dist/command/cli/cloud-cli.js +7 -6
  19. package/dist/command/cli/cloud-kit.d.ts +0 -2
  20. package/dist/command/cli/cloud-kit.js +3 -7
  21. package/dist/command/cli/config/config-discovery.d.ts +12 -0
  22. package/dist/command/cli/config/config-discovery.js +19 -0
  23. package/dist/command/cli/doctor/doctor-rows.d.ts +12 -0
  24. package/dist/command/cli/doctor/doctor-rows.js +12 -0
  25. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  26. package/dist/command/cli/drive/drive-command.js +1 -1
  27. package/dist/command/cli/launch/cli-launch.d.ts +3 -23
  28. package/dist/command/cli/launch/cli-launch.js +29 -70
  29. package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +33 -0
  30. package/dist/command/cli/lifecycle/daemon-lifecycle.js +198 -0
  31. package/dist/command/cli/mcp-command.js +5 -3
  32. package/dist/command/cli/ports/resolve/cli-port.d.ts +15 -1
  33. package/dist/command/cli/ports/resolve/cli-port.js +50 -2
  34. package/dist/command/cli/report-command.d.ts +16 -0
  35. package/dist/command/cli/report-command.js +97 -0
  36. package/dist/command/cli/status/status-lines.d.ts +28 -0
  37. package/dist/command/cli/status/status-lines.js +117 -0
  38. package/dist/command/cli.d.ts +1 -1
  39. package/dist/command/cli.js +29 -177
  40. package/dist/command/daemon/binding/daemon-status-probe.d.ts +32 -0
  41. package/dist/command/daemon/binding/daemon-status-probe.js +93 -0
  42. package/dist/command/daemon/binding/loopback-reach.d.ts +42 -0
  43. package/dist/command/daemon/binding/loopback-reach.js +63 -0
  44. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  45. package/dist/command/daemon/daemon-resilience.d.ts +13 -1
  46. package/dist/command/daemon/daemon-resilience.js +12 -1
  47. package/dist/command/daemon/daemon.d.ts +2 -11
  48. package/dist/command/daemon/daemon.js +8 -11
  49. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  50. package/dist/command/daemon/lifetime/heartbeat.d.ts +8 -0
  51. package/dist/command/daemon/lifetime/heartbeat.js +10 -0
  52. package/dist/command/daemon/lifetime/log-cap.d.ts +68 -0
  53. package/dist/command/daemon/lifetime/log-cap.js +115 -0
  54. package/dist/command/setup/agent-notice-memory.d.ts +16 -0
  55. package/dist/command/setup/agent-notice-memory.js +65 -0
  56. package/dist/command/setup/bringup/dev-server-wait.d.ts +1 -0
  57. package/dist/command/setup/bringup/dev-server-wait.js +16 -0
  58. package/dist/command/setup/bringup/ensure-daemon.js +1 -1
  59. package/dist/command/setup/init/init-host.js +8 -0
  60. package/dist/command/setup/init/init-runtime.js +13 -1
  61. package/dist/command/setup/node-effects.js +1 -1
  62. package/dist/command/setup/probe/page-probe.js +9 -2
  63. package/dist/command/setup/run-setup.d.ts +25 -7
  64. package/dist/command/setup/run-setup.js +51 -9
  65. package/dist/command/setup/setup-command.js +31 -3
  66. package/dist/command/setup/terminal/confirm.js +2 -1
  67. package/dist/command/update/updater.d.ts +27 -0
  68. package/dist/command/update/updater.js +35 -2
  69. package/dist/features/crawl/crawl-tools.js +3 -1
  70. package/dist/features/crawl/crawl.d.ts +2 -0
  71. package/dist/features/crawl/crawl.js +3 -1
  72. package/dist/features/harness/drive-report.d.ts +73 -0
  73. package/dist/features/harness/drive-report.js +196 -0
  74. package/dist/features/harness/driver.js +29 -8
  75. package/dist/features/harness/drivers.d.ts +19 -0
  76. package/dist/features/harness/drivers.js +19 -0
  77. package/dist/features/harness/fill-values.d.ts +67 -0
  78. package/dist/features/harness/fill-values.js +153 -0
  79. package/dist/features/harness/jev-driver.d.ts +188 -0
  80. package/dist/features/harness/jev-driver.js +661 -0
  81. package/dist/features/harness/openai-driver.d.ts +46 -0
  82. package/dist/features/harness/openai-driver.js +197 -0
  83. package/dist/features/harness/platform-config.d.ts +62 -0
  84. package/dist/features/harness/platform-config.js +97 -0
  85. package/dist/features/visual/visual-tools.js +26 -2
  86. package/dist/index.d.ts +1 -1
  87. package/dist/index.js +80 -130
  88. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  89. package/dist/judgement/capsule/capsule-store.js +58 -6
  90. package/dist/judgement/capsule/capsule.js +5 -0
  91. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  92. package/dist/judgement/capsule/causal-summary.js +7 -0
  93. package/dist/judgement/domain/domain-model.js +38 -9
  94. package/dist/judgement/domain/domain-tools.js +4 -2
  95. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  96. package/dist/judgement/phenomena/phenomena.d.ts +2 -1
  97. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  98. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  99. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  100. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  101. package/dist/judgement/runs/artifact/render-report.js +4 -1
  102. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  103. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  104. package/dist/judgement/runs/context-tools.js +21 -3
  105. package/dist/judgement/runs/drive-run.js +7 -2
  106. package/dist/judgement/runs/verification-sync.d.ts +2 -2
  107. package/dist/judgement/runs/verification-sync.js +9 -2
  108. package/dist/language/flows/affected-tools.js +6 -3
  109. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  110. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  111. package/dist/language/flows/flow-anchor.d.ts +12 -0
  112. package/dist/language/flows/flow-anchor.js +20 -0
  113. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  114. package/dist/language/flows/flow-expect-grammar.js +92 -11
  115. package/dist/language/flows/flow-intent.js +1 -1
  116. package/dist/language/flows/flow-learning.d.ts +3 -0
  117. package/dist/language/flows/flow-learning.js +39 -8
  118. package/dist/language/flows/flow-replay-run.d.ts +55 -10
  119. package/dist/language/flows/flow-replay-run.js +217 -58
  120. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  121. package/dist/language/flows/flow-replay.d.ts +29 -11
  122. package/dist/language/flows/flow-replay.js +221 -203
  123. package/dist/language/flows/flow-result.d.ts +18 -1
  124. package/dist/language/flows/flow-result.js +18 -2
  125. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  126. package/dist/language/flows/flow-step-runners.js +20 -4
  127. package/dist/language/flows/flow-store-for-session.d.ts +2 -1
  128. package/dist/language/flows/flow-success.d.ts +21 -6
  129. package/dist/language/flows/flow-success.js +50 -138
  130. package/dist/language/flows/flow-tools.js +8 -4
  131. package/dist/language/flows/flows.d.ts +15 -10
  132. package/dist/language/flows/flows.js +17 -4
  133. package/dist/language/flows/heal.d.ts +9 -1
  134. package/dist/language/flows/heal.js +24 -2
  135. package/dist/language/flows/learned-sources.d.ts +21 -0
  136. package/dist/language/flows/learned-sources.js +84 -0
  137. package/dist/language/flows/narrow-write.d.ts +4 -4
  138. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  139. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  140. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  141. package/dist/language/flows/recording/tape/recordings.d.ts +2 -2
  142. package/dist/language/flows/replay.js +13 -9
  143. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  144. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  145. package/dist/language/flows/stores/flake-store.js +2 -3
  146. package/dist/language/flows/suite/coverage.d.ts +1 -1
  147. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  148. package/dist/language/flows/suite-selection.d.ts +15 -1
  149. package/dist/language/flows/suite-selection.js +1 -1
  150. package/dist/language/flows/verify-change-tools.js +21 -4
  151. package/dist/memory/cloud/account-state.d.ts +1 -1
  152. package/dist/memory/cloud/account-state.js +5 -4
  153. package/dist/memory/cloud/cloud-config.d.ts +9 -0
  154. package/dist/memory/cloud/cloud-config.js +9 -0
  155. package/dist/memory/cloud/cloud-sync.d.ts +7 -4
  156. package/dist/memory/cloud/cloud-sync.js +11 -6
  157. package/dist/memory/cloud/harness-config.d.ts +12 -0
  158. package/dist/memory/cloud/harness-config.js +58 -0
  159. package/dist/memory/cloud/harness-offer.d.ts +44 -0
  160. package/dist/memory/cloud/harness-offer.js +146 -0
  161. package/dist/memory/cloud/harness-switch.d.ts +11 -0
  162. package/dist/memory/cloud/harness-switch.js +53 -0
  163. package/dist/memory/cloud/sync-cycle.d.ts +12 -0
  164. package/dist/memory/cloud/sync-cycle.js +29 -4
  165. package/dist/memory/cloud/sync-daemon.d.ts +35 -2
  166. package/dist/memory/cloud/sync-daemon.js +45 -0
  167. package/dist/memory/cloud/sync-disk.js +11 -6
  168. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  169. package/dist/memory/impact/impact-recorder.js +2 -1
  170. package/dist/memory/impact/impact-store.d.ts +5 -0
  171. package/dist/memory/impact/impact-store.js +25 -0
  172. package/dist/memory/intent/inline-intent.js +8 -3
  173. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  174. package/dist/memory/intent/intent-shard-store.js +253 -141
  175. package/dist/memory/intent/intent-shard.d.ts +22 -23
  176. package/dist/memory/intent/intent-shard.js +1 -1
  177. package/dist/memory/intent/intent-store.d.ts +13 -8
  178. package/dist/memory/intent/intent-store.js +46 -90
  179. package/dist/memory/intent/intent-tools.js +34 -23
  180. package/dist/memory/journal/ambient-store.js +2 -3
  181. package/dist/memory/journal/attach-journal.d.ts +11 -0
  182. package/dist/memory/journal/attach-journal.js +1 -1
  183. package/dist/memory/journal/deviation-report.js +4 -1
  184. package/dist/memory/journal/deviation-service.js +10 -2
  185. package/dist/memory/journal/drive-flow.d.ts +2 -2
  186. package/dist/memory/journal/drive-flow.js +21 -12
  187. package/dist/memory/journal/envelope-store.js +2 -3
  188. package/dist/memory/journal/journal-query.d.ts +35 -1
  189. package/dist/memory/journal/journal-query.js +46 -0
  190. package/dist/memory/journal/journal-recorder.d.ts +71 -2
  191. package/dist/memory/journal/journal-recorder.js +45 -7
  192. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  193. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  194. package/dist/memory/journal/on-disk/retention.d.ts +91 -2
  195. package/dist/memory/journal/on-disk/retention.js +181 -11
  196. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  197. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  198. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -2
  199. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -38
  200. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  201. package/dist/memory/journal/on-disk/workspace-tiers.js +88 -0
  202. package/dist/memory/journal/route-template.d.ts +22 -0
  203. package/dist/memory/journal/route-template.js +44 -0
  204. package/dist/memory/journal/self-observation.d.ts +3 -0
  205. package/dist/memory/journal/self-observation.js +67 -0
  206. package/dist/memory/journal/session-end.d.ts +17 -4
  207. package/dist/memory/journal/session-end.js +85 -7
  208. package/dist/memory/journal/session-journal.d.ts +122 -5
  209. package/dist/memory/journal/session-journal.js +489 -32
  210. package/dist/memory/project/artifact-root-resolver.d.ts +3 -0
  211. package/dist/memory/project/artifact-root-resolver.js +89 -0
  212. package/dist/memory/project/artifact-root.d.ts +39 -2
  213. package/dist/memory/project/artifact-root.js +58 -1
  214. package/dist/memory/project/baselines.d.ts +1 -1
  215. package/dist/memory/project/dir/fill-value-store.d.ts +32 -0
  216. package/dist/memory/project/dir/fill-value-store.js +88 -0
  217. package/dist/memory/project/dir/reticle-dir.d.ts +15 -5
  218. package/dist/memory/project/dir/reticle-dir.js +11 -0
  219. package/dist/memory/project/fs/fs-port.d.ts +22 -1
  220. package/dist/memory/project/fs/fs-port.js +72 -5
  221. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  222. package/dist/memory/project/fs/write-atomic.js +48 -0
  223. package/dist/memory/project/learned-routes.d.ts +16 -2
  224. package/dist/memory/project/learned-routes.js +26 -10
  225. package/dist/memory/project/project-for-root.d.ts +30 -0
  226. package/dist/memory/project/project-for-root.js +43 -0
  227. package/dist/memory/project/project-tools.js +10 -5
  228. package/dist/memory/project/session-root.d.ts +35 -6
  229. package/dist/memory/project/session-root.js +70 -8
  230. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  231. package/dist/memory/recall/prior/connection-memory.js +8 -0
  232. package/dist/memory/recall/registered-projects.d.ts +2 -1
  233. package/dist/portal/bridge/auth-failure-reason.d.ts +9 -0
  234. package/dist/portal/bridge/auth-failure-reason.js +20 -3
  235. package/dist/portal/bridge/bridge.d.ts +6 -1
  236. package/dist/portal/bridge/bridge.js +36 -2
  237. package/dist/portal/input/real-input.js +2 -1
  238. package/dist/portal/pool/browser-pool.d.ts +10 -0
  239. package/dist/portal/pool/browser-pool.js +10 -0
  240. package/dist/portal/pool/playwright-launcher.js +1 -0
  241. package/dist/portal/pool/pool-contract.d.ts +2 -0
  242. package/dist/portal/pool/storage-seed.d.ts +2 -1
  243. package/dist/portal/pool/zero-install.d.ts +27 -0
  244. package/dist/portal/pool/zero-install.js +54 -0
  245. package/dist/portal/realm/web-realm.js +6 -0
  246. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  247. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  248. package/dist/portal/session/dev-server/served-document.js +57 -0
  249. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  250. package/dist/portal/session/facts/background-traffic.js +25 -0
  251. package/dist/portal/session/facts/session-replaced.d.ts +19 -0
  252. package/dist/portal/session/facts/session-replaced.js +22 -0
  253. package/dist/portal/session/live-control-tools.js +48 -3
  254. package/dist/portal/session/no-session-diagnosis.d.ts +1 -0
  255. package/dist/portal/session/no-session-diagnosis.js +67 -60
  256. package/dist/portal/session/no-session-next-action.js +3 -2
  257. package/dist/portal/session/no-session-watch.js +14 -10
  258. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  259. package/dist/portal/session/rebind.d.ts +18 -0
  260. package/dist/portal/session/rebind.js +38 -0
  261. package/dist/portal/session/session-health.d.ts +61 -0
  262. package/dist/portal/session/session-health.js +40 -1
  263. package/dist/portal/session/session-info.d.ts +6 -0
  264. package/dist/portal/session/session-manager.d.ts +13 -0
  265. package/dist/portal/session/session-manager.js +42 -3
  266. package/dist/portal/session/session-successor.d.ts +11 -0
  267. package/dist/portal/session/session-successor.js +14 -1
  268. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  269. package/dist/portal/session/session-verdict-facts.js +15 -0
  270. package/dist/portal/session/session.d.ts +26 -10
  271. package/dist/portal/session/session.js +48 -49
  272. package/dist/status-payload.d.ts +12 -1
  273. package/dist/status-payload.js +4 -1
  274. package/dist/surface/http-server.js +3 -5
  275. package/dist/surface/mcp/faults/mcp-outage.d.ts +2 -1
  276. package/dist/surface/mcp/faults/mcp-outage.js +20 -4
  277. package/dist/surface/mcp/mcp-proxy.d.ts +10 -1
  278. package/dist/surface/mcp/mcp-proxy.js +23 -12
  279. package/dist/surface/mcp/mcp.d.ts +10 -1
  280. package/dist/surface/mcp/mcp.js +59 -29
  281. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +15 -2
  282. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +22 -5
  283. package/dist/surface/mcp/proxy/proxy-log.d.ts +5 -11
  284. package/dist/surface/mcp/proxy/proxy-log.js +7 -22
  285. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  286. package/dist/surface/mcp/server-instructions.js +12 -1
  287. package/dist/surface/tools/act/act-preflight.js +6 -1
  288. package/dist/surface/tools/act/already-true.d.ts +40 -0
  289. package/dist/surface/tools/act/already-true.js +36 -0
  290. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +6 -0
  291. package/dist/surface/tools/act/navigation/navigate-arrival.js +13 -0
  292. package/dist/surface/tools/act/sequence-grade.js +13 -0
  293. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  294. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  295. package/dist/surface/tools/act-capsule.js +49 -8
  296. package/dist/surface/tools/act-tools.js +25 -24
  297. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  298. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  299. package/dist/surface/tools/assert/assert-grade.js +14 -2
  300. package/dist/surface/tools/assert/assert-verdict.js +74 -21
  301. package/dist/surface/tools/browser-tools.js +4 -3
  302. package/dist/surface/tools/coverage-tools.js +5 -2
  303. package/dist/surface/tools/dynamic-tools.js +43 -46
  304. package/dist/surface/tools/error-recovery.d.ts +6 -0
  305. package/dist/surface/tools/error-recovery.js +15 -0
  306. package/dist/surface/tools/explore-tools.js +80 -7
  307. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  308. package/dist/surface/tools/feedback-tools.js +50 -3
  309. package/dist/surface/tools/first-sentence.d.ts +24 -0
  310. package/dist/surface/tools/first-sentence.js +0 -0
  311. package/dist/surface/tools/harness-explore.d.ts +125 -1
  312. package/dist/surface/tools/harness-explore.js +401 -15
  313. package/dist/surface/tools/harness-plan.d.ts +76 -0
  314. package/dist/surface/tools/harness-plan.js +156 -0
  315. package/dist/surface/tools/harness-toolset.js +12 -1
  316. package/dist/surface/tools/invoke-tool.js +82 -9
  317. package/dist/surface/tools/lease-hint.d.ts +8 -0
  318. package/dist/surface/tools/lease-hint.js +10 -0
  319. package/dist/surface/tools/lease-tools.d.ts +16 -28
  320. package/dist/surface/tools/lease-tools.js +53 -5
  321. package/dist/surface/tools/lineage-tools.js +1 -1
  322. package/dist/surface/tools/live-call-text.d.ts +6 -0
  323. package/dist/surface/tools/live-call-text.js +36 -2
  324. package/dist/surface/tools/observe-tools.js +69 -15
  325. package/dist/surface/tools/read/query-windowed.d.ts +1 -1
  326. package/dist/surface/tools/read/query-windowed.js +1 -1
  327. package/dist/surface/tools/read-tools.js +1 -2
  328. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  329. package/dist/surface/tools/real-input-attempt.js +1 -1
  330. package/dist/surface/tools/tool-kit.d.ts +23 -3
  331. package/dist/surface/tools/tool-kit.js +6 -1
  332. package/dist/surface/tools/tool-surface.js +17 -5
  333. package/dist/surface/tools/tools-helpers.d.ts +8 -7
  334. package/dist/surface/tools/tools-helpers.js +11 -13
  335. package/dist/surface/tools/tools.js +70 -30
  336. package/dist/telemetry/bug-found.js +32 -2
  337. package/dist/telemetry/feedback-context.js +3 -3
  338. package/dist/telemetry/feedback-local.d.ts +1 -0
  339. package/dist/telemetry/feedback-local.js +1 -3
  340. package/dist/telemetry/feedback.d.ts +1 -1
  341. package/dist/telemetry/harness-drive.d.ts +6 -0
  342. package/dist/telemetry/harness-drive.js +39 -0
  343. package/dist/telemetry/hud-metrics.d.ts +32 -0
  344. package/dist/telemetry/hud-metrics.js +95 -0
  345. package/dist/telemetry/mcp-connection.d.ts +14 -1
  346. package/dist/telemetry/mcp-connection.js +17 -2
  347. package/dist/telemetry/onboarding-firsts.d.ts +30 -1
  348. package/dist/telemetry/onboarding-firsts.js +54 -12
  349. package/dist/telemetry/session-metrics.d.ts +5 -0
  350. package/dist/telemetry/session-metrics.js +15 -1
  351. package/dist/telemetry/verification-of.js +31 -3
  352. package/dist/wire-journal.d.ts +31 -0
  353. package/dist/wire-journal.js +100 -0
  354. package/docs/README.md +1 -0
  355. package/docs/agent-cheatsheet.md +7 -3
  356. package/docs/autodrive.md +42 -2
  357. package/docs/benchmarks.md +1 -1
  358. package/docs/capabilities.mdx +1 -1
  359. package/docs/cli/cloud.mdx +11 -9
  360. package/docs/cli/doctor.mdx +1 -0
  361. package/docs/cli/init.mdx +1 -0
  362. package/docs/cli/report.mdx +44 -0
  363. package/docs/cli/status.mdx +35 -20
  364. package/docs/cli.mdx +8 -18
  365. package/docs/desktop.mdx +1 -1
  366. package/docs/faq.mdx +1 -1
  367. package/docs/flows.md +11 -0
  368. package/docs/frameworks.mdx +113 -1
  369. package/docs/install-agentic.mdx +36 -0
  370. package/docs/install-manual.mdx +1 -1
  371. package/docs/packages/tauri.mdx +1 -1
  372. package/docs/packages.mdx +1 -1
  373. package/docs/predicates.mdx +144 -4
  374. package/docs/system-map.md +6 -4
  375. package/docs/telemetry.md +2 -1
  376. package/docs/token-efficiency.md +2 -2
  377. package/docs/tools/overview.mdx +1 -1
  378. package/docs/tools/query.mdx +10 -10
  379. package/docs/troubleshooting.mdx +8 -2
  380. package/docs/usage.md +2 -2
  381. package/docs/what-is-recorded.md +62 -0
  382. package/package.json +5 -5
  383. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  384. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
@@ -123,12 +123,37 @@ export function liveCallText(text, advertised) {
123
123
  continue;
124
124
  out = out.replace(pattern, instead);
125
125
  }
126
- return out.replace(TOOL_TOKEN, (name) => {
126
+ /**
127
+ * A sentence explaining where a name WENT keeps that name, even though it is unreachable.
128
+ *
129
+ * These messages open with their own subject — "reticle_act_sequence was merged into reticle_act",
130
+ * "reticle_refresh no longer exists" — and the rewrite is precisely a rule for replacing
131
+ * unreachable names, so it replaced the subject too. Asking about `reticle_act_sequence` answered
132
+ * "reticle_act no longer exists", which is false: `reticle_act` is a tool, and the one thing the
133
+ * reader needed to know was which name had moved.
134
+ *
135
+ * Only the leading token, and only in front of those two phrases. Every other mention in the same
136
+ * sentence — including the tool to call INSTEAD — is still rewritten, which is the whole job.
137
+ */
138
+ const explainsItsSubject = /^(reticle_[a-z_]+)(?= (?:was merged into|no longer exists))/.exec(out);
139
+ const subject = explainsItsSubject?.[1];
140
+ return out.replace(TOOL_TOKEN, (name, offset) => {
141
+ if (name === subject && 0 === offset)
142
+ return name;
127
143
  if (advertised.has(name))
128
144
  return name;
129
145
  return replacementFor(name, advertised) ?? name;
130
146
  });
131
147
  }
148
+ /**
149
+ * Keys whose STRING value names a thing rather than advising a call.
150
+ *
151
+ * `name` is what the caller asked about and has to match their question against; `tool` is the
152
+ * already-resolved answer to "call this instead", so redirecting it a second time can only move it
153
+ * away from the answer. Deliberately two names and not a pattern: every other string in a result is
154
+ * prose, and prose is exactly what the rewrite is for.
155
+ */
156
+ const IDENTITY_KEYS = new Set(['name', 'tool']);
132
157
  /**
133
158
  * The same rewrite, applied to a result's STRING VALUES instead of to its encoded form.
134
159
  *
@@ -140,6 +165,12 @@ export function liveCallText(text, advertised) {
140
165
  * was corrected and the result became unreadable, which is a worse trade than the advice was worth.
141
166
  *
142
167
  * Values, not keys: a key is a contract with the caller and nothing in a key is advice.
168
+ *
169
+ * And not every value is advice either. A field that carries a tool's IDENTITY is an answer to
170
+ * "which one", not a suggestion about what to call — rewriting it destroys the thing the caller
171
+ * asked for. `reticle_tools { names: ["reticle_act_sequence"] }` sets `name` to the name it was
172
+ * asked about, and this rewrote it to `reticle_act`, so a batch query came back with entries the
173
+ * caller could no longer match to their questions. See `IDENTITY_KEYS`.
143
174
  */
144
175
  export function liveCallValues(value, advertised) {
145
176
  if ('string' === typeof value)
@@ -149,7 +180,10 @@ export function liveCallValues(value, advertised) {
149
180
  if (null !== value && 'object' === typeof value) {
150
181
  const out = {};
151
182
  for (const [key, each] of Object.entries(value)) {
152
- out[key] = liveCallValues(each, advertised);
183
+ out[key] =
184
+ IDENTITY_KEYS.has(key) && 'string' === typeof each
185
+ ? each
186
+ : liveCallValues(each, advertised);
153
187
  }
154
188
  return out;
155
189
  }
@@ -7,7 +7,7 @@ import { z } from 'zod';
7
7
  import { aliasParam } from './args/alias-args.js';
8
8
  import { CONSOLE_ATTACH_NOTE, CONSOLE_LEVELS, ReticleCommand, DEFAULT_ASSERT_TIMEOUT_MS, PredicateKind, Verified, } from '@reticlehq/core';
9
9
  import { ReticleTool } from '@reticlehq/core';
10
- import { countSchema, cursorSchema, httpStatusSchema, timeoutMsSchema, windowMsSchema, } from './args/numeric-bounds.js';
10
+ import { countSchema, cursorSchema, httpStatusSchema, timeoutMsSchema, waitForTimeoutMsSchema, resumeAfter, MAX_BLOCKING_WAIT_MS, windowMsSchema, } from './args/numeric-bounds.js';
11
11
  import { buildReactionReport } from '@reticlehq/engine/question/reaction.js';
12
12
  import { findContradictions } from '@reticlehq/engine/disagreement/contradictions.js';
13
13
  import { evaluatePredicate, waitForPredicate, PredicateSchema, } from '@reticlehq/engine/question/predicate/predicate.js';
@@ -16,9 +16,10 @@ import { WALL_CLOCK } from '../../portal/session/timing/wall-clock.js';
16
16
  import { parsePredicate } from '@reticlehq/engine/question/predicate/predicate-parse.js';
17
17
  import { matchNet, matchConsole, isConsoleEvent, eventMatchesFilters, netEmptyHint, consoleEmptyHint, reconcileNet, projectNetCall, projectConsoleLog, withoutUrlRaw, } from '@reticlehq/engine/window/event-filters.js';
18
18
  import { applyEventBudget, costHint, withSizeCost, DEFAULT_OBSERVE_EVENT_LIMIT, DEFAULT_QUERY_LIMIT, } from '../../portal/session/output-budget.js';
19
- import { annotateStarvedFailure, healthEnvelope, bufferEnvelope, } from '../../portal/session/session-health.js';
19
+ import { annotateStarvedFailure, currentOf, healthEnvelope, bufferEnvelope, } from '../../portal/session/session-health.js';
20
20
  import { assertsDerivedIpcStatus, DERIVED_IPC_STATUS_ADVICE, isPresenceOnlyAssertion, PRESENCE_ONLY_ADVICE, } from './assert/assert-grade.js';
21
21
  import { assertVerdict } from './assert/assert-verdict.js';
22
+ import { followLostObservation } from './act/act-observation.js';
22
23
  import { withGapNovelty } from './gap-novelty.js';
23
24
  import { assertionSource } from './assert/assert-source.js';
24
25
  import { isChangeUndeclared } from '@reticlehq/engine/evidence/undeclared-change.js';
@@ -171,6 +172,7 @@ export const OBSERVE_TOOLS = [
171
172
  currentDocumentId: session.currentDocumentId,
172
173
  currentEditEpoch: session.currentEditEpoch,
173
174
  appOrigin: session.url,
175
+ background: session.background,
174
176
  ...(judgingTheAct ? { ...session.lastAct.effect(), actionSince: actCursor } : {}),
175
177
  });
176
178
  // carry session health — a throttled tab means the observed timeline may be incomplete.
@@ -192,15 +194,19 @@ export const OBSERVE_TOOLS = [
192
194
  predicate: PredicateSchema.optional().describe('Predicate to wait for: { signal }, { net }, { element }, { kind: "net", ok: false } (assert on the OUTCOME — the honest field for IPC, which has no status code), { kind: "state", store, path, equals } (assert a registered store\'s value directly — the source of truth no DOM read can reach; equals takes a literal or { $gte | $contains | $length } pattern), { kind: "settled", quietMs } (deterministic network + DOM idle — prefer this over a fixed sleep), or a combination via allOf/anyOf.'),
193
195
  // Same concept, the neighbouring tool's name. See alias-args.ts.
194
196
  until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
195
- timeout_ms: timeoutMsSchema
197
+ timeout_ms: waitForTimeoutMsSchema
196
198
  .optional()
197
- .describe('Maximum wait in milliseconds. Default: 4000. Capped at 55000: your MCP client aborts the request before a longer wait can return, so a bound above this would be advertised and not deliverable. To outlast it, poll — several short waits, each of which returns a verdict.'),
199
+ .describe(`Maximum wait in milliseconds. Default: 4000, up to 600000. One call waits at most ${String(MAX_BLOCKING_WAIT_MS)} ms, because your MCP client aborts a longer request; past that it returns resume_ms, and you call again with timeout_ms: resume_ms and the same since to keep waiting.`),
198
200
  since: cursorSchema
199
201
  .optional()
200
202
  .describe('Cursor from a prior reticle_act — scopes the wait to events after that act.'),
201
203
  ...sessionIdShape,
202
204
  },
203
205
  outputSchema: {
206
+ resume_ms: z
207
+ .number()
208
+ .optional()
209
+ .describe('Present when this call stopped at the per-call limit before the predicate was seen. Call again with timeout_ms set to this, the same predicate and the same since, to keep waiting.'),
204
210
  pass: z.boolean(),
205
211
  evidence: z.unknown().optional(),
206
212
  failureReason: z.string().optional(),
@@ -208,6 +214,10 @@ export const OBSERVE_TOOLS = [
208
214
  .boolean()
209
215
  .optional()
210
216
  .describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
217
+ sessionId: z
218
+ .string()
219
+ .optional()
220
+ .describe('The session that answered, when a full-document navigation replaced the one this was asked of. Absent when the original session survived.'),
211
221
  inconclusive: z
212
222
  .string()
213
223
  .optional()
@@ -234,9 +244,11 @@ export const OBSERVE_TOOLS = [
234
244
  .describe('Where the code behind this verdict lives, as `file:line`. For an element/text assertion it is the matched element itself; for a FAILING signal/net/state assertion — which has no element to point at — it is the control last acted on, where the handler that should have fired lives. OMITTED when neither is known: this tool never borrows an unrelated location.'),
235
245
  },
236
246
  handler: async (deps, args) => {
237
- const waitBudget = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
247
+ const requestedMs = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
248
+ // One call never blocks past what the client allows; the rest comes back as resume_ms.
249
+ const waitBudget = Math.min(requestedMs, MAX_BLOCKING_WAIT_MS);
238
250
  // Spend the budget waiting for the APP as well as for the predicate. See resolve-within.
239
- const session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), waitBudget, WALL_CLOCK);
251
+ let session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), waitBudget, WALL_CLOCK);
240
252
  // `until` is act_and_wait's name for this — see alias-args.ts.
241
253
  const predicate = parsePredicate(aliasParam(args, 'predicate', ['until'])['predicate']);
242
254
  // Refused up front rather than waited out: a body clause this session cannot answer would
@@ -245,8 +257,22 @@ export const OBSERVE_TOOLS = [
245
257
  if (bodyRefusal !== undefined)
246
258
  throw new Error(bodyRefusal);
247
259
  // Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
248
- const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
249
- const verdict = await waitForPredicate(session, predicate, waitBudget, since);
260
+ let since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
261
+ // See the note on the assert handler below: a wait cut off by a full-document navigation is
262
+ // followed to the document that took over, rather than graded as a lost observation there.
263
+ const predicateStarted = session.elapsed();
264
+ const followed = await followLostObservation({
265
+ sessions: deps.sessions,
266
+ session,
267
+ verdict: await waitForPredicate(session, predicate, waitBudget, since),
268
+ timeout: waitBudget,
269
+ predicateStarted,
270
+ reevaluate: (next, budget) => waitForPredicate(next, predicate, budget, 0),
271
+ });
272
+ if (followed.followed)
273
+ since = 0;
274
+ session = followed.session;
275
+ const verdict = followed.verdict;
250
276
  // match reticle_assert — wrap with control + session health (throttle matters most while blocking)
251
277
  // and the buffer envelope, so a verdict reached over an evicted window says so.
252
278
  return withControl(session, {
@@ -255,6 +281,8 @@ export const OBSERVE_TOOLS = [
255
281
  // `lastActSourceOnFailure` — an assert used to be blamed on the previous act's file:line.
256
282
  ...annotateStarvedFailure(session, verdict),
257
283
  ...assertionSource(session, predicate, verdict),
284
+ ...(followed.followed ? { sessionId: session.id } : {}),
285
+ ...((resume) => (resume === undefined ? {} : { resume_ms: resume }))(resumeAfter(requestedMs, waitBudget, verdict)),
258
286
  ...healthEnvelope(session),
259
287
  ...bufferEnvelope(session),
260
288
  });
@@ -271,7 +299,7 @@ export const OBSERVE_TOOLS = [
271
299
  // is the most common thing an agent wants to assert. A field report reached us from an agent
272
300
  // that guessed `urlContains` on route (net's spelling) and got unrecognized_keys.
273
301
  'Predicate to evaluate. Kinds: { signal, name|dataMatches|count } ' +
274
- '{ net, urlContains|method|status|count|bodyContains|requestBodyContains|requestBodyMatches } ' +
302
+ '{ net, urlContains|method|status|count|bodyMatches|bodyContains|requestBodyContains|requestBodyMatches } ' +
275
303
  '{ state, path|equals } { route, pathname (exact) | contains (path+query+hash) } ' +
276
304
  '{ element, testid|role|text } { text } { console, level|contains|absent } { animation, name } ' +
277
305
  '{ settled } — combine with { allOf | anyOf | not }. Prefer a signal/net/state consequence ' +
@@ -294,6 +322,10 @@ export const OBSERVE_TOOLS = [
294
322
  .boolean()
295
323
  .optional()
296
324
  .describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
325
+ sessionId: z
326
+ .string()
327
+ .optional()
328
+ .describe('The session that answered, when a full-document navigation replaced the one this was asked of. Absent when the original session survived.'),
297
329
  inconclusive: z
298
330
  .string()
299
331
  .optional()
@@ -338,7 +370,7 @@ export const OBSERVE_TOOLS = [
338
370
  handler: async (deps, args) => {
339
371
  const timeout = asNumber(args['timeout_ms']) ?? 0;
340
372
  // Spend the budget waiting for the APP as well as for the predicate. See resolve-within.
341
- const session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), timeout, WALL_CLOCK);
373
+ let session = await resolveSessionWithin(deps.sessions, asString(args['sessionId']), timeout, WALL_CLOCK);
342
374
  // `until` is act_and_wait's name for this — see alias-args.ts.
343
375
  const predicate = parsePredicate(aliasParam(args, 'predicate', ['until'])['predicate']);
344
376
  // Refused up front rather than waited out: a body clause this session cannot answer would
@@ -347,13 +379,34 @@ export const OBSERVE_TOOLS = [
347
379
  if (bodyRefusal !== undefined)
348
380
  throw new Error(bodyRefusal);
349
381
  // Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
350
- const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
382
+ let since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
351
383
  // Declared BEFORE the verdict, so the undeclared-change read below finds it open and stays
352
384
  // quiet on THIS verdict rather than on the next one. Discharged after that read.
353
385
  const intentId = await linkInlineIntent(deps, asString(args['sessionId']), asString(args['intent']), PredicateKind.SETTLED === predicate.kind ? undefined : predicate);
354
- const verdict = timeout > 0
355
- ? await waitForPredicate(session, predicate, timeout, since)
356
- : await evaluatePredicate(session, predicate, since);
386
+ // A full-document navigation tears the in-page SDK down mid-wait, and the predicate finishes
387
+ // `observationLost` against a channel that no longer exists. `act_and_wait` has followed the
388
+ // document that took over since the MPA drive was fixed; this path did not, so an assertion
389
+ // straddling a navigation came back "Reticle could not tell" while the answer was sitting on
390
+ // the successor — reported four times from the field, every one of them proving `yes` on the
391
+ // UNCHANGED predicate after a manual reconnect. Re-asking is not fabricating: the consequence
392
+ // is evaluated on a live document, and where there is no unique successor to follow,
393
+ // `followLostObservation` refuses to guess and the honest lost verdict stands.
394
+ const predicateStarted = session.elapsed();
395
+ const followed = await followLostObservation({
396
+ sessions: deps.sessions,
397
+ session,
398
+ verdict: timeout > 0
399
+ ? await waitForPredicate(session, predicate, timeout, since)
400
+ : await evaluatePredicate(session, predicate, since),
401
+ timeout,
402
+ predicateStarted,
403
+ reevaluate: (next, budget) => waitForPredicate(next, predicate, budget, 0),
404
+ });
405
+ // The successor's buffer is its own: the departed session's cursor means nothing there.
406
+ if (followed.followed)
407
+ since = 0;
408
+ session = followed.session;
409
+ const verdict = followed.verdict;
357
410
  // A GREEN presence-only assertion is the dangerous case (a wrong element can fake it) — nudge
358
411
  // toward a consequence. Never on a failing verdict (moot) or when a signal/net is asserted.
359
412
  // Two nudges, both only on a GREEN verdict (a failing one is moot): a presence-only assertion
@@ -396,6 +449,7 @@ export const OBSERVE_TOOLS = [
396
449
  return withControl(session, {
397
450
  ...decision,
398
451
  ...annotateStarvedFailure(session, verdict),
452
+ ...(followed.followed ? { sessionId: session.id } : {}),
399
453
  ...(contradictions.length > 0 ? { contradictions } : {}),
400
454
  // What the app did not tell Reticle, on the same rule the act path uses.
401
455
  // Remedy once per session, facts every time. Applied HERE rather than inside
@@ -408,7 +462,7 @@ export const OBSERVE_TOOLS = [
408
462
  ...coverage,
409
463
  // The SAME pointer the journal keeps, not a second lookup — one verdict, one file:line.
410
464
  ...(verdictEffect.source === undefined ? {} : { source: verdictEffect.source }),
411
- ...healthEnvelope(session),
465
+ ...healthEnvelope(currentOf(deps.sessions, session)),
412
466
  ...bufferEnvelope(session),
413
467
  });
414
468
  },
@@ -11,7 +11,7 @@
11
11
  * is not advertised on the default surface, so the agent that needed it could not see it and had no
12
12
  * way to learn it existed. A capability reachable only by already knowing about it is not reachable.
13
13
  *
14
- * The SCROLLING half lives in `portal/input/scrolling-find.ts`, because it drives the page and this
14
+ * The SCROLLING half lives in `portal/input/scroll-find.ts`, because it drives the page and this
15
15
  * directory must not reach into `input/` — doing so completed a mutual pair, and two directories
16
16
  * that need each other cannot be read, moved or tested apart. Shaping an answer and scrolling a list
17
17
  * are different jobs anyway; the guard made that visible before it was a habit.
@@ -11,7 +11,7 @@
11
11
  * is not advertised on the default surface, so the agent that needed it could not see it and had no
12
12
  * way to learn it existed. A capability reachable only by already knowing about it is not reachable.
13
13
  *
14
- * The SCROLLING half lives in `portal/input/scrolling-find.ts`, because it drives the page and this
14
+ * The SCROLLING half lives in `portal/input/scroll-find.ts`, because it drives the page and this
15
15
  * directory must not reach into `input/` — doing so completed a mutual pair, and two directories
16
16
  * that need each other cannot be read, moved or tested apart. Shaping an answer and scrolling a list
17
17
  * are different jobs anyway; the guard made that visible before it was a habit.
@@ -14,8 +14,7 @@ import { diffLines } from '../../memory/project/baselines.js';
14
14
  import { selectPath, capDepth, projectComponentState } from '../../portal/session/state-select.js';
15
15
  import { costHint } from '../../portal/session/output-budget.js';
16
16
  import { buildReactionReport, summarizeReaction } from '@reticlehq/engine/question/reaction.js';
17
- import { asNumber, asString } from '@reticlehq/core';
18
- import { parseInteractive } from './tools-helpers.js';
17
+ import { asNumber, asString, parseInteractive } from '@reticlehq/core';
19
18
  import { sessionIdShape, commandOrThrow, snapshotTree } from './tool-kit.js';
20
19
  import { bufferEnvelope } from '../../portal/session/session-health.js';
21
20
  import { routeOfUrl } from '@reticlehq/engine/question/predicate/predicate-route.js';
@@ -22,11 +22,6 @@
22
22
  import { ActionType, InputModeReason } from '@reticlehq/core';
23
23
  import type { Session } from '../../portal/session/session.js';
24
24
  import { type ToolDeps } from './tool-kit.js';
25
- /**
26
- * Expand a leading `~` against the caller's home directory. Absolute and relative paths pass
27
- * through unchanged. `home` is injected so unit tests do not depend on the machine's real home.
28
- */
29
- export declare function expandUserPath(rawPath: string, home: string): string;
30
25
  /**
31
26
  * If the action is `upload` AND the inner args carry `path`, read the file from disk and rewrite
32
27
  * the args to `{ content, name, type, __base64: true }` before the ACT command reaches the browser.
@@ -99,7 +99,7 @@ const UPLOAD_MAX_BYTES = Math.floor((TRANSPORT_LIMITS.MAX_MESSAGE_BYTES / (4 / 3
99
99
  * Expand a leading `~` against the caller's home directory. Absolute and relative paths pass
100
100
  * through unchanged. `home` is injected so unit tests do not depend on the machine's real home.
101
101
  */
102
- export function expandUserPath(rawPath, home) {
102
+ function expandUserPath(rawPath, home) {
103
103
  if ('~' === rawPath)
104
104
  return home;
105
105
  if (rawPath.startsWith('~/') || rawPath.startsWith('~\\'))
@@ -5,7 +5,7 @@
5
5
  * without a circular import — `tools.ts` assembles the groups and re-exports `ToolDef`/`ToolDeps`.
6
6
  */
7
7
  import { z } from 'zod';
8
- import { ReticleCommand } from '@reticlehq/core';
8
+ import { type ProjectId, ReticleCommand } from '@reticlehq/core';
9
9
  import type { SessionManager } from '../../portal/session/session-manager.js';
10
10
  import type { RealInputProvider } from '../../portal/input/real-input.js';
11
11
  import type { BaselineStore } from '../../memory/project/baselines.js';
@@ -33,6 +33,21 @@ export interface ToolDeps<Ext = unknown> {
33
33
  recordings: RecordingStore;
34
34
  /** on-disk anchored-flow store (.reticle/flows/). */
35
35
  flows: FlowStore;
36
+ /**
37
+ * The credential this machine already holds for the linked project, if it is linked.
38
+ *
39
+ * INJECTED rather than read here. `reticle link` files a project-scoped key in
40
+ * `~/.reticle/credentials.json`, and the harness needs it so that somebody who has signed in and
41
+ * linked is not also asked to export a key by hand. Resolving it inside the tool surface would
42
+ * make `tools` reach into `memory/cloud`, which the directory guard refused — and it was right
43
+ * to: this is a port, and the daemon already resolves exactly this for cloud sync.
44
+ *
45
+ * Absent ⇒ nothing is linked, or the caller is an embedder with no filesystem. Never an error.
46
+ */
47
+ linkedCloud?: () => Promise<{
48
+ url: string;
49
+ apiKey: string;
50
+ } | null>;
36
51
  /** structured annotations accumulating for the live recording. */
37
52
  annotations: AnnotationStore;
38
53
  /**
@@ -65,7 +80,7 @@ export interface ToolDeps<Ext = unknown> {
65
80
  * embedding this engine may not have a filesystem to search. Absent ⇒ `reticleRoot`, which is
66
81
  * exactly today's behaviour.
67
82
  */
68
- artifactRootFor?: (projectId: string | undefined) => ArtifactRoot;
83
+ artifactRootFor?: (projectId: ProjectId | undefined) => ArtifactRoot;
69
84
  /**
70
85
  * A verification run just landed — wake cloud sync instead of waiting for its next tick.
71
86
  *
@@ -85,7 +100,7 @@ export interface ToolDeps<Ext = unknown> {
85
100
  * test construction of ToolDeps predates it. Absence means "cannot tell", which must never be
86
101
  * treated as a mismatch.
87
102
  */
88
- projectId?: string;
103
+ projectId?: ProjectId;
89
104
  /** injected clock for the contract's generatedAt stamp. */
90
105
  now: () => number;
91
106
  /**
@@ -207,6 +222,11 @@ export declare const EnvelopeKey: {
207
222
  readonly VERIFY_NEXT: "verify_next";
208
223
  /** The contextual "tell us what just went wrong" invitation. Same story, same release. */
209
224
  readonly FEEDBACK_INVITE: "feedback_invite";
225
+ /**
226
+ * The same moment, for the HUMAN: a call with the founder, or an email through `identify`. The
227
+ * agent is told to offer it and never to book or submit anything itself.
228
+ */
229
+ readonly TALK_TO_US: "talk_to_us";
210
230
  /** SDK/daemon version skew — often the one fact that explains everything else in the session. */
211
231
  readonly VERSION_SKEW: "version_skew";
212
232
  /** A feedback report that was accepted and then failed to send. Only the reporter can act on it. */
@@ -28,7 +28,7 @@ export const intentArg = z
28
28
  'BAD: "P1 step 5", "drive 2 of 2", "same as before the fix", "the board renders cleanly" — these name a session, ' +
29
29
  'a step number or nothing checkable, and the person reading them later has none of that context. ' +
30
30
  'This is shared memory: it is pooled per project and later agents read it back to avoid re-deriving what you just established. ' +
31
- 'Recorded in .reticle/intent.json, the same ledger reticle_intent writes, and marked proved by this verdict if it passes.');
31
+ 'Recorded in .reticle/intent/, the same ledger reticle_intent writes, and marked proved by this verdict if it passes.');
32
32
  export const sessionIdShape = {
33
33
  sessionId: z
34
34
  .string()
@@ -75,6 +75,11 @@ export const EnvelopeKey = {
75
75
  VERIFY_NEXT: 'verify_next',
76
76
  /** The contextual "tell us what just went wrong" invitation. Same story, same release. */
77
77
  FEEDBACK_INVITE: 'feedback_invite',
78
+ /**
79
+ * The same moment, for the HUMAN: a call with the founder, or an email through `identify`. The
80
+ * agent is told to offer it and never to book or submit anything itself.
81
+ */
82
+ TALK_TO_US: 'talk_to_us',
78
83
  /** SDK/daemon version skew — often the one fact that explains everything else in the session. */
79
84
  VERSION_SKEW: 'version_skew',
80
85
  /** A feedback report that was accepted and then failed to send. Only the reporter can act on it. */
@@ -395,11 +395,23 @@ export function describeToolSurface(active, requested) {
395
395
  export function defaultAdvertisedNames() {
396
396
  const surface = resolveToolSurface();
397
397
  const names = [...filterToolNames(surface)];
398
- // `reticle_run` is real only where the surface keeps a dispatch hatch. The merged surface ships
399
- // the catalogue without one, and naming a hatch that is not there is the same defect one level in.
400
- return TOOL_SURFACE.MERGED === surface
401
- ? [...names, ReticleTool.TOOLS]
402
- : [...names, ReticleTool.TOOLS, ReticleTool.RUN];
398
+ /*
399
+ * Both meta tools, on every surface, because that is what the MCP actually advertises.
400
+ *
401
+ * This used to withhold `reticle_run` from the merged surface, reasoning that "naming a hatch
402
+ * that is not there is the same defect one level in". The reasoning is sound and the premise was
403
+ * false: `buildDynamicTools` returns `[reticle_tools, reticle_run]` unconditionally and
404
+ * `advertisedTools` appends both to every surface, so the hatch has always been there. Measured
405
+ * against a live daemon on the default surface: `reticle_run` is advertised, and
406
+ * `reticle_run { tool: "reticle_lease" }` reaches `reticle_lease`.
407
+ *
408
+ * Two functions answering one question, and this was the one the MCP never called. It is read by
409
+ * `server-instructions`, which gates "Everything else is one hop: reticle_tools lists it,
410
+ * reticle_run calls it" on this list - so agents were told the hatch was absent from a surface
411
+ * carrying it, and six recovery messages were later rewritten to match the lie.
412
+ * `advertised-names-are-real.test.ts` now pins this to `advertisedTools` itself.
413
+ */
414
+ return [...names, ReticleTool.TOOLS, ReticleTool.RUN];
403
415
  }
404
416
  /** The advertised NAME set for a surface, without needing the tool table. */
405
417
  function filterToolNames(surface) {
@@ -1,10 +1,12 @@
1
1
  /** Small pure helpers shared by the MCP tool handlers. */
2
- interface InteractiveItem {
3
- ref: string;
4
- desc: string;
5
- }
6
- /** Parse interactive elements (with refs) out of a snapshot tree for exploration. */
7
- export declare function parseInteractive(tree: string): InteractiveItem[];
2
+ /**
3
+ * The argument a call names a tab with.
4
+ *
5
+ * A named constant because dispatch now WRITES this key as well as reading it — see `runTool`,
6
+ * which pins the session it resolved into the args the handler is given — and a key spelled at both
7
+ * ends of that can drift without anything saying so.
8
+ */
9
+ export declare const SESSION_ID_ARG = "sessionId";
8
10
  /**
9
11
  * The session this call is aimed at: a top-level `sessionId`, or the same key on sequence steps.
10
12
  *
@@ -36,4 +38,3 @@ export declare function sourceOf(value: unknown): {
36
38
  line: number;
37
39
  column?: number;
38
40
  } | undefined;
39
- export {};
@@ -1,15 +1,13 @@
1
1
  import { asRecord, asString } from '@reticlehq/core';
2
- /** Parse interactive elements (with refs) out of a snapshot tree for exploration. */
3
- export function parseInteractive(tree) {
4
- const items = [];
5
- for (const line of tree.split('\n')) {
6
- const match = /\(ref=(e\d+)\)/.exec(line);
7
- if (match !== null) {
8
- items.push({ ref: match[1] ?? '', desc: line.replace(/\s*\(ref=e\d+\)/, '').trim() });
9
- }
10
- }
11
- return items;
12
- }
2
+ /** Small pure helpers shared by the MCP tool handlers. */
3
+ /**
4
+ * The argument a call names a tab with.
5
+ *
6
+ * A named constant because dispatch now WRITES this key as well as reading it — see `runTool`,
7
+ * which pins the session it resolved into the args the handler is given — and a key spelled at both
8
+ * ends of that can drift without anything saying so.
9
+ */
10
+ export const SESSION_ID_ARG = 'sessionId';
13
11
  /**
14
12
  * The session this call is aimed at: a top-level `sessionId`, or the same key on sequence steps.
15
13
  *
@@ -21,7 +19,7 @@ export function parseInteractive(tree) {
21
19
  * Mixed step ids refuse rather than pick: two named tabs is a guess we will not make.
22
20
  */
23
21
  export function sessionIdFromArgs(args) {
24
- const top = asString(args['sessionId']);
22
+ const top = asString(args[SESSION_ID_ARG]);
25
23
  if (top !== undefined)
26
24
  return top;
27
25
  const steps = args['steps'];
@@ -29,7 +27,7 @@ export function sessionIdFromArgs(args) {
29
27
  return undefined;
30
28
  let found;
31
29
  for (const raw of steps) {
32
- const id = asString(asRecord(raw)['sessionId']);
30
+ const id = asString(asRecord(raw)[SESSION_ID_ARG]);
33
31
  if (id === undefined)
34
32
  continue;
35
33
  if (found !== undefined && found !== id) {