@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
@@ -52,12 +52,12 @@ declare const IntentRecordSchema: z.ZodObject<{
52
52
  flow: z.ZodOptional<z.ZodString>;
53
53
  files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
54
54
  }, "strip", z.ZodTypeAny, {
55
- route?: string | undefined;
56
55
  flow?: string | undefined;
56
+ route?: string | undefined;
57
57
  files?: string[] | undefined;
58
58
  }, {
59
- route?: string | undefined;
60
59
  flow?: string | undefined;
60
+ route?: string | undefined;
61
61
  files?: string[] | undefined;
62
62
  }>>;
63
63
  provenBy: z.ZodOptional<z.ZodObject<{
@@ -94,15 +94,15 @@ declare const IntentRecordSchema: z.ZodObject<{
94
94
  /** When it was last touched, so a stale-looking record can be told from an untouched one. */
95
95
  updatedAt: z.ZodOptional<z.ZodNumber>;
96
96
  }, "strip", z.ZodTypeAny, {
97
- status: "proved" | "stale" | "proposed" | "agreed";
97
+ status: "proved" | "proposed" | "agreed" | "stale";
98
98
  state: "proved" | "declared" | "bound";
99
99
  id: string;
100
100
  subject: string;
101
101
  statement: string;
102
102
  declaredAt: number;
103
103
  surface?: {
104
- route?: string | undefined;
105
104
  flow?: string | undefined;
105
+ route?: string | undefined;
106
106
  files?: string[] | undefined;
107
107
  } | undefined;
108
108
  source?: string | undefined;
@@ -119,15 +119,15 @@ declare const IntentRecordSchema: z.ZodObject<{
119
119
  statement: string;
120
120
  }[] | undefined;
121
121
  }, {
122
- status: "proved" | "stale" | "proposed" | "agreed";
122
+ status: "proved" | "proposed" | "agreed" | "stale";
123
123
  state: "proved" | "declared" | "bound";
124
124
  id: string;
125
125
  subject: string;
126
126
  statement: string;
127
127
  declaredAt: number;
128
128
  surface?: {
129
- route?: string | undefined;
130
129
  flow?: string | undefined;
130
+ route?: string | undefined;
131
131
  files?: string[] | undefined;
132
132
  } | undefined;
133
133
  source?: string | undefined;
@@ -159,12 +159,12 @@ export declare const IntentShardSchema: z.ZodObject<{
159
159
  flow: z.ZodOptional<z.ZodString>;
160
160
  files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
161
161
  }, "strip", z.ZodTypeAny, {
162
- route?: string | undefined;
163
162
  flow?: string | undefined;
163
+ route?: string | undefined;
164
164
  files?: string[] | undefined;
165
165
  }, {
166
- route?: string | undefined;
167
166
  flow?: string | undefined;
167
+ route?: string | undefined;
168
168
  files?: string[] | undefined;
169
169
  }>>;
170
170
  provenBy: z.ZodOptional<z.ZodObject<{
@@ -201,15 +201,15 @@ export declare const IntentShardSchema: z.ZodObject<{
201
201
  /** When it was last touched, so a stale-looking record can be told from an untouched one. */
202
202
  updatedAt: z.ZodOptional<z.ZodNumber>;
203
203
  }, "strip", z.ZodTypeAny, {
204
- status: "proved" | "stale" | "proposed" | "agreed";
204
+ status: "proved" | "proposed" | "agreed" | "stale";
205
205
  state: "proved" | "declared" | "bound";
206
206
  id: string;
207
207
  subject: string;
208
208
  statement: string;
209
209
  declaredAt: number;
210
210
  surface?: {
211
- route?: string | undefined;
212
211
  flow?: string | undefined;
212
+ route?: string | undefined;
213
213
  files?: string[] | undefined;
214
214
  } | undefined;
215
215
  source?: string | undefined;
@@ -226,15 +226,15 @@ export declare const IntentShardSchema: z.ZodObject<{
226
226
  statement: string;
227
227
  }[] | undefined;
228
228
  }, {
229
- status: "proved" | "stale" | "proposed" | "agreed";
229
+ status: "proved" | "proposed" | "agreed" | "stale";
230
230
  state: "proved" | "declared" | "bound";
231
231
  id: string;
232
232
  subject: string;
233
233
  statement: string;
234
234
  declaredAt: number;
235
235
  surface?: {
236
- route?: string | undefined;
237
236
  flow?: string | undefined;
237
+ route?: string | undefined;
238
238
  files?: string[] | undefined;
239
239
  } | undefined;
240
240
  source?: string | undefined;
@@ -255,15 +255,15 @@ export declare const IntentShardSchema: z.ZodObject<{
255
255
  version: 1;
256
256
  subject: string;
257
257
  intents: Record<string, {
258
- status: "proved" | "stale" | "proposed" | "agreed";
258
+ status: "proved" | "proposed" | "agreed" | "stale";
259
259
  state: "proved" | "declared" | "bound";
260
260
  id: string;
261
261
  subject: string;
262
262
  statement: string;
263
263
  declaredAt: number;
264
264
  surface?: {
265
- route?: string | undefined;
266
265
  flow?: string | undefined;
266
+ route?: string | undefined;
267
267
  files?: string[] | undefined;
268
268
  } | undefined;
269
269
  source?: string | undefined;
@@ -284,15 +284,15 @@ export declare const IntentShardSchema: z.ZodObject<{
284
284
  version: 1;
285
285
  subject: string;
286
286
  intents: Record<string, {
287
- status: "proved" | "stale" | "proposed" | "agreed";
287
+ status: "proved" | "proposed" | "agreed" | "stale";
288
288
  state: "proved" | "declared" | "bound";
289
289
  id: string;
290
290
  subject: string;
291
291
  statement: string;
292
292
  declaredAt: number;
293
293
  surface?: {
294
- route?: string | undefined;
295
294
  flow?: string | undefined;
295
+ route?: string | undefined;
296
296
  files?: string[] | undefined;
297
297
  } | undefined;
298
298
  source?: string | undefined;
@@ -311,7 +311,6 @@ export declare const IntentShardSchema: z.ZodObject<{
311
311
  }>;
312
312
  }>;
313
313
  export type IntentShard = z.infer<typeof IntentShardSchema>;
314
- export declare const summarise: (statement: string) => string;
315
314
  /** One line per intent: enough to decide whether to open the shard, and no more. */
316
315
  declare const IntentIndexEntrySchema: z.ZodObject<{
317
316
  id: z.ZodString;
@@ -319,12 +318,12 @@ declare const IntentIndexEntrySchema: z.ZodObject<{
319
318
  statement: z.ZodString;
320
319
  status: z.ZodEnum<["proposed", "agreed", "proved", "stale"]>;
321
320
  }, "strip", z.ZodTypeAny, {
322
- status: "proved" | "stale" | "proposed" | "agreed";
321
+ status: "proved" | "proposed" | "agreed" | "stale";
323
322
  id: string;
324
323
  subject: string;
325
324
  statement: string;
326
325
  }, {
327
- status: "proved" | "stale" | "proposed" | "agreed";
326
+ status: "proved" | "proposed" | "agreed" | "stale";
328
327
  id: string;
329
328
  subject: string;
330
329
  statement: string;
@@ -338,19 +337,19 @@ export declare const IntentIndexSchema: z.ZodObject<{
338
337
  statement: z.ZodString;
339
338
  status: z.ZodEnum<["proposed", "agreed", "proved", "stale"]>;
340
339
  }, "strip", z.ZodTypeAny, {
341
- status: "proved" | "stale" | "proposed" | "agreed";
340
+ status: "proved" | "proposed" | "agreed" | "stale";
342
341
  id: string;
343
342
  subject: string;
344
343
  statement: string;
345
344
  }, {
346
- status: "proved" | "stale" | "proposed" | "agreed";
345
+ status: "proved" | "proposed" | "agreed" | "stale";
347
346
  id: string;
348
347
  subject: string;
349
348
  statement: string;
350
349
  }>, "many">;
351
350
  }, "strip", z.ZodTypeAny, {
352
351
  entries: {
353
- status: "proved" | "stale" | "proposed" | "agreed";
352
+ status: "proved" | "proposed" | "agreed" | "stale";
354
353
  id: string;
355
354
  subject: string;
356
355
  statement: string;
@@ -358,7 +357,7 @@ export declare const IntentIndexSchema: z.ZodObject<{
358
357
  version: 1;
359
358
  }, {
360
359
  entries: {
361
- status: "proved" | "stale" | "proposed" | "agreed";
360
+ status: "proved" | "proposed" | "agreed" | "stale";
362
361
  id: string;
363
362
  subject: string;
364
363
  statement: string;
@@ -74,7 +74,7 @@ export const IntentShardSchema = z.object({
74
74
  * can do to a file meant to be read every session, which is the reason to keep it.
75
75
  */
76
76
  const SUMMARY_MAX = 72;
77
- export const summarise = (statement) => statement.length <= SUMMARY_MAX ? statement : `${statement.slice(0, SUMMARY_MAX - 1).trimEnd()}…`;
77
+ const summarise = (statement) => statement.length <= SUMMARY_MAX ? statement : `${statement.slice(0, SUMMARY_MAX - 1).trimEnd()}…`;
78
78
  /** One line per intent: enough to decide whether to open the shard, and no more. */
79
79
  const IntentIndexEntrySchema = z.object({
80
80
  id: z.string().min(1),
@@ -1,6 +1,14 @@
1
1
  import { type Intent, type IntentSurface } from '@reticlehq/core/artifacts';
2
2
  import type { FileSystemPort } from '../project/fs/fs-port.js';
3
3
  import type { Clock } from '../../machine/clock.js';
4
+ /**
5
+ * The intent ledger's domain operations: declare, place, bind, discharge.
6
+ *
7
+ * Every operation is a PURE transition from core (`redeclareIntent`, `bindIntent`,
8
+ * `dischargeIntent`) handed to the ledger's atomic upsert. Storage is `IntentShardStore` —
9
+ * `.reticle/intent/<subject>/intent.json`, a flow's name being its subject — and this class writes no
10
+ * file of its own, so there is exactly one place an intent can be.
11
+ */
4
12
  export declare class IntentStore {
5
13
  #private;
6
14
  constructor(fs: FileSystemPort, root: string, clock: Clock);
@@ -12,7 +20,8 @@ export declare class IntentStore {
12
20
  * Declare one or more intents.
13
21
  *
14
22
  * Batched because the marginal cost of the whole mechanism has to stay at one call per feature; an
15
- * agent that must make five calls to declare five things will make none.
23
+ * agent that must make five calls to declare five things will make none. Saying an intent again
24
+ * does not unsay it: see `redeclareIntent` for what survives.
16
25
  */
17
26
  declare(entries: readonly {
18
27
  id: string;
@@ -22,13 +31,9 @@ export declare class IntentStore {
22
31
  /**
23
32
  * File a record under where it turned out to be about.
24
33
  *
25
- * Separate from `declare` because the two happen at different MOMENTS and know different things.
26
- * An inline intent is declared BEFORE the action — deliberately, so a verdict can see it open —
27
- * and at that instant the agent is still on the page it is leaving. The route that describes what
28
- * the intent is ABOUT only exists after the consequence lands.
29
- *
30
- * Write-once: an existing surface is never overwritten. A record placed by an agent that named its
31
- * own subject must not be re-filed by a later run that happened to be somewhere else.
34
+ * Separate from `declare` because an inline intent is declared BEFORE the action, and the route
35
+ * that describes it only exists after the consequence lands. Write-once: an existing surface is
36
+ * never overwritten. A flow named here moves the record into that flow's directory.
32
37
  */
33
38
  place(id: string, surface: IntentSurface): Promise<boolean>;
34
39
  /** Attach the predicate that would prove an intent. False when the id names nothing. */
@@ -1,115 +1,71 @@
1
- import { bindIntent, declareIntent, dischargeIntent, emptyIntentFile, openIntents, parseIntentFile, upsertIntent, } from '@reticlehq/core/artifacts';
2
- import { reticleDirPaths } from '../project/dir/reticle-dir.js';
3
- import { withFileLock } from '../project/file-lock.js';
1
+ import { IntentState, bindIntent, declareIntent, redeclareIntent, dischargeIntent, isActionLabel, } from '@reticlehq/core/artifacts';
2
+ import { IntentShardStore } from './intent-shard-store.js';
3
+ import { IntentStatus } from './intent-shard.js';
4
4
  /**
5
- * The intent ledger on disk — `.reticle/intent.json`, git-checked and meant to be read in review.
5
+ * The intent ledger's domain operations: declare, place, bind, discharge.
6
6
  *
7
- * Git-checked deliberately. The one real defence against an agent quietly narrowing what it meant to
8
- * match what it can already prove is that a human sees the narrowing in a diff, and that only works
9
- * if the file lives with the code and travels with the PR. It is also why the writes are byte-stable:
10
- * a ledger that churns on every run is one whose diffs nobody reads.
11
- *
12
- * Every operation goes through the same file lock the other stores use, because two sessions driving
13
- * one project is ordinary and a lost declaration would be silent.
7
+ * Every operation is a PURE transition from core (`redeclareIntent`, `bindIntent`,
8
+ * `dischargeIntent`) handed to the ledger's atomic upsert. Storage is `IntentShardStore` —
9
+ * `.reticle/intent/<subject>/intent.json`, a flow's name being its subject — and this class writes no
10
+ * file of its own, so there is exactly one place an intent can be.
14
11
  */
15
- const JSON_INDENT = 2;
16
12
  export class IntentStore {
17
- #fs;
18
- #root;
13
+ #ledger;
19
14
  #clock;
20
15
  constructor(fs, root, clock) {
21
- this.#fs = fs;
22
- this.#root = root;
16
+ this.#ledger = new IntentShardStore(fs, root, clock);
23
17
  this.#clock = clock;
24
18
  }
25
- #path() {
26
- return reticleDirPaths(this.#root).intent;
27
- }
28
- /**
29
- * Load the ledger, failing soft to empty.
30
- *
31
- * This is a git-checked file an agent can write and a human can hand-merge, so a malformed one is
32
- * genuinely reachable — a conflict marker left in place is the obvious case. Throwing here would
33
- * take down the verdict that was only asking what was still open, which trades a small problem for
34
- * a large one.
35
- */
36
- async #load() {
37
- try {
38
- const raw = await this.#fs.readFile(this.#path());
39
- return parseIntentFile(JSON.parse(raw));
40
- }
41
- catch {
42
- return emptyIntentFile();
43
- }
44
- }
45
- /** Byte-stable: 2-space indent, one trailing newline. An unchanged ledger produces no diff. */
46
- async #save(file) {
47
- await this.#fs.mkdir(reticleDirPaths(this.#root).root);
48
- await this.#fs.writeFile(this.#path(), `${JSON.stringify(file, null, JSON_INDENT)}\n`);
49
- }
50
19
  /** Every intent, in declaration order. */
51
20
  async read() {
52
- return Object.values((await this.#load()).intents);
21
+ return this.#ledger.all();
53
22
  }
54
23
  /** Everything not yet proved — what an agent asking "am I done?" still owes. */
55
24
  async open() {
56
- return openIntents(await this.#load());
25
+ // Stale is not owed: it is kept as history, not as work.
26
+ return (await this.#ledger.all()).filter((record) => IntentState.PROVED !== record.state && IntentStatus.STALE !== record.status);
57
27
  }
58
28
  /**
59
29
  * Declare one or more intents.
60
30
  *
61
31
  * Batched because the marginal cost of the whole mechanism has to stay at one call per feature; an
62
- * agent that must make five calls to declare five things will make none.
32
+ * agent that must make five calls to declare five things will make none. Saying an intent again
33
+ * does not unsay it: see `redeclareIntent` for what survives.
63
34
  */
64
35
  async declare(entries) {
65
- if (0 === entries.length)
66
- return [];
67
- return withFileLock(this.#path(), async () => {
68
- let file = await this.#load();
69
- const now = this.#clock.now();
70
- const declared = [];
71
- for (const entry of entries) {
72
- const intent = declareIntent({ ...entry, now });
73
- file = upsertIntent(file, intent);
74
- const stored = file.intents[intent.id];
75
- if (stored !== undefined)
76
- declared.push(stored);
77
- }
78
- await this.#save(file);
79
- return declared;
80
- });
36
+ const now = this.#clock.now();
37
+ const declared = [];
38
+ for (const entry of entries) {
39
+ // A step label is a log line, not a rule: every route that declares comes through here.
40
+ if (isActionLabel(entry.statement))
41
+ continue;
42
+ const stored = await this.#ledger.upsert(entry.id, (existing) => redeclareIntent(existing, declareIntent({ ...entry, now })));
43
+ if (stored !== undefined)
44
+ declared.push(stored);
45
+ }
46
+ return declared;
81
47
  }
82
48
  /**
83
49
  * File a record under where it turned out to be about.
84
50
  *
85
- * Separate from `declare` because the two happen at different MOMENTS and know different things.
86
- * An inline intent is declared BEFORE the action — deliberately, so a verdict can see it open —
87
- * and at that instant the agent is still on the page it is leaving. The route that describes what
88
- * the intent is ABOUT only exists after the consequence lands.
89
- *
90
- * Write-once: an existing surface is never overwritten. A record placed by an agent that named its
91
- * own subject must not be re-filed by a later run that happened to be somewhere else.
51
+ * Separate from `declare` because an inline intent is declared BEFORE the action, and the route
52
+ * that describes it only exists after the consequence lands. Write-once: an existing surface is
53
+ * never overwritten. A flow named here moves the record into that flow's directory.
92
54
  */
93
55
  async place(id, surface) {
94
- return withFileLock(this.#path(), async () => {
95
- const file = await this.#load();
96
- const existing = file.intents[id];
56
+ let placed = false;
57
+ await this.#ledger.upsert(id, (existing) => {
97
58
  if (existing === undefined || existing.surface !== undefined)
98
- return false;
99
- await this.#save(upsertIntent(file, { ...existing, surface }));
100
- return true;
59
+ return undefined;
60
+ placed = true;
61
+ return { ...existing, surface };
101
62
  });
63
+ return placed;
102
64
  }
103
65
  /** Attach the predicate that would prove an intent. False when the id names nothing. */
104
66
  async bind(id, binding) {
105
- return withFileLock(this.#path(), async () => {
106
- const file = await this.#load();
107
- const existing = file.intents[id];
108
- if (existing === undefined)
109
- return false;
110
- await this.#save(upsertIntent(file, bindIntent(existing, binding)));
111
- return true;
112
- });
67
+ const stored = await this.#ledger.upsert(id, (existing) => existing === undefined ? undefined : bindIntent(existing, binding));
68
+ return stored !== undefined;
113
69
  }
114
70
  /**
115
71
  * Record that a verdict proved an intent.
@@ -118,16 +74,16 @@ export class IntentStore {
118
74
  * and must never be the reason one fails to return.
119
75
  */
120
76
  async discharge(id, proof) {
121
- return withFileLock(this.#path(), async () => {
122
- const file = await this.#load();
123
- const existing = file.intents[id];
77
+ let proved = false;
78
+ await this.#ledger.upsert(id, (existing) => {
124
79
  if (existing === undefined)
125
- return false;
126
- const proved = dischargeIntent(existing, proof);
127
- if (proved === existing)
128
- return false;
129
- await this.#save(upsertIntent(file, proved));
130
- return true;
80
+ return undefined;
81
+ const next = dischargeIntent(existing, proof);
82
+ if (next === existing)
83
+ return undefined;
84
+ proved = true;
85
+ return next;
131
86
  });
87
+ return proved;
132
88
  }
133
89
  }
@@ -4,8 +4,10 @@ import { IntentShardStore } from './intent-shard-store.js';
4
4
  import { IntentStatus } from './intent-shard.js';
5
5
  import { ReticleTool } from '@reticlehq/core';
6
6
  import { sessionIdShape } from '../../surface/tools/tool-kit.js';
7
+ import { PredicateSchema } from '@reticlehq/engine/question/predicate/predicate.js';
7
8
  import { sessionRoot } from '../project/session-root.js';
8
9
  import { asString } from '@reticlehq/core';
10
+ import { isActionLabel } from '@reticlehq/core/artifacts';
9
11
  /**
10
12
  * Declare what a change was SUPPOSED to make true, while somebody still knows.
11
13
  *
@@ -24,11 +26,13 @@ const INDEX = 'index';
24
26
  const SUBJECT = 'subject';
25
27
  const GET = 'get';
26
28
  const RECORD = 'record';
29
+ /** Why a step label is not stored, in words that say what to write instead. */
30
+ const STEP_LABEL_REFUSAL = 'describes a step that was done, not what must be true. State the rule, e.g. "saving the form shows the new row in the list"';
27
31
  const MIGRATE = 'migrate';
28
32
  export const INTENT_TOOLS = [
29
33
  {
30
34
  name: ReticleTool.INTENT,
31
- description: 'Record what a change is SUPPOSED to make true, as a durable statement ABOUT THE PRODUCT that a teammate who was not here will understand in six months — name the behaviour, not this run or its step number, and never "renders cleanly", which nothing can check. It is SHARED memory: pooled per project and read back by later agents. Capture it while you still know — then verification does not have to re-derive it from the DOM later. { action:"declare", intents:[{ id, statement, surface? }] } takes prose and needs NO predicate: at declare time there is often no route, no ref and no code yet, and a predicate demanded there is just a mechanism. Declare EARLY (as you build) and batch them — one call per feature is the whole budget. { action:"bind", id, binding } attaches the predicate that would prove it once you know how; an intent with no binding is not a failure, it is the most interesting row in the ledger — something meant that nothing can currently prove. { action:"list" } returns what is still open. Stored in .reticle/intent.json, git-checked so a human sees in review if an intent was later narrowed to match what was easy to prove.',
35
+ description: 'Record what a change is SUPPOSED to make true, as a durable statement ABOUT THE PRODUCT that a teammate who was not here will understand in six months — name the behaviour, not this run or its step number, and never "renders cleanly", which nothing can check. It is SHARED memory: pooled per project and read back by later agents. Capture it while you still know — then verification does not have to re-derive it from the DOM later. { action:"declare", intents:[{ id, statement, surface? }] } takes prose and needs NO predicate: at declare time there is often no route, no ref and no code yet, and a predicate demanded there is just a mechanism. Declare EARLY (as you build) and batch them — one call per feature is the whole budget. { action:"bind", id, binding } attaches the predicate that would prove it once you know how; an intent with no binding is not a failure, it is the most interesting row in the ledger — something meant that nothing can currently prove. { action:"list" } returns what is still open. Stored in .reticle/intent/<subject>/intent.json (a flow name is its subject), git-checked so a human sees in review if an intent was later narrowed to match what was easy to prove.',
32
36
  example: {
33
37
  action: DECLARE,
34
38
  intents: [
@@ -56,8 +60,8 @@ export const INTENT_TOOLS = [
56
60
  .describe('record only: how settled it is. Defaults to proposed.'),
57
61
  intents: z
58
62
  .array(z.object({
59
- id: z.string(),
60
- statement: z.string(),
63
+ id: z.string().min(1),
64
+ statement: z.string().min(1),
61
65
  surface: z
62
66
  .object({
63
67
  route: z.string().optional(),
@@ -69,10 +73,19 @@ export const INTENT_TOOLS = [
69
73
  .optional()
70
74
  .describe('declare only. Batchable — declare every intent for a feature in one call.'),
71
75
  id: z.string().optional().describe('bind only: which intent the predicate proves.'),
72
- binding: z
73
- .unknown()
74
- .optional()
75
- .describe("bind only: the predicate that would prove it, in reticle_assert's shape."),
76
+ /*
77
+ * The predicate schema, not `unknown`.
78
+ *
79
+ * The description has always said "in reticle_assert's shape" and the type said "anything",
80
+ * so a client reading the surface to build this call learned the field's name and nothing
81
+ * else — the same degradation the recursive `until` predicate suffered when it was converted
82
+ * without the SDK's own options. This one was not a converter bug: it was declared that way.
83
+ * Caught by `weakest-client-schemas.test.ts`, which is the first thing that ever looked.
84
+ *
85
+ * Accepting the real shape also means a malformed binding is refused at the boundary instead
86
+ * of being written into the ledger and failing later against a verdict it can never satisfy.
87
+ */
88
+ binding: PredicateSchema.optional().describe("bind only: the predicate that would prove it, in reticle_assert's shape."),
76
89
  ...sessionIdShape,
77
90
  },
78
91
  outputSchema: {
@@ -81,6 +94,10 @@ export const INTENT_TOOLS = [
81
94
  .optional()
82
95
  .describe('The intents this call declared, or on `list` everything still open — each { id, statement, state, declaredAt, binding?, surface?, provenBy?, amended? }. `state` is declared (prose only), bound (a predicate exists), or proved (a verdict satisfied it).'),
83
96
  bound: z.boolean().optional().describe('bind only: false when the id names no intent.'),
97
+ refused: z
98
+ .array(z.object({ id: z.string(), reason: z.string() }))
99
+ .optional()
100
+ .describe('declare only: statements not stored, and why.'),
84
101
  path: z.string().optional().describe('Where the ledger was written.'),
85
102
  entries: z
86
103
  .array(z.unknown())
@@ -130,28 +147,22 @@ export const INTENT_TOOLS = [
130
147
  return { bound: await store.bind(id, args['binding']) };
131
148
  }
132
149
  if (LIST === action) {
133
- /*
134
- * Both files, one answer.
135
- *
136
- * `declare` writes the flat `.reticle/intent.json`; `record` writes the sharded
137
- * `.reticle/intent/`. Listing only the flat one meant a recorded intent could not be found
138
- * again by the agent that had just written it — and the lesson an agent draws from that is
139
- * "the intent does not exist", not "there are two stores".
140
- *
141
- * Merged HERE rather than inside either store: this tool is the one seam that knows both
142
- * exist, and neither store should have to learn the other's layout to stay honest.
143
- */
144
- const flat = await store.open();
145
- const seen = new Set(flat.map((intent) => intent.id));
146
- const fromShards = (await shards.all()).filter((record) => !seen.has(record.id));
147
- return { intents: [...flat, ...fromShards] };
150
+ // One ledger, so one read. This merged two stores while `declare` and `record` wrote two
151
+ // different files; kept past that, it would add back every PROVED intent to a list that
152
+ // promises only what is still open.
153
+ return { intents: await store.open() };
148
154
  }
149
155
  const raw = args['intents'];
150
156
  const entries = Array.isArray(raw)
151
157
  ? raw
152
158
  : [];
153
159
  const declared = await store.declare(entries);
154
- return { intents: declared, path: root };
160
+ // Said, not swallowed: an agent that declared something and finds nothing stored would
161
+ // otherwise conclude the ledger lost it.
162
+ const refused = entries
163
+ .filter((entry) => isActionLabel(entry.statement))
164
+ .map((entry) => ({ id: entry.id, reason: STEP_LABEL_REFUSAL }));
165
+ return { intents: declared, ...(0 === refused.length ? {} : { refused }), path: root };
155
166
  },
156
167
  },
157
168
  ];
@@ -1,4 +1,5 @@
1
1
  import { dirname } from 'node:path';
2
+ import { writeFileAtomic } from '../project/fs/write-atomic.js';
2
3
  import { reticleDirPaths } from '../project/dir/reticle-dir.js';
3
4
  import { AmbientFileSchema } from './on-disk/ambient-file.js';
4
5
  import { onlyStableAmbient } from '@reticlehq/engine/window/ambient.js';
@@ -45,8 +46,6 @@ export class AmbientStore {
45
46
  // numbering, so persisting it teaches the next session to suppress an element it never saw.
46
47
  const regions = onlyStableAmbient(counts);
47
48
  const body = `${JSON.stringify({ version: AMBIENT_FILE_VERSION, regions }, null, 2)}\n`;
48
- const tmp = `${this.#path}.tmp`;
49
- await this.#fs.writeFile(tmp, body);
50
- await this.#fs.rename(tmp, this.#path);
49
+ await writeFileAtomic(this.#fs, this.#path, body);
51
50
  }
52
51
  }
@@ -3,6 +3,17 @@ import { JournalRecorder, type JournalReader } from './journal-recorder.js';
3
3
  /** The minimal Session surface the journal attachment needs (Session satisfies it structurally). */
4
4
  export interface JournalTarget {
5
5
  readonly id: string;
6
+ /**
7
+ * The `.reticle` this session's artifacts belong in, stamped on session-create before this runs.
8
+ *
9
+ * The journal used to go to the daemon's own root — wherever the agent was launched — while the
10
+ * run artifact written at teardown already used this one. The journal is the worse half to
11
+ * misroute: it carries URLs, request and response bodies and DOM text from the app under test, so
12
+ * a daemon started in a backend wrote that app's traffic into a repository nobody instrumented,
13
+ * and the `.reticle/.gitignore` meant to keep journals out of a shared repo was being written into
14
+ * the OTHER tree. Undefined only when no project could be resolved, which keeps the old fallback.
15
+ */
16
+ readonly artifactRoot?: string | undefined;
6
17
  /** Milliseconds since the session connected — the recorder's injected clock. */
7
18
  elapsed(): number;
8
19
  setJournal(recorder: JournalRecorder, reader?: JournalReader): void;
@@ -19,7 +19,7 @@ export function makeJournalAttach(deps) {
19
19
  log('journal_skipped_unsafe_session_id', { sessionId: session.id });
20
20
  return;
21
21
  }
22
- const journal = new SessionJournal(deps.fs, deps.reticleRoot, session.id);
22
+ const journal = new SessionJournal(deps.fs, session.artifactRoot ?? deps.reticleRoot, session.id);
23
23
  // Same SessionJournal is both the write sink and the read fall-through for queries after eviction.
24
24
  session.setJournal(new JournalRecorder(journal, { now: () => session.elapsed() }), journal);
25
25
  };
@@ -1,3 +1,4 @@
1
+ import { routeTemplate } from './route-template.js';
1
2
  import { compareSegment, MIN_ENVELOPE_SAMPLES, } from './envelope.js';
2
3
  function headlineFor(report) {
3
4
  const truncNote = report.truncatedSegments > 0
@@ -31,7 +32,9 @@ export function buildDeviationReport(envelopes, segments, zThreshold) {
31
32
  truncated += 1;
32
33
  continue;
33
34
  }
34
- const envelope = envelopes.get(segment.route);
35
+ // The SAME key the service accumulates under — a lookup on the observed path would miss every
36
+ // envelope on an app with ids in its URLs, which is the case this templating exists for.
37
+ const envelope = envelopes.get(routeTemplate(segment.route));
35
38
  if (envelope === undefined || envelope.samples < MIN_ENVELOPE_SAMPLES)
36
39
  continue;
37
40
  judged += 1;
@@ -1,3 +1,4 @@
1
+ import { routeTemplate } from './route-template.js';
1
2
  import { addSegmentToEnvelope, emptyEnvelope } from './envelope.js';
2
3
  import { buildDeviationReport } from './deviation-report.js';
3
4
  import { withFileLock } from '../project/file-lock.js';
@@ -22,8 +23,15 @@ export async function reportAndAccumulate(store, segments, zThreshold) {
22
23
  // Never learn from a truncated sample — its understated counts would poison the baseline.
23
24
  if (true === segment.truncated)
24
25
  continue;
25
- const current = envelopes.get(segment.route) ?? emptyEnvelope(segment.route);
26
- envelopes.set(segment.route, addSegmentToEnvelope(current, segment));
26
+ /*
27
+ * Keyed on the route TEMPLATE, not the observed path. Keyed on the path, an app with ids in
28
+ * its URLs mints one envelope per id, every envelope holds a single sample, and nothing ever
29
+ * reaches MIN_ENVELOPE_SAMPLES — so the deviation report answers "envelope too new" forever
30
+ * and the feature never turns on. See route-template.ts.
31
+ */
32
+ const key = routeTemplate(segment.route);
33
+ const current = envelopes.get(key) ?? emptyEnvelope(key);
34
+ envelopes.set(key, addSegmentToEnvelope(current, segment));
27
35
  }
28
36
  await store.save(envelopes);
29
37
  return report;
@@ -1,4 +1,4 @@
1
- import type { FlowExpect, FlowName } from '@reticlehq/core';
1
+ import type { FlowName, Predicate } from '@reticlehq/core';
2
2
  /**
3
3
  * What this module needs a recorded step to BE, named structurally rather than imported.
4
4
  *
@@ -12,7 +12,7 @@ export interface TapeStep {
12
12
  tool: string;
13
13
  args: Record<string, unknown>;
14
14
  stable: boolean;
15
- expect?: FlowExpect;
15
+ expect?: Predicate;
16
16
  /** Recorder-internal, and the field journeys are cut on. Never written to the saved flow. */
17
17
  route?: string;
18
18
  }