@reticlehq/server 3.2.0 → 3.4.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 (437) hide show
  1. package/LICENSE-ENTERPRISE +1 -1
  2. package/README.md +3 -3
  3. package/SKILL.md +23 -22
  4. package/dist/chromium-launch-options.d.ts +4 -3
  5. package/dist/chromium-launch-options.js +6 -2
  6. package/dist/command/cli/adhoc-suite.d.ts +41 -0
  7. package/dist/command/cli/adhoc-suite.js +159 -0
  8. package/dist/command/cli/adhoc-verdict.d.ts +58 -2
  9. package/dist/command/cli/adhoc-verdict.js +108 -13
  10. package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
  11. package/dist/command/cli/answers/gate-hook-message.js +6 -0
  12. package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
  13. package/dist/command/cli/auth/cloud-keystore.js +0 -3
  14. package/dist/command/cli/auth/cloud-session.d.ts +4 -0
  15. package/dist/command/cli/auth/cloud-session.js +2 -0
  16. package/dist/command/cli/cli-doctor.js +30 -8
  17. package/dist/command/cli/cli-flow-commands.d.ts +3 -6
  18. package/dist/command/cli/cli-flow-commands.js +67 -4
  19. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  20. package/dist/command/cli/cli-parse-grammar.js +7 -0
  21. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  22. package/dist/command/cli/cli-parse-verify.js +86 -13
  23. package/dist/command/cli/cli-parse.d.ts +14 -1
  24. package/dist/command/cli/cli-parse.js +54 -8
  25. package/dist/command/cli/cli-update-commands.js +8 -1
  26. package/dist/command/cli/cli-verify.d.ts +80 -0
  27. package/dist/command/cli/cli-verify.js +181 -26
  28. package/dist/command/cli/cloud-cli.js +5 -2
  29. package/dist/command/cli/cloud-kit.d.ts +0 -2
  30. package/dist/command/cli/cloud-kit.js +3 -5
  31. package/dist/command/cli/cloud-login.js +21 -3
  32. package/dist/command/cli/demo/demo-page.js +6 -3
  33. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
  34. package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
  35. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  36. package/dist/command/cli/launch/cli-launch.d.ts +9 -29
  37. package/dist/command/cli/launch/cli-launch.js +27 -49
  38. package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
  39. package/dist/command/cli/launch/sdk-version-match.js +206 -0
  40. package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
  41. package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
  42. package/dist/command/cli/ports/resolve/cli-port.js +169 -15
  43. package/dist/command/cli/report-command.d.ts +16 -0
  44. package/dist/command/cli/report-command.js +97 -0
  45. package/dist/command/cli/setup-mcp-cli.js +13 -13
  46. package/dist/command/cli/tutorial.d.ts +2 -2
  47. package/dist/command/cli/tutorial.js +21 -7
  48. package/dist/command/cli.js +67 -10
  49. package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
  50. package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
  51. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  52. package/dist/command/daemon/daemon-resolve.d.ts +9 -0
  53. package/dist/command/daemon/daemon-resolve.js +1 -1
  54. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  55. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
  56. package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
  57. package/dist/command/dev/stale-issue-guard.d.ts +3 -4
  58. package/dist/command/dev/stale-issue-guard.js +8 -8
  59. package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
  60. package/dist/command/setup/bringup/connect-lease.js +38 -0
  61. package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
  62. package/dist/command/setup/bringup/dev-server-files.js +131 -0
  63. package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
  64. package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
  65. package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
  66. package/dist/command/setup/bringup/ensure-daemon.js +135 -16
  67. package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
  68. package/dist/command/setup/bringup/static-page-server.js +151 -0
  69. package/dist/command/setup/desktop-shape.d.ts +4 -0
  70. package/dist/command/setup/desktop-shape.js +18 -2
  71. package/dist/command/setup/init/init-host.js +8 -0
  72. package/dist/command/setup/init/init-port.d.ts +15 -0
  73. package/dist/command/setup/init/init-port.js +44 -0
  74. package/dist/command/setup/init/init-runtime.d.ts +1 -1
  75. package/dist/command/setup/init/init-runtime.js +39 -2
  76. package/dist/command/setup/node-effects.d.ts +27 -14
  77. package/dist/command/setup/node-effects.js +80 -44
  78. package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
  79. package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
  80. package/dist/command/setup/probe/page-probe.d.ts +13 -2
  81. package/dist/command/setup/probe/page-probe.js +18 -3
  82. package/dist/command/setup/run-setup.d.ts +26 -1
  83. package/dist/command/setup/run-setup.js +96 -13
  84. package/dist/command/setup/session-pick.d.ts +13 -0
  85. package/dist/command/setup/session-pick.js +20 -0
  86. package/dist/command/setup/setup-command.d.ts +2 -14
  87. package/dist/command/setup/setup-command.js +105 -31
  88. package/dist/command/setup/setup-mcp.js +3 -3
  89. package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
  90. package/dist/command/setup/terminal/wait-progress.js +17 -0
  91. package/dist/features/crawl/crawl-empty.js +1 -1
  92. package/dist/features/crawl/crawl-tools.d.ts +6 -0
  93. package/dist/features/crawl/crawl-tools.js +57 -0
  94. package/dist/features/crawl/crawl.d.ts +2 -0
  95. package/dist/features/crawl/crawl.js +171 -156
  96. package/dist/features/exhaust/app-coverage.d.ts +33 -0
  97. package/dist/features/exhaust/app-coverage.js +31 -0
  98. package/dist/features/exhaust/code-coverage.d.ts +47 -0
  99. package/dist/features/exhaust/code-coverage.js +77 -0
  100. package/dist/features/exhaust/exhaust-run.d.ts +33 -0
  101. package/dist/features/exhaust/exhaust-run.js +82 -0
  102. package/dist/features/exhaust/explorer.d.ts +103 -0
  103. package/dist/features/exhaust/explorer.js +195 -0
  104. package/dist/features/exhaust/failure-branches.d.ts +33 -0
  105. package/dist/features/exhaust/failure-branches.js +92 -0
  106. package/dist/features/exhaust/ledger.d.ts +202 -0
  107. package/dist/features/exhaust/ledger.js +252 -0
  108. package/dist/features/exhaust/session-fold.d.ts +31 -0
  109. package/dist/features/exhaust/session-fold.js +79 -0
  110. package/dist/features/exhaust/session-port.d.ts +36 -0
  111. package/dist/features/exhaust/session-port.js +102 -0
  112. package/dist/features/harness/drive-report.d.ts +0 -9
  113. package/dist/features/harness/drive-report.js +18 -0
  114. package/dist/features/harness/driver.js +4 -7
  115. package/dist/features/harness/fill-values.d.ts +6 -0
  116. package/dist/features/harness/fill-values.js +3 -0
  117. package/dist/features/harness/jev-driver.js +36 -22
  118. package/dist/features/harness/openai-driver.js +4 -7
  119. package/dist/features/harness/platform-config.d.ts +10 -0
  120. package/dist/features/harness/platform-config.js +13 -6
  121. package/dist/index.d.ts +10 -1
  122. package/dist/index.js +78 -104
  123. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  124. package/dist/judgement/capsule/capsule-store.js +58 -6
  125. package/dist/judgement/capsule/capsule.js +5 -0
  126. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  127. package/dist/judgement/capsule/causal-summary.js +7 -0
  128. package/dist/judgement/domain/domain-model.js +40 -9
  129. package/dist/judgement/oracles/self-instrument.js +4 -2
  130. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  131. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  132. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  133. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  134. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  135. package/dist/judgement/runs/artifact/render-report.js +4 -1
  136. package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
  137. package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
  138. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  139. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  140. package/dist/judgement/runs/context-tools.js +21 -3
  141. package/dist/judgement/runs/drive-run.js +7 -2
  142. package/dist/judgement/runs/verification-sync.d.ts +3 -1
  143. package/dist/judgement/runs/verification-sync.js +1 -1
  144. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  145. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  146. package/dist/language/flows/change/affected.d.ts +9 -0
  147. package/dist/language/flows/change/affected.js +35 -0
  148. package/dist/language/flows/change/gate.d.ts +20 -0
  149. package/dist/language/flows/change/gate.js +12 -1
  150. package/dist/language/flows/flow-anchor.d.ts +12 -0
  151. package/dist/language/flows/flow-anchor.js +20 -0
  152. package/dist/language/flows/flow-author.d.ts +7 -0
  153. package/dist/language/flows/flow-author.js +19 -0
  154. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  155. package/dist/language/flows/flow-expect-grammar.js +92 -11
  156. package/dist/language/flows/flow-intent.js +1 -1
  157. package/dist/language/flows/flow-journey.d.ts +54 -0
  158. package/dist/language/flows/flow-journey.js +119 -0
  159. package/dist/language/flows/flow-learning.d.ts +3 -0
  160. package/dist/language/flows/flow-learning.js +39 -8
  161. package/dist/language/flows/flow-replay-run.d.ts +33 -12
  162. package/dist/language/flows/flow-replay-run.js +131 -52
  163. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  164. package/dist/language/flows/flow-replay.d.ts +27 -12
  165. package/dist/language/flows/flow-replay.js +127 -111
  166. package/dist/language/flows/flow-result.d.ts +2 -0
  167. package/dist/language/flows/flow-result.js +25 -0
  168. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  169. package/dist/language/flows/flow-step-runners.js +20 -4
  170. package/dist/language/flows/flow-success.d.ts +21 -6
  171. package/dist/language/flows/flow-success.js +50 -138
  172. package/dist/language/flows/flow-tools.js +17 -5
  173. package/dist/language/flows/flows.d.ts +18 -5
  174. package/dist/language/flows/flows.js +101 -16
  175. package/dist/language/flows/heal.d.ts +9 -1
  176. package/dist/language/flows/heal.js +24 -2
  177. package/dist/language/flows/learned-sources.d.ts +21 -0
  178. package/dist/language/flows/learned-sources.js +84 -0
  179. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  180. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  181. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  182. package/dist/language/flows/recording/replay-halt.js +3 -1
  183. package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
  184. package/dist/language/flows/recording/tape/recordings.js +55 -1
  185. package/dist/language/flows/replay.d.ts +19 -0
  186. package/dist/language/flows/replay.js +53 -13
  187. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  188. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  189. package/dist/language/flows/stores/flake-store.js +2 -3
  190. package/dist/language/flows/suite/coverage.d.ts +1 -1
  191. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  192. package/dist/language/flows/verify-change-tools.js +19 -2
  193. package/dist/launch-chromium.d.ts +80 -0
  194. package/dist/launch-chromium.js +218 -0
  195. package/dist/memory/cloud/cloud-config.d.ts +11 -2
  196. package/dist/memory/cloud/cloud-config.js +47 -7
  197. package/dist/memory/cloud/cloud-sync.d.ts +4 -3
  198. package/dist/memory/cloud/cloud-sync.js +7 -10
  199. package/dist/memory/cloud/harness-config.d.ts +2 -0
  200. package/dist/memory/cloud/harness-offer.js +5 -6
  201. package/dist/memory/cloud/harness-switch.js +5 -6
  202. package/dist/memory/cloud/sync-cycle.d.ts +78 -1
  203. package/dist/memory/cloud/sync-cycle.js +321 -53
  204. package/dist/memory/cloud/sync-daemon.d.ts +13 -0
  205. package/dist/memory/cloud/sync-daemon.js +45 -20
  206. package/dist/memory/cloud/sync-disk.js +27 -8
  207. package/dist/memory/impact/impact-store.js +6 -0
  208. package/dist/memory/intent/inline-intent.js +8 -3
  209. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  210. package/dist/memory/intent/intent-shard-store.js +252 -140
  211. package/dist/memory/intent/intent-shard.d.ts +0 -23
  212. package/dist/memory/intent/intent-shard.js +1 -11
  213. package/dist/memory/intent/intent-store.d.ts +13 -8
  214. package/dist/memory/intent/intent-store.js +46 -90
  215. package/dist/memory/intent/intent-tools.js +34 -23
  216. package/dist/memory/journal/ambient-store.js +2 -3
  217. package/dist/memory/journal/deviation-report.js +4 -1
  218. package/dist/memory/journal/deviation-service.js +10 -2
  219. package/dist/memory/journal/drive-flow.d.ts +19 -14
  220. package/dist/memory/journal/drive-flow.js +65 -48
  221. package/dist/memory/journal/envelope-store.js +2 -3
  222. package/dist/memory/journal/journal-recorder.d.ts +21 -0
  223. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  224. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  225. package/dist/memory/journal/on-disk/retention.d.ts +14 -10
  226. package/dist/memory/journal/on-disk/retention.js +13 -12
  227. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  228. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  229. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
  230. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
  231. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  232. package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
  233. package/dist/memory/journal/route-template.d.ts +22 -0
  234. package/dist/memory/journal/route-template.js +44 -0
  235. package/dist/memory/journal/session-end.d.ts +13 -2
  236. package/dist/memory/journal/session-end.js +88 -18
  237. package/dist/memory/journal/session-journal.d.ts +8 -1
  238. package/dist/memory/journal/session-journal.js +10 -0
  239. package/dist/memory/project/baselines.d.ts +1 -1
  240. package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
  241. package/dist/memory/project/dir/reticle-dir.js +1 -0
  242. package/dist/memory/project/fs/fs-port.js +44 -5
  243. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  244. package/dist/memory/project/fs/write-atomic.js +48 -0
  245. package/dist/memory/project/project-tools.js +3 -1
  246. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  247. package/dist/memory/recall/prior/connection-memory.js +8 -0
  248. package/dist/memory/recall/registered-projects.d.ts +2 -1
  249. package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
  250. package/dist/portal/bridge/auth-failure-reason.js +9 -4
  251. package/dist/portal/bridge/bridge.d.ts +8 -0
  252. package/dist/portal/bridge/bridge.js +43 -2
  253. package/dist/portal/input/js-coverage.d.ts +25 -0
  254. package/dist/portal/input/js-coverage.js +30 -0
  255. package/dist/portal/input/real-input.d.ts +11 -0
  256. package/dist/portal/input/real-input.js +31 -5
  257. package/dist/portal/pool/browser-pool.d.ts +10 -0
  258. package/dist/portal/pool/browser-pool.js +10 -0
  259. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  260. package/dist/portal/pool/playwright-launcher.js +21 -13
  261. package/dist/portal/pool/pool-contract.d.ts +2 -0
  262. package/dist/portal/pool/storage-seed.d.ts +2 -1
  263. package/dist/portal/pool/zero-install.d.ts +27 -0
  264. package/dist/portal/pool/zero-install.js +54 -0
  265. package/dist/portal/realm/web-realm.js +6 -0
  266. package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
  267. package/dist/portal/session/dev-server/dev-command.js +30 -12
  268. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  269. package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
  270. package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
  271. package/dist/portal/session/dev-server/route-status-probe.js +57 -0
  272. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  273. package/dist/portal/session/dev-server/served-document.js +57 -0
  274. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  275. package/dist/portal/session/facts/background-traffic.js +25 -0
  276. package/dist/portal/session/facts/observed-state.d.ts +11 -0
  277. package/dist/portal/session/facts/observed-state.js +34 -0
  278. package/dist/portal/session/live-control-tools.js +48 -3
  279. package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
  280. package/dist/portal/session/no-session-diagnosis.js +62 -5
  281. package/dist/portal/session/no-session-next-action.d.ts +13 -0
  282. package/dist/portal/session/no-session-next-action.js +48 -9
  283. package/dist/portal/session/no-session-watch.d.ts +18 -0
  284. package/dist/portal/session/no-session-watch.js +88 -2
  285. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  286. package/dist/portal/session/session-health.d.ts +61 -0
  287. package/dist/portal/session/session-health.js +43 -3
  288. package/dist/portal/session/session-info.d.ts +6 -0
  289. package/dist/portal/session/session-manager.d.ts +29 -6
  290. package/dist/portal/session/session-manager.js +42 -5
  291. package/dist/portal/session/session-reaper.d.ts +28 -0
  292. package/dist/portal/session/session-reaper.js +49 -1
  293. package/dist/portal/session/session-successor.d.ts +11 -0
  294. package/dist/portal/session/session-successor.js +14 -1
  295. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  296. package/dist/portal/session/session-verdict-facts.js +15 -0
  297. package/dist/portal/session/session.d.ts +10 -0
  298. package/dist/portal/session/session.js +34 -26
  299. package/dist/surface/http-server.d.ts +2 -1
  300. package/dist/surface/http-server.js +4 -2
  301. package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
  302. package/dist/surface/mcp/mcp-proxy.js +5 -5
  303. package/dist/surface/mcp/mcp.js +4 -2
  304. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
  305. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
  306. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  307. package/dist/surface/mcp/server-instructions.js +21 -8
  308. package/dist/surface/tools/act/after-match.d.ts +17 -0
  309. package/dist/surface/tools/act/after-match.js +30 -0
  310. package/dist/surface/tools/act/already-true.d.ts +40 -0
  311. package/dist/surface/tools/act/already-true.js +36 -0
  312. package/dist/surface/tools/act/durable.d.ts +69 -0
  313. package/dist/surface/tools/act/durable.js +139 -0
  314. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
  315. package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
  316. package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
  317. package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
  318. package/dist/surface/tools/act/proved-controls.d.ts +9 -0
  319. package/dist/surface/tools/act/proved-controls.js +11 -0
  320. package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
  321. package/dist/surface/tools/act/sequence-grade.js +32 -1
  322. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  323. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  324. package/dist/surface/tools/act-capsule.d.ts +7 -0
  325. package/dist/surface/tools/act-capsule.js +68 -8
  326. package/dist/surface/tools/act-sequence-tool.js +25 -8
  327. package/dist/surface/tools/act-tools.js +51 -74
  328. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  329. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  330. package/dist/surface/tools/assert/assert-grade.js +26 -3
  331. package/dist/surface/tools/assert/assert-verdict.js +32 -6
  332. package/dist/surface/tools/browser-tools.js +17 -4
  333. package/dist/surface/tools/coverage-tools.js +27 -1
  334. package/dist/surface/tools/dynamic-tools.js +6 -0
  335. package/dist/surface/tools/error-recovery.js +4 -4
  336. package/dist/surface/tools/feedback-invite.js +6 -4
  337. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  338. package/dist/surface/tools/feedback-tools.js +1 -1
  339. package/dist/surface/tools/harness-explore.d.ts +3 -2
  340. package/dist/surface/tools/harness-explore.js +7 -6
  341. package/dist/surface/tools/invoke-tool.js +17 -4
  342. package/dist/surface/tools/lease-hint.d.ts +8 -0
  343. package/dist/surface/tools/lease-hint.js +10 -0
  344. package/dist/surface/tools/lease-tools.d.ts +16 -28
  345. package/dist/surface/tools/lease-tools.js +68 -11
  346. package/dist/surface/tools/lineage-tools.js +1 -1
  347. package/dist/surface/tools/live-call-text.js +4 -1
  348. package/dist/surface/tools/observe-tools.js +23 -7
  349. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  350. package/dist/surface/tools/real-input-attempt.js +1 -1
  351. package/dist/surface/tools/tool-kit.d.ts +5 -0
  352. package/dist/surface/tools/tool-kit.js +6 -1
  353. package/dist/surface/tools/tool-surface.js +17 -5
  354. package/dist/surface/tools/tools.js +68 -29
  355. package/dist/telemetry/argument-shape.d.ts +0 -2
  356. package/dist/telemetry/argument-shape.js +0 -4
  357. package/dist/telemetry/error-class.d.ts +2 -3
  358. package/dist/telemetry/error-class.js +2 -3
  359. package/dist/telemetry/feedback-local.d.ts +1 -0
  360. package/dist/telemetry/feedback-local.js +1 -3
  361. package/dist/telemetry/feedback.d.ts +1 -1
  362. package/dist/telemetry/harness-drive.d.ts +0 -2
  363. package/dist/telemetry/harness-drive.js +0 -4
  364. package/dist/telemetry/hud-metrics.d.ts +32 -0
  365. package/dist/telemetry/hud-metrics.js +95 -0
  366. package/dist/telemetry/session-metrics.d.ts +5 -0
  367. package/dist/telemetry/session-metrics.js +15 -1
  368. package/dist/wire-journal.d.ts +34 -0
  369. package/dist/wire-journal.js +104 -0
  370. package/dist/workspace-packages.d.ts +0 -2
  371. package/dist/workspace-packages.js +1 -9
  372. package/docs/README.md +5 -2
  373. package/docs/actions.mdx +3 -3
  374. package/docs/agent-cheatsheet.md +4 -4
  375. package/docs/architecture.md +6 -6
  376. package/docs/best-practices.mdx +1 -1
  377. package/docs/capabilities.mdx +32 -1
  378. package/docs/cli/cloud.mdx +21 -9
  379. package/docs/cli/doctor.mdx +4 -0
  380. package/docs/cli/feedback.mdx +2 -2
  381. package/docs/cli/gate.mdx +9 -4
  382. package/docs/cli/init.mdx +1 -0
  383. package/docs/cli/report.mdx +44 -0
  384. package/docs/cli/update.mdx +10 -0
  385. package/docs/cli.mdx +9 -0
  386. package/docs/desktop.mdx +14 -10
  387. package/docs/environment.mdx +87 -0
  388. package/docs/faq.mdx +18 -16
  389. package/docs/first-drive.md +5 -13
  390. package/docs/flows.md +32 -2
  391. package/docs/frameworks.mdx +140 -9
  392. package/docs/getting-started.md +3 -3
  393. package/docs/http-transport.md +6 -3
  394. package/docs/human-control.md +2 -2
  395. package/docs/index.mdx +16 -6
  396. package/docs/install-agentic.mdx +37 -1
  397. package/docs/install-manual.mdx +1 -1
  398. package/docs/integration-patterns.md +3 -3
  399. package/docs/multi-agent-testing.md +1 -1
  400. package/docs/packages/babel-plugin.mdx +1 -1
  401. package/docs/packages/browser.mdx +2 -2
  402. package/docs/packages/react.mdx +2 -2
  403. package/docs/packages/tauri.mdx +1 -1
  404. package/docs/packages/vite-plugin.mdx +2 -2
  405. package/docs/packages.mdx +9 -9
  406. package/docs/predicates.mdx +176 -7
  407. package/docs/quickstart.mdx +2 -2
  408. package/docs/recipes.mdx +2 -2
  409. package/docs/state-management.mdx +2 -2
  410. package/docs/system-map.md +1 -1
  411. package/docs/telemetry.md +1 -1
  412. package/docs/token-efficiency.md +3 -3
  413. package/docs/tools/act-and-wait.mdx +1 -0
  414. package/docs/tools/act-sequence.mdx +1 -1
  415. package/docs/tools/console.mdx +1 -1
  416. package/docs/tools/inspect.mdx +1 -1
  417. package/docs/tools/network.mdx +1 -1
  418. package/docs/tools/query.mdx +11 -11
  419. package/docs/tools/sessions.mdx +1 -1
  420. package/docs/tools/snapshot.mdx +1 -1
  421. package/docs/tools/state.mdx +1 -1
  422. package/docs/tools/wait-for.mdx +1 -1
  423. package/docs/usage.md +8 -7
  424. package/docs/use-cases.mdx +157 -0
  425. package/docs/vs-screenshots.mdx +3 -3
  426. package/docs/what-is-recorded.md +62 -0
  427. package/docs/what-is-reticle.mdx +17 -20
  428. package/docs/why-reticle.mdx +14 -21
  429. package/package.json +11 -10
  430. package/dist/judgement/capsule/minimize.d.ts +0 -12
  431. package/dist/judgement/capsule/minimize.js +0 -22
  432. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  433. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
  434. package/dist/judgement/phenomena/phenomena.d.ts +0 -26
  435. package/dist/judgement/phenomena/phenomena.js +0 -101
  436. package/dist/language/flows/flow-report.d.ts +0 -22
  437. package/dist/language/flows/flow-report.js +0 -106
@@ -21,7 +21,6 @@
21
21
  */
22
22
  import { z } from 'zod';
23
23
  import { type Intent } from '@reticlehq/core/artifacts';
24
- import type { FileSystemPort } from '../project/fs/fs-port.js';
25
24
  /**
26
25
  * How settled a record is.
27
26
  *
@@ -311,25 +310,6 @@ export declare const IntentShardSchema: z.ZodObject<{
311
310
  }>;
312
311
  }>;
313
312
  export type IntentShard = z.infer<typeof IntentShardSchema>;
314
- export declare const summarise: (statement: string) => string;
315
- /** One line per intent: enough to decide whether to open the shard, and no more. */
316
- declare const IntentIndexEntrySchema: z.ZodObject<{
317
- id: z.ZodString;
318
- subject: z.ZodString;
319
- statement: z.ZodString;
320
- status: z.ZodEnum<["proposed", "agreed", "proved", "stale"]>;
321
- }, "strip", z.ZodTypeAny, {
322
- status: "proved" | "proposed" | "agreed" | "stale";
323
- id: string;
324
- subject: string;
325
- statement: string;
326
- }, {
327
- status: "proved" | "proposed" | "agreed" | "stale";
328
- id: string;
329
- subject: string;
330
- statement: string;
331
- }>;
332
- export type IntentIndexEntry = z.infer<typeof IntentIndexEntrySchema>;
333
313
  export declare const IntentIndexSchema: z.ZodObject<{
334
314
  version: z.ZodLiteral<1>;
335
315
  entries: z.ZodArray<z.ZodObject<{
@@ -367,7 +347,6 @@ export declare const IntentIndexSchema: z.ZodObject<{
367
347
  }>;
368
348
  export type IntentIndex = z.infer<typeof IntentIndexSchema>;
369
349
  export declare const emptyShard: (subject: string) => IntentShard;
370
- export declare const emptyIndex: () => IntentIndex;
371
350
  /** The verification lifecycle a legacy record carried, mapped onto the settledness axis. */
372
351
  export declare const statusFromState: (state: Intent["state"]) => IntentStatus;
373
352
  /**
@@ -384,6 +363,4 @@ export declare const indexFrom: (shards: readonly IntentShard[]) => IntentIndex;
384
363
  export declare const shardsFrom: (records: readonly IntentRecord[]) => IntentShard[];
385
364
  /** Serialise byte-stably, with keys sorted so a re-save of unchanged data is a no-op diff. */
386
365
  export declare const serialise: (value: unknown) => string;
387
- /** Read + validate one JSON file, failing soft: a hand-merged file with a conflict marker is real. */
388
- export declare const readJsonFile: <T>(fs: FileSystemPort, path: string, parse: (raw: unknown) => T, fallback: T) => Promise<T>;
389
366
  export {};
@@ -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),
@@ -96,7 +96,6 @@ export const emptyShard = (subject) => ({
96
96
  subject,
97
97
  intents: {},
98
98
  });
99
- export const emptyIndex = () => ({ version: INTENT_SHARD_VERSION, entries: [] });
100
99
  /** The verification lifecycle a legacy record carried, mapped onto the settledness axis. */
101
100
  export const statusFromState = (state) => 'proved' === state ? IntentStatus.PROVED : IntentStatus.AGREED;
102
101
  /**
@@ -142,12 +141,3 @@ const sortKeys = (value) => {
142
141
  return value;
143
142
  return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)));
144
143
  };
145
- /** Read + validate one JSON file, failing soft: a hand-merged file with a conflict marker is real. */
146
- export const readJsonFile = async (fs, path, parse, fallback) => {
147
- try {
148
- return parse(JSON.parse(await fs.readFile(path)));
149
- }
150
- catch {
151
- return fallback;
152
- }
153
- };
@@ -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
  }
@@ -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 { FlowFile, 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,9 +12,13 @@ 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
+ page?: string;
19
+ endPage?: string;
20
+ /** The intent the agent declared on this action. The first one names the journey. */
21
+ intent?: string;
18
22
  }
19
23
  /** The compiled shape a flow store accepts. Structural, for the same reason as `TapeStep`. */
20
24
  export interface DriveProgram {
@@ -22,6 +26,7 @@ export interface DriveProgram {
22
26
  version: number;
23
27
  steps: TapeStep[];
24
28
  startPath?: string;
29
+ author?: FlowFile['author'];
25
30
  }
26
31
  /**
27
32
  * What a session drove, saved as a replayable flow — without anybody asking for it.
@@ -36,21 +41,21 @@ export interface DriveProgram {
36
41
  */
37
42
  /** The one condition on saving, and the reason the whole thing is safe. */
38
43
  export declare function carriesAnAssertion(steps: readonly TapeStep[]): boolean;
44
+ /** Every auto-saved flow's name starts here, which is what lets a merge tell them from hand-named ones. */
45
+ export declare const DRIVE_FLOW_PREFIX = "drive-";
39
46
  /**
40
- * A stable name for what this session drove — led by what it proved.
47
+ * A readable name for a journey, led by WHY it was driven.
41
48
  *
42
- * Two properties, and the name used to have only the second. It has to be STABLE: teardown fires on
43
- * every socket close and a reconnecting tab keeps its id, so a name that moves leaves one journey
44
- * scattered across several files, each a partial copy of the others. And it has to be READABLE,
45
- * because `presenter-controls.ts` renders it straight into the replay button's `textContent` — so
46
- * the label a person actually sees was `drive-sdc991872-6d66-4adf-8780-f931c62905f9`, twice, for two
47
- * different journeys. A session id is a fact about the socket, not about the feature.
49
+ * The agent's own `intent` on the action is the best name there is — it is the sentence a person
50
+ * would use — so it leads when one was declared. Without one, what the journey proved names it (the
51
+ * strongest claim first), and the route follows so two journeys stay apart.
48
52
  *
49
- * So the claim leads, the route follows, and a SHORT session discriminator trails: two sessions that
50
- * prove the same thing on the same route stay separate files rather than overwriting each other,
51
- * which is the one thing the full id was buying that the claim cannot.
53
+ * No session id. It used to trail every name so two sessions never overwrote each other, which also
54
+ * made every session's drive of the same journey its own file. Two DIFFERENT journeys that land on
55
+ * one name are now told apart at save by their shape, and two copies of the SAME journey merge —
56
+ * see FlowStore.saveJourney.
52
57
  */
53
- export declare function driveFlowName(sessionId: string, route?: string, steps?: readonly TapeStep[]): FlowName;
58
+ export declare function driveFlowName(route?: string, steps?: readonly TapeStep[]): FlowName;
54
59
  export interface DriveFlowOutcome {
55
60
  /** The flows that were written — one per journey the session contained. */
56
61
  readonly saved?: readonly string[];
@@ -65,7 +70,7 @@ export interface DriveFlowOutcome {
65
70
  readonly unprovenSteps?: number;
66
71
  }
67
72
  /** A flow per journey, so two journeys in one session are two regression tests rather than one. */
68
- export declare function driveFlowsFrom(sessionId: string, tape: {
73
+ export declare function driveFlowsFrom(tape: {
69
74
  steps: readonly TapeStep[];
70
75
  startPath?: string;
71
76
  } | undefined): {