@reticlehq/server 2.13.1 → 2.14.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 (449) hide show
  1. package/SKILL.md +8 -18
  2. package/bin/reticle.js +3 -0
  3. package/dist/bridge/auth-failure-reason.js +12 -1
  4. package/dist/bridge/bridge-security.d.ts +8 -0
  5. package/dist/bridge/bridge-security.js +6 -1
  6. package/dist/bridge/bridge.d.ts +3 -0
  7. package/dist/bridge/bridge.js +23 -1
  8. package/dist/bridge/bridge.test-harness.d.ts +10 -1
  9. package/dist/bridge/bridge.test-harness.js +7 -1
  10. package/dist/bridge/pairing-token.d.ts +17 -0
  11. package/dist/bridge/pairing-token.js +26 -0
  12. package/dist/bridge/token-auth.d.ts +7 -0
  13. package/dist/bridge/token-auth.js +7 -1
  14. package/dist/capsule/capsule-store.d.ts +4 -4
  15. package/dist/capsule/capsule.d.ts +1 -1
  16. package/dist/capsule/capsule.js +3 -3
  17. package/dist/capsule/causal-summary.d.ts +21 -1
  18. package/dist/capsule/causal-summary.js +8 -6
  19. package/dist/capsule/divergence.d.ts +1 -1
  20. package/dist/capsule/divergence.js +26 -10
  21. package/dist/chromium-launch-options.d.ts +2 -1
  22. package/dist/cli/adhoc-verdict.d.ts +58 -0
  23. package/dist/cli/adhoc-verdict.js +115 -0
  24. package/dist/cli/chromium-hint.d.ts +18 -4
  25. package/dist/cli/chromium-hint.js +54 -6
  26. package/dist/cli/cli-doctor.js +1 -2
  27. package/dist/cli/cli-flow-commands.d.ts +16 -2
  28. package/dist/cli/cli-flow-commands.js +28 -9
  29. package/dist/cli/cli-parse-feedback.js +1 -1
  30. package/dist/cli/cli-parse.d.ts +2 -1
  31. package/dist/cli/cli-parse.js +38 -0
  32. package/dist/cli/cli-port.d.ts +5 -13
  33. package/dist/cli/cli-port.js +5 -38
  34. package/dist/cli/cli-update-commands.js +4 -4
  35. package/dist/cli/cli-verify.d.ts +24 -7
  36. package/dist/cli/cli-verify.js +87 -13
  37. package/dist/cli/cloud-keystore.d.ts +2 -1
  38. package/dist/cli/cloud-login.d.ts +2 -1
  39. package/dist/cli/cloud-session.d.ts +2 -1
  40. package/dist/cli/cloud-session.js +1 -1
  41. package/dist/cli/daemon-start-options.d.ts +2 -1
  42. package/dist/cli/device-flow.d.ts +2 -2
  43. package/dist/cli/doctor-daemon-line.d.ts +2 -1
  44. package/dist/cli/doctor-project-line.d.ts +2 -1
  45. package/dist/cli/doctor-rows.d.ts +2 -1
  46. package/dist/cli/drive-attach.d.ts +4 -3
  47. package/dist/cli/gate-hook-message.d.ts +2 -1
  48. package/dist/cli/status-next-action.js +10 -11
  49. package/dist/cli.d.ts +1 -0
  50. package/dist/cli.js +21 -9
  51. package/dist/cloud/account-state.d.ts +20 -0
  52. package/dist/cloud/account-state.js +65 -0
  53. package/dist/cloud/cloud-sync.d.ts +46 -3
  54. package/dist/cloud/cloud-sync.js +116 -0
  55. package/dist/cloud/sync-cycle.d.ts +5 -4
  56. package/dist/cloud/sync-cycle.js +1 -1
  57. package/dist/cloud/sync-daemon.d.ts +3 -19
  58. package/dist/cloud/sync-daemon.js +2 -2
  59. package/dist/crawl/crawl-tools.js +1 -1
  60. package/dist/crawl/crawl.d.ts +5 -5
  61. package/dist/crawl/crawl.js +138 -4
  62. package/dist/daemon/daemon-resilience.d.ts +3 -2
  63. package/dist/daemon/daemon-resilience.js +43 -4
  64. package/dist/daemon/daemon-resolve.d.ts +0 -9
  65. package/dist/daemon/daemon-resolve.js +2 -2
  66. package/dist/daemon/dev-servers.d.ts +1 -1
  67. package/dist/daemon/dev-servers.js +1 -1
  68. package/dist/daemon/loopback-alias.d.ts +2 -1
  69. package/dist/daemon/startup-failure.d.ts +11 -0
  70. package/dist/daemon/startup-failure.js +46 -0
  71. package/dist/events/contradictions.d.ts +10 -16
  72. package/dist/events/contradictions.js +149 -17
  73. package/dist/events/declared.d.ts +13 -1
  74. package/dist/events/declared.js +59 -3
  75. package/dist/events/echo-mismatch.js +75 -6
  76. package/dist/events/lineage.d.ts +52 -0
  77. package/dist/events/lineage.js +122 -0
  78. package/dist/events/net-evidence.d.ts +21 -0
  79. package/dist/events/net-evidence.js +81 -0
  80. package/dist/events/predicate-console.d.ts +13 -0
  81. package/dist/events/predicate-console.js +138 -0
  82. package/dist/events/predicate-element.d.ts +13 -0
  83. package/dist/events/predicate-element.js +214 -0
  84. package/dist/events/predicate-eval.d.ts +15 -3
  85. package/dist/events/predicate-eval.js +128 -110
  86. package/dist/events/predicate-parse.js +34 -1
  87. package/dist/events/predicate-request-body.d.ts +50 -0
  88. package/dist/events/predicate-request-body.js +120 -0
  89. package/dist/events/predicate-route.d.ts +21 -1
  90. package/dist/events/predicate-route.js +149 -21
  91. package/dist/events/predicate-schema.d.ts +8 -1
  92. package/dist/events/predicate-schema.js +34 -0
  93. package/dist/events/predicate.d.ts +2 -0
  94. package/dist/events/predicate.js +52 -159
  95. package/dist/events/split-text-miss.d.ts +6 -4
  96. package/dist/events/split-text-miss.js +12 -5
  97. package/dist/flows/affected-tools.js +22 -9
  98. package/dist/flows/annotate.d.ts +2 -1
  99. package/dist/flows/annotate.js +19 -1
  100. package/dist/flows/coverage.d.ts +2 -2
  101. package/dist/flows/flake.d.ts +3 -3
  102. package/dist/flows/flow-expect-grammar.d.ts +33 -0
  103. package/dist/flows/flow-expect-grammar.js +155 -0
  104. package/dist/flows/flow-replay-run.d.ts +1 -1
  105. package/dist/flows/flow-replay-run.js +28 -15
  106. package/dist/flows/flow-replay.d.ts +10 -0
  107. package/dist/flows/flow-replay.js +57 -22
  108. package/dist/flows/flow-secret-field.d.ts +14 -0
  109. package/dist/flows/flow-secret-field.js +22 -0
  110. package/dist/flows/flow-step-runners.d.ts +1 -0
  111. package/dist/flows/flow-step-runners.js +91 -34
  112. package/dist/flows/flow-success.js +22 -0
  113. package/dist/flows/flow-tools.js +27 -8
  114. package/dist/flows/flow-upload-resolve.d.ts +23 -0
  115. package/dist/flows/flow-upload-resolve.js +46 -0
  116. package/dist/flows/flows.d.ts +15 -0
  117. package/dist/flows/flows.js +17 -14
  118. package/dist/flows/git-changed.d.ts +23 -4
  119. package/dist/flows/git-changed.js +32 -6
  120. package/dist/flows/heal-run.js +2 -2
  121. package/dist/flows/predicate-to-expect.d.ts +3 -2
  122. package/dist/flows/predicate-to-expect.js +11 -5
  123. package/dist/flows/recording-backtrack.d.ts +24 -0
  124. package/dist/flows/recording-backtrack.js +73 -0
  125. package/dist/flows/recordings.d.ts +6 -0
  126. package/dist/flows/replay-halt.d.ts +26 -0
  127. package/dist/flows/replay-halt.js +30 -0
  128. package/dist/flows/replay.d.ts +0 -8
  129. package/dist/flows/replay.js +15 -3
  130. package/dist/flows/suite-flakes.d.ts +2 -1
  131. package/dist/flows/verify-change-tools.js +16 -4
  132. package/dist/honesty/already-true.d.ts +14 -0
  133. package/dist/honesty/already-true.js +47 -4
  134. package/dist/honesty/blind-spots.d.ts +3 -1
  135. package/dist/honesty/blind-spots.js +24 -1
  136. package/dist/honesty/body-capture-remedy.d.ts +42 -0
  137. package/dist/honesty/body-capture-remedy.js +95 -0
  138. package/dist/honesty/feature-capture.d.ts +3 -2
  139. package/dist/honesty/feature-capture.js +1 -1
  140. package/dist/honesty/gap-ledger.d.ts +1 -1
  141. package/dist/honesty/gap-ledger.js +1 -1
  142. package/dist/honesty/instrumentation-gaps.d.ts +8 -1
  143. package/dist/honesty/instrumentation-gaps.js +12 -2
  144. package/dist/honesty/observability.d.ts +4 -3
  145. package/dist/honesty/tool-hit-rate.d.ts +3 -2
  146. package/dist/honesty/uncaptured-bodies.d.ts +3 -1
  147. package/dist/honesty/uncaptured-bodies.js +6 -2
  148. package/dist/honesty/unsettled.d.ts +9 -0
  149. package/dist/honesty/unsettled.js +45 -0
  150. package/dist/honesty/verified.d.ts +32 -1
  151. package/dist/honesty/verified.js +37 -10
  152. package/dist/impact/impact-store.d.ts +5 -14
  153. package/dist/impact/impact-store.js +49 -6
  154. package/dist/index.js +1 -1
  155. package/dist/input/network-detail.d.ts +26 -1
  156. package/dist/input/network-detail.js +44 -12
  157. package/dist/input/network-mock-tools.js +24 -17
  158. package/dist/input/real-input.js +1 -1
  159. package/dist/input/viewport-tools.js +25 -13
  160. package/dist/intent/inline-intent.d.ts +0 -10
  161. package/dist/intent/inline-intent.js +1 -1
  162. package/dist/intent/intent-shard-store.d.ts +3 -2
  163. package/dist/intent/intent-shard-store.js +1 -1
  164. package/dist/intent/intent-shard.d.ts +14 -14
  165. package/dist/intent/intent-shard.js +4 -4
  166. package/dist/intent/intent-store.d.ts +1 -1
  167. package/dist/intent/intent-store.js +1 -1
  168. package/dist/intent/intent-subject.d.ts +2 -1
  169. package/dist/intent/open-intents.d.ts +3 -2
  170. package/dist/license/license.d.ts +4 -4
  171. package/dist/license/license.js +1 -1
  172. package/dist/mcp/attach-memory.d.ts +2 -1
  173. package/dist/mcp/client-identity.d.ts +2 -1
  174. package/dist/mcp/mcp-outage.d.ts +1 -1
  175. package/dist/mcp/mcp-outage.js +1 -1
  176. package/dist/mcp/mcp-proxy.d.ts +3 -1
  177. package/dist/mcp/mcp-proxy.js +32 -7
  178. package/dist/mcp/mcp.js +3 -1
  179. package/dist/mcp/proxy-handshake.d.ts +2 -1
  180. package/dist/mcp/proxy-idle-exit.d.ts +45 -0
  181. package/dist/mcp/proxy-idle-exit.js +94 -0
  182. package/dist/mcp/server-instructions.d.ts +2 -1
  183. package/dist/memory/project-memory.d.ts +2 -3
  184. package/dist/memory/project-memory.js +1 -1
  185. package/dist/oracles/propose-consequences.js +5 -5
  186. package/dist/oracles/self-instrument.d.ts +2 -2
  187. package/dist/oracles/self-instrument.js +1 -1
  188. package/dist/platform.d.ts +3 -5
  189. package/dist/platform.js +3 -5
  190. package/dist/pool/browser-pool.d.ts +92 -0
  191. package/dist/pool/browser-pool.js +119 -5
  192. package/dist/pool/playwright-launcher.js +29 -2
  193. package/dist/pool/storage-seed.d.ts +23 -0
  194. package/dist/pool/storage-seed.js +198 -0
  195. package/dist/project/artifact-root.d.ts +2 -1
  196. package/dist/project/memory-fs.d.ts +2 -1
  197. package/dist/project/reticle-dir.js +1 -1
  198. package/dist/project/session-root.d.ts +8 -0
  199. package/dist/project/session-root.js +9 -2
  200. package/dist/runs/reticle-runner.d.ts +14 -1
  201. package/dist/runs/reticle-runner.js +39 -2
  202. package/dist/session/attachment-history.d.ts +2 -1
  203. package/dist/session/fake-session.d.ts +37 -0
  204. package/dist/session/fake-session.js +81 -0
  205. package/dist/session/lease-visibility.d.ts +2 -1
  206. package/dist/session/live-control-tools.js +6 -0
  207. package/dist/session/no-session-diagnosis.d.ts +17 -1
  208. package/dist/session/no-session-diagnosis.js +32 -6
  209. package/dist/session/no-session-next-action.d.ts +14 -0
  210. package/dist/session/no-session-next-action.js +18 -0
  211. package/dist/session/no-session-watch.js +46 -3
  212. package/dist/session/registered-projects.d.ts +54 -0
  213. package/dist/session/registered-projects.js +73 -0
  214. package/dist/session/review-store.d.ts +2 -1
  215. package/dist/session/session-health.d.ts +62 -1
  216. package/dist/session/session-health.js +82 -2
  217. package/dist/session/session-manager.d.ts +11 -1
  218. package/dist/session/session-manager.js +18 -3
  219. package/dist/session/session-replaced.d.ts +24 -0
  220. package/dist/session/session-replaced.js +29 -0
  221. package/dist/session/session-successor.js +20 -4
  222. package/dist/session/session.d.ts +13 -5
  223. package/dist/session/session.js +31 -23
  224. package/dist/setup/agent-configs.d.ts +3 -2
  225. package/dist/setup/agent-writer.d.ts +3 -2
  226. package/dist/setup/approval-migration.d.ts +2 -1
  227. package/dist/setup/approval-migration.js +1 -1
  228. package/dist/setup/auto-approve.d.ts +11 -19
  229. package/dist/setup/auto-approve.js +15 -12
  230. package/dist/{init → setup}/confirm.js +1 -1
  231. package/dist/setup/desktop-shape.d.ts +3 -2
  232. package/dist/setup/drive-agent.d.ts +2 -3
  233. package/dist/setup/drive-agent.js +1 -1
  234. package/dist/setup/drive-plan.d.ts +3 -2
  235. package/dist/setup/ensure-daemon.d.ts +2 -1
  236. package/dist/setup/existing-app.d.ts +12 -0
  237. package/dist/setup/existing-app.js +13 -0
  238. package/dist/setup/init-host.d.ts +11 -0
  239. package/dist/setup/init-host.js +26 -0
  240. package/dist/setup/init-runtime.d.ts +4 -10
  241. package/dist/setup/init-runtime.js +23 -16
  242. package/dist/setup/license-key.d.ts +2 -1
  243. package/dist/setup/listeners.d.ts +2 -1
  244. package/dist/setup/loopback-probe-urls.d.ts +18 -0
  245. package/dist/setup/loopback-probe-urls.js +52 -0
  246. package/dist/setup/node-effects.d.ts +3 -0
  247. package/dist/setup/node-effects.js +26 -11
  248. package/dist/setup/page-probe.d.ts +5 -0
  249. package/dist/setup/relaunch.d.ts +2 -1
  250. package/dist/setup/run-setup.d.ts +5 -1
  251. package/dist/setup/run-setup.js +141 -50
  252. package/dist/setup/setup-command.d.ts +3 -2
  253. package/dist/setup/setup-command.js +8 -0
  254. package/dist/setup/setup-options.d.ts +5 -3
  255. package/dist/setup/setup-options.js +3 -2
  256. package/dist/setup/wait-progress.d.ts +28 -0
  257. package/dist/setup/wait-progress.js +43 -0
  258. package/dist/telemetry/app-instrumented.d.ts +2 -1
  259. package/dist/telemetry/app-instrumented.js +1 -1
  260. package/dist/telemetry/automation-hint.d.ts +1 -1
  261. package/dist/telemetry/automation-hint.js +1 -1
  262. package/dist/telemetry/cli-telemetry.js +1 -1
  263. package/dist/telemetry/connect-failure.d.ts +1 -1
  264. package/dist/telemetry/connect-failure.js +1 -1
  265. package/dist/telemetry/crash-cause.d.ts +3 -2
  266. package/dist/telemetry/crash-cause.js +1 -1
  267. package/dist/telemetry/daemon-telemetry.d.ts +3 -2
  268. package/dist/telemetry/daemon-telemetry.js +1 -1
  269. package/dist/telemetry/error-class.d.ts +3 -2
  270. package/dist/telemetry/error-class.js +1 -1
  271. package/dist/telemetry/feedback-cli.js +1 -1
  272. package/dist/telemetry/feedback-context.d.ts +3 -2
  273. package/dist/telemetry/feedback-context.js +5 -4
  274. package/dist/telemetry/feedback-local.d.ts +3 -2
  275. package/dist/telemetry/feedback.d.ts +4 -3
  276. package/dist/telemetry/feedback.js +1 -1
  277. package/dist/telemetry/git-facts.d.ts +2 -2
  278. package/dist/telemetry/git-facts.js +1 -1
  279. package/dist/telemetry/identify.d.ts +1 -1
  280. package/dist/telemetry/identify.js +1 -1
  281. package/dist/telemetry/init-telemetry.d.ts +2 -14
  282. package/dist/telemetry/init-telemetry.js +4 -13
  283. package/dist/telemetry/install-source.d.ts +7 -13
  284. package/dist/telemetry/install-source.js +7 -29
  285. package/dist/telemetry/license-activation.d.ts +3 -2
  286. package/dist/telemetry/license-activation.js +1 -1
  287. package/dist/telemetry/machine-snapshot.d.ts +1 -1
  288. package/dist/telemetry/mcp-connection.js +1 -1
  289. package/dist/telemetry/project-profile.d.ts +0 -14
  290. package/dist/telemetry/project-profile.js +1 -1
  291. package/dist/telemetry/proxy-telemetry.js +1 -1
  292. package/dist/telemetry/session-metrics.d.ts +1 -1
  293. package/dist/telemetry/session-metrics.js +1 -1
  294. package/dist/telemetry/telemetry.d.ts +1 -17
  295. package/dist/telemetry/telemetry.js +4 -4
  296. package/dist/telemetry/tool-refused.d.ts +1 -1
  297. package/dist/telemetry/tool-refused.js +1 -1
  298. package/dist/tools/act-observation.d.ts +3 -2
  299. package/dist/tools/act-preflight.js +8 -3
  300. package/dist/tools/act-target.d.ts +4 -0
  301. package/dist/tools/act-target.js +14 -5
  302. package/dist/tools/act-tools.d.ts +0 -2
  303. package/dist/tools/act-tools.js +45 -15
  304. package/dist/tools/assert-source.d.ts +30 -0
  305. package/dist/tools/assert-source.js +21 -0
  306. package/dist/tools/assert-verdict.d.ts +1 -1
  307. package/dist/tools/assert-verdict.js +14 -4
  308. package/dist/tools/browser-tools.js +28 -8
  309. package/dist/tools/complete-snapshot.d.ts +3 -2
  310. package/dist/tools/dynamic-tools.js +8 -0
  311. package/dist/tools/error-recovery.d.ts +10 -0
  312. package/dist/tools/error-recovery.js +23 -0
  313. package/dist/tools/feedback-tools.js +1 -1
  314. package/dist/tools/invoke-tool.js +2 -0
  315. package/dist/tools/lease-tools.d.ts +48 -20
  316. package/dist/tools/lease-tools.js +311 -76
  317. package/dist/tools/lineage-tools.d.ts +14 -0
  318. package/dist/tools/lineage-tools.js +64 -0
  319. package/dist/tools/merge-tools.js +1 -3
  320. package/dist/tools/navigate-arrival.d.ts +45 -1
  321. package/dist/tools/navigate-arrival.js +39 -6
  322. package/dist/tools/navigate-result.d.ts +8 -1
  323. package/dist/tools/navigate-result.js +14 -4
  324. package/dist/tools/numeric-bounds.d.ts +0 -11
  325. package/dist/tools/numeric-bounds.js +4 -4
  326. package/dist/tools/observe-tools.js +22 -26
  327. package/dist/tools/observed-nothing.d.ts +9 -0
  328. package/dist/tools/observed-nothing.js +2 -1
  329. package/dist/tools/read-tools.js +12 -17
  330. package/dist/tools/real-input-attempt.d.ts +14 -6
  331. package/dist/tools/real-input-attempt.js +75 -18
  332. package/dist/tools/reconcile-tools.js +2 -1
  333. package/dist/tools/reload-result.d.ts +6 -1
  334. package/dist/tools/reload-result.js +7 -2
  335. package/dist/tools/resolve-target.d.ts +7 -1
  336. package/dist/tools/resolve-target.js +72 -9
  337. package/dist/tools/settle-in-flight.d.ts +1 -1
  338. package/dist/tools/settle-in-flight.js +9 -2
  339. package/dist/tools/snapshot-delta.d.ts +24 -1
  340. package/dist/tools/snapshot-delta.js +66 -7
  341. package/dist/tools/tool-names.d.ts +1 -0
  342. package/dist/tools/tool-names.js +1 -0
  343. package/dist/tools/tool-surface.js +20 -2
  344. package/dist/tools/tools.js +120 -11
  345. package/dist/tools/verify-next-baton.d.ts +2 -1
  346. package/dist/update/sdk-sync.d.ts +1 -1
  347. package/dist/update/sdk-sync.js +1 -1
  348. package/dist/update/updater.js +1 -1
  349. package/dist/version/sdk-fix.d.ts +2 -1
  350. package/dist/version/version-skew.d.ts +0 -8
  351. package/dist/version/version-skew.js +1 -1
  352. package/docs/README.md +8 -6
  353. package/docs/actions.mdx +1 -1
  354. package/docs/agent-cheatsheet.md +4 -2
  355. package/docs/architecture.md +1 -1
  356. package/docs/cli/mcp.mdx +3 -1
  357. package/docs/cli/watch.mdx +1 -1
  358. package/docs/cli.mdx +1 -1
  359. package/docs/desktop.mdx +1 -1
  360. package/docs/docs.json +8 -3
  361. package/docs/faq.mdx +9 -0
  362. package/docs/first-drive.md +136 -0
  363. package/docs/frameworks.mdx +29 -7
  364. package/docs/gate-plan.md +2 -2
  365. package/docs/gates.md +19 -11
  366. package/docs/getting-started.md +7 -1
  367. package/docs/http-transport.md +164 -0
  368. package/docs/index.mdx +5 -3
  369. package/docs/install-manual.mdx +1 -1
  370. package/docs/packages/tauri.mdx +1 -1
  371. package/docs/packages.mdx +15 -3
  372. package/docs/platform-integration.md +1 -1
  373. package/docs/predicates.mdx +2 -0
  374. package/docs/system-map.md +2 -2
  375. package/docs/telemetry-contract.md +4 -4
  376. package/docs/telemetry-events.mdx +1 -1
  377. package/docs/telemetry.md +3 -3
  378. package/docs/tools-navigate.mdx +14 -6
  379. package/docs/usage.md +4 -4
  380. package/package.json +7 -4
  381. package/dist/init/agent-rules.d.ts +0 -116
  382. package/dist/init/agent-rules.js +0 -279
  383. package/dist/init/app-choice.d.ts +0 -20
  384. package/dist/init/app-choice.js +0 -25
  385. package/dist/init/astro-host.d.ts +0 -21
  386. package/dist/init/astro-host.js +0 -27
  387. package/dist/init/astro-patch.d.ts +0 -33
  388. package/dist/init/astro-patch.js +0 -300
  389. package/dist/init/capabilities.d.ts +0 -40
  390. package/dist/init/capabilities.js +0 -150
  391. package/dist/init/closing-hint.d.ts +0 -36
  392. package/dist/init/closing-hint.js +0 -120
  393. package/dist/init/connect-steps.d.ts +0 -2
  394. package/dist/init/connect-steps.js +0 -50
  395. package/dist/init/cra.d.ts +0 -79
  396. package/dist/init/cra.js +0 -178
  397. package/dist/init/csp-check.d.ts +0 -38
  398. package/dist/init/csp-check.js +0 -107
  399. package/dist/init/csp-doctor.d.ts +0 -32
  400. package/dist/init/csp-doctor.js +0 -54
  401. package/dist/init/desktop-doctor.d.ts +0 -41
  402. package/dist/init/desktop-doctor.js +0 -198
  403. package/dist/init/detect.d.ts +0 -96
  404. package/dist/init/detect.js +0 -209
  405. package/dist/init/dev-script.d.ts +0 -50
  406. package/dist/init/dev-script.js +0 -66
  407. package/dist/init/format-generated.d.ts +0 -18
  408. package/dist/init/format-generated.js +0 -39
  409. package/dist/init/install-hint.d.ts +0 -9
  410. package/dist/init/install-hint.js +0 -29
  411. package/dist/init/mcp-clients.d.ts +0 -89
  412. package/dist/init/mcp-clients.js +0 -299
  413. package/dist/init/mcp-registered.d.ts +0 -12
  414. package/dist/init/mcp-registered.js +0 -14
  415. package/dist/init/mcp.d.ts +0 -89
  416. package/dist/init/mcp.js +0 -129
  417. package/dist/init/next-patch.d.ts +0 -39
  418. package/dist/init/next-patch.js +0 -196
  419. package/dist/init/node-io.d.ts +0 -7
  420. package/dist/init/node-io.js +0 -117
  421. package/dist/init/non-js-project.d.ts +0 -27
  422. package/dist/init/non-js-project.js +0 -84
  423. package/dist/init/patch-kind.d.ts +0 -20
  424. package/dist/init/patch-kind.js +0 -10
  425. package/dist/init/plan-framework.d.ts +0 -64
  426. package/dist/init/plan-framework.js +0 -565
  427. package/dist/init/plan.d.ts +0 -242
  428. package/dist/init/plan.js +0 -703
  429. package/dist/init/preflight.d.ts +0 -28
  430. package/dist/init/preflight.js +0 -38
  431. package/dist/init/project-id.d.ts +0 -12
  432. package/dist/init/project-id.js +0 -25
  433. package/dist/init/refresh-rules.d.ts +0 -39
  434. package/dist/init/refresh-rules.js +0 -51
  435. package/dist/init/run.d.ts +0 -117
  436. package/dist/init/run.js +0 -806
  437. package/dist/init/slash-command.d.ts +0 -27
  438. package/dist/init/slash-command.js +0 -132
  439. package/dist/init/snippets.d.ts +0 -134
  440. package/dist/init/snippets.js +0 -572
  441. package/dist/init/vite-config.d.ts +0 -18
  442. package/dist/init/vite-config.js +0 -114
  443. package/dist/init/windows-quote.d.ts +0 -38
  444. package/dist/init/windows-quote.js +0 -70
  445. package/dist/init/workspace-apps.d.ts +0 -30
  446. package/dist/init/workspace-apps.js +0 -178
  447. package/dist/project/remember-project.d.ts +0 -24
  448. package/dist/project/remember-project.js +0 -40
  449. /package/dist/{init → setup}/confirm.d.ts +0 -0
@@ -96,16 +96,22 @@ export function predicateToExpect(predicate) {
96
96
  * `reticle_verify` then correctly called it `unverifiable` — the record → save → verify path
97
97
  * completing all the way to a run that could never be a pass. Found by driving it.
98
98
  *
99
- * The list below is exactly what `successToPredicate` reads, plus the testid the step runner
100
- * asserts directly against the DOM. Anything it cannot compile is still dropped.
99
+ * The list below is exactly what `successToPredicate` reads, including an element located by
100
+ * role or name. A testid is also asserted directly against the DOM by the step runner. Anything
101
+ * it cannot compile is still dropped.
101
102
  */
102
103
  export function enforcedOnReplay(expect) {
103
104
  if (expect === undefined)
104
105
  return undefined;
105
106
  const kept = {};
106
- // The step runner asserts this one directly against the live DOM, before the predicate engine.
107
- if (expect.element?.testid !== undefined)
108
- kept.element = expect.element;
107
+ // The step runner asserts a testid against the live DOM before the predicate engine. Role and
108
+ // name are not that path: successToPredicate compiles them, and dropping them here made a
109
+ // recorded `until` by button name vanish so the saved flow could not go red.
110
+ const element = expect.element;
111
+ if (undefined !== element &&
112
+ (undefined !== element.testid || undefined !== element.role || undefined !== element.name)) {
113
+ kept.element = element;
114
+ }
109
115
  // Everything `successToPredicate` can compile. Replay evaluates EVERY kind of expect through it
110
116
  // (see assertStepExpect); this list is what that function actually reads.
111
117
  if (expect.state !== undefined)
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A recorded flow that backtracks across pages cannot replay.
3
+ *
4
+ * The recorder stores clicks, not navigations. A drive that opens a product and then returns to
5
+ * search saves both clicks; replay lands on the product page and looks for a control that only
6
+ * exists on search. That shape is visible from the route list with no change to the flow file, so
7
+ * stop/save can warn instead of writing a flow that fails on the next click.
8
+ */
9
+ import { type ReticleEvent } from '@reticlehq/core';
10
+ /**
11
+ * The page a recording step sat on, comparable across path routers and hash routers.
12
+ *
13
+ * A startPath is stored as pathname+hash (`/#/search`); a ROUTE_CHANGE carries them separately.
14
+ * Without this, every hash-router page compares as `/` and a backtrack is invisible.
15
+ */
16
+ export declare function recordingRouteOf(pathname: string, hash?: string): string;
17
+ /**
18
+ * Warn when the journey left a page and came back. Linear A→B→C is silent: that still cannot
19
+ * replay either if a later click needs a previous page, but the reported failure is specifically
20
+ * the backtrack, and inventing a warning for every multi-page drive would teach agents to ignore it.
21
+ */
22
+ export declare function recordingBacktrackWarning(routes: readonly string[]): string | undefined;
23
+ /** Ordered pages the recording sat on, startPath first, consecutive stays collapsed. */
24
+ export declare function routesFromRecording(startPath: string | undefined, events: readonly ReticleEvent[]): string[];
@@ -0,0 +1,73 @@
1
+ /**
2
+ * A recorded flow that backtracks across pages cannot replay.
3
+ *
4
+ * The recorder stores clicks, not navigations. A drive that opens a product and then returns to
5
+ * search saves both clicks; replay lands on the product page and looks for a control that only
6
+ * exists on search. That shape is visible from the route list with no change to the flow file, so
7
+ * stop/save can warn instead of writing a flow that fails on the next click.
8
+ */
9
+ import { EventType } from '@reticlehq/core';
10
+ import { routePathOf } from '../events/predicate-route.js';
11
+ function asString(value) {
12
+ return 'string' === typeof value ? value : undefined;
13
+ }
14
+ /**
15
+ * The page a recording step sat on, comparable across path routers and hash routers.
16
+ *
17
+ * A startPath is stored as pathname+hash (`/#/search`); a ROUTE_CHANGE carries them separately.
18
+ * Without this, every hash-router page compares as `/` and a backtrack is invisible.
19
+ */
20
+ export function recordingRouteOf(pathname, hash = '') {
21
+ const hashIdx = pathname.indexOf('#/');
22
+ if (hashIdx >= 0) {
23
+ return routePathOf(pathname.slice(0, hashIdx) || '/', pathname.slice(hashIdx));
24
+ }
25
+ const fragment = hash.startsWith('#') ? hash : 0 === hash.length ? '' : `#${hash}`;
26
+ if (fragment.startsWith('#/'))
27
+ return routePathOf(0 === pathname.length ? '/' : pathname, fragment);
28
+ return pathname;
29
+ }
30
+ function collapseConsecutive(routes) {
31
+ const out = [];
32
+ for (const route of routes) {
33
+ if (0 === route.length)
34
+ continue;
35
+ if (out.at(-1) === route)
36
+ continue;
37
+ out.push(route);
38
+ }
39
+ return out;
40
+ }
41
+ /**
42
+ * Warn when the journey left a page and came back. Linear A→B→C is silent: that still cannot
43
+ * replay either if a later click needs a previous page, but the reported failure is specifically
44
+ * the backtrack, and inventing a warning for every multi-page drive would teach agents to ignore it.
45
+ */
46
+ export function recordingBacktrackWarning(routes) {
47
+ const path = collapseConsecutive(routes);
48
+ const seen = new Set();
49
+ for (const route of path) {
50
+ if (seen.has(route)) {
51
+ return (`this recording returned to ${route} after leaving it — replay has no navigation steps, so ` +
52
+ 'the next click looks for a control that only exists on a page the tab is no longer on. ' +
53
+ `Journey: ${path.join(' → ')}. Split into one flow per page, or record the control that navigates back.`);
54
+ }
55
+ seen.add(route);
56
+ }
57
+ return undefined;
58
+ }
59
+ /** Ordered pages the recording sat on, startPath first, consecutive stays collapsed. */
60
+ export function routesFromRecording(startPath, events) {
61
+ const raw = [];
62
+ if (undefined !== startPath)
63
+ raw.push(recordingRouteOf(startPath));
64
+ for (const event of events) {
65
+ if (EventType.ROUTE_CHANGE !== event.type)
66
+ continue;
67
+ const pathname = asString(event.data['pathname']) ?? asString(event.data['to']);
68
+ if (undefined === pathname)
69
+ continue;
70
+ raw.push(recordingRouteOf(pathname, asString(event.data['hash']) ?? ''));
71
+ }
72
+ return collapseConsecutive(raw);
73
+ }
@@ -22,6 +22,12 @@ export interface CompiledProgram {
22
22
  version: number;
23
23
  steps: RecordedStep[];
24
24
  startPath?: string;
25
+ /**
26
+ * Pages the recording sat on, in order, consecutive stays collapsed. In-memory only — not written
27
+ * to the flow file. Lets save warn about a backtrack (a journey that cannot replay) without a
28
+ * format change.
29
+ */
30
+ routes?: string[];
25
31
  }
26
32
  /**
27
33
  * Tracks in-flight recordings (name -> { buffer cursor at record_start, captured steps })
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Whether a replay stopped before the end of the flow, and how much it never reached.
3
+ *
4
+ * `replayFlow` breaks on the first failing step. That is right — once a consequence did not hold,
5
+ * every later step would run against a state the flow never described, and continuing would turn
6
+ * one wrong result into several. What was missing is any way for the caller to SEE it: a two-step
7
+ * flow that halted comes back with one step result, and a reader who does not know the halt rule
8
+ * sees a step that is simply absent.
9
+ *
10
+ * Reported as "replay silently skips a second destructive step" — with three correct observations
11
+ * and a wrong conclusion, because the output offered no other reading.
12
+ */
13
+ import type { FlowStepResult } from '@reticlehq/core';
14
+ /** Set on a replay that stopped early; omitted entirely otherwise, so a clean pass stays flat. */
15
+ export interface ReplayHalt {
16
+ /** Index of the step that stopped the run. */
17
+ atStep: number;
18
+ /** How many of the flow's steps were never attempted because of it. */
19
+ notAttempted: number;
20
+ }
21
+ /**
22
+ * `total` is the FLOW's step count, deliberately — not `results.length`. The results array is the
23
+ * short one, so deriving the total from it would report zero skipped on every halt, which is the
24
+ * defect restated as its own fix.
25
+ */
26
+ export declare function haltedFrom(results: readonly FlowStepResult[], total: number): ReplayHalt | undefined;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Whether a replay stopped before the end of the flow, and how much it never reached.
3
+ *
4
+ * `replayFlow` breaks on the first failing step. That is right — once a consequence did not hold,
5
+ * every later step would run against a state the flow never described, and continuing would turn
6
+ * one wrong result into several. What was missing is any way for the caller to SEE it: a two-step
7
+ * flow that halted comes back with one step result, and a reader who does not know the halt rule
8
+ * sees a step that is simply absent.
9
+ *
10
+ * Reported as "replay silently skips a second destructive step" — with three correct observations
11
+ * and a wrong conclusion, because the output offered no other reading.
12
+ */
13
+ /**
14
+ * `total` is the FLOW's step count, deliberately — not `results.length`. The results array is the
15
+ * short one, so deriving the total from it would report zero skipped on every halt, which is the
16
+ * defect restated as its own fix.
17
+ */
18
+ export function haltedFrom(results, total) {
19
+ const last = results[results.length - 1];
20
+ if (last === undefined)
21
+ return undefined;
22
+ if (last.ok && last.drift === undefined)
23
+ return undefined;
24
+ const notAttempted = total - results.length;
25
+ // A failure on the FINAL step is not a halt: nothing was left to attempt, and `notAttempted: 0`
26
+ // would send a reader looking for steps that do not exist.
27
+ if (notAttempted <= 0)
28
+ return undefined;
29
+ return { atStep: last.step, notAttempted };
30
+ }
@@ -13,14 +13,6 @@ export declare function ambiguousTestidNote(value: string): string;
13
13
  * resolution — can't drift between them.
14
14
  */
15
15
  export declare function queryRefs(result: CommandResult): string[];
16
- /**
17
- * The environment variable that supplies one redacted field.
18
- *
19
- * Named after the field so it is guessable from the flow alone: `auth-password` is read from
20
- * `RETICLE_SECRET_AUTH_PASSWORD`. A scheme requiring a lookup table would mean the flow says a
21
- * value is missing and cannot say what to set.
22
- */
23
- export declare const secretEnvKey: (field: string) => string;
24
16
  /**
25
17
  * A destructive-action confirmation is one-shot and must never persist into a recording.
26
18
  *
@@ -31,7 +31,7 @@ export function queryRefs(result) {
31
31
  * `RETICLE_SECRET_AUTH_PASSWORD`. A scheme requiring a lookup table would mean the flow says a
32
32
  * value is missing and cannot say what to set.
33
33
  */
34
- export const secretEnvKey = (field) => `RETICLE_SECRET_${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
34
+ const secretEnvKey = (field) => `RETICLE_SECRET_${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
35
35
  /**
36
36
  * A destructive-action confirmation is one-shot and must never persist into a recording.
37
37
  *
@@ -57,6 +57,18 @@ export function replayActionArgs(value, confirmDangerous = false, field) {
57
57
  }
58
58
  return args;
59
59
  }
60
+ /**
61
+ * The field a compiled recording step names — the same mapping `anchorFieldName` uses on a
62
+ * FlowAnchor, read off the `by`/`value`/`name` shape `compileAnchorArgs` emits.
63
+ */
64
+ function recordedFieldName(step) {
65
+ const by = asString(step['by']);
66
+ if (QueryBy.TESTID === by)
67
+ return asString(step['value']);
68
+ if (QueryBy.ROLE === by)
69
+ return asString(step['name']);
70
+ return undefined;
71
+ }
60
72
  /** The element's source location from an action result, when the framework stamped one. */
61
73
  function sourceFromResult(res) {
62
74
  const source = asRecord(res['source']);
@@ -265,7 +277,7 @@ export async function replayProgram(session, program, confirmDangerous = false)
265
277
  liveSteps.push({
266
278
  ref,
267
279
  action: asString(sub['action']) ?? '',
268
- args: replayActionArgs(sub['args'], confirmDangerous),
280
+ args: replayActionArgs(sub['args'], confirmDangerous, recordedFieldName(sub)),
269
281
  });
270
282
  }
271
283
  // Attribute the step's effects to the step: unattributed effects are learned as ambient
@@ -293,7 +305,7 @@ export async function replayProgram(session, program, confirmDangerous = false)
293
305
  r = await session.command(ReticleCommand.ACT, {
294
306
  ref,
295
307
  action: asString(step.args['action']) ?? '',
296
- args: replayActionArgs(step.args['args'], confirmDangerous),
308
+ args: replayActionArgs(step.args['args'], confirmDangerous, recordedFieldName(step.args)),
297
309
  });
298
310
  }
299
311
  finally {
@@ -18,7 +18,7 @@
18
18
  import { ReplayStatus } from '@reticlehq/core';
19
19
  import type { FileSystemPort } from '../project/fs-port.js';
20
20
  /** Just the shape this needs from a replay — so a test does not have to build a whole result. */
21
- export interface FlakeOutcome {
21
+ interface FlakeOutcome {
22
22
  readonly name: string;
23
23
  readonly status: ReplayStatus;
24
24
  }
@@ -31,3 +31,4 @@ export interface FlakeOutcome {
31
31
  export declare function recordSuiteFlakes(fs: FileSystemPort, reticleRoot: string, runs: readonly {
32
32
  readonly replay: FlakeOutcome;
33
33
  }[]): Promise<readonly string[]>;
34
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { sessionRoot } from '../project/session-root.js';
2
+ import { sessionRoot, sessionProjectId } from '../project/session-root.js';
3
3
  import { verdictForSuite } from './verify-change-verdict.js';
4
4
  import { attributedFailures } from './attributed-failure.js';
5
5
  import { Verified } from '@reticlehq/core';
@@ -62,16 +62,28 @@ export const VERIFY_CHANGE_TOOLS = [
62
62
  ? args['files'].filter((f) => 'string' === typeof f)
63
63
  : [];
64
64
  const since = asString(args['since']);
65
- const changedFiles = await resolveChangedFiles(files, since);
65
+ // The daemon's cwd is not the project — it is wherever the MCP host started it, which for a
66
+ // globally-registered server is `/` or `$HOME`. `deps.reticleRoot` is the project directory
67
+ // this daemon was configured with, and it is the right tree to diff.
68
+ const changed = await resolveChangedFiles(files, since, deps.reticleRoot);
69
+ const changedFiles = changed.files;
66
70
  // Same root flow_save wrote to. A read that resolved differently would report "no flows
67
71
  // covered this change" over flows that exist, which reads as a clean result rather than
68
72
  // an error, so the disagreement would be invisible.
69
- const flows = await loadNamedFlows(deps.fs, sessionRoot(deps, asString(args['sessionId'])));
73
+ // Both halves of the address from one place. The root was already resolved from the session;
74
+ // the id used to come from the daemon's cwd, so they named different projects.
75
+ const sid = asString(args['sessionId']);
76
+ const flows = await loadNamedFlows(deps.fs, sessionRoot(deps, sid), sessionProjectId(deps, sid));
70
77
  const { affected, unknownProvenance } = affectedSavedFlows(flows, changedFiles);
71
78
  if (0 === changedFiles.length) {
72
79
  return {
73
80
  verified: Verified.UNKNOWN,
74
- because: 'no changed files were given, so there was nothing to decide about',
81
+ // A git failure and a clean tree both arrive here with no files, and they are opposite
82
+ // answers: one means there was nothing to decide about, the other means the question was
83
+ // never asked. `unknown` is right either way, but the REASON is what the caller acts on.
84
+ because: changed.failed
85
+ ? `could not read the diff for \`${String(since)}\`, so nothing was compared: ${changed.reason ?? 'git failed'}`
86
+ : 'no changed files were given, so there was nothing to decide about',
75
87
  changedFiles,
76
88
  flowsRun: [],
77
89
  unknownProvenance,
@@ -1,2 +1,16 @@
1
1
  import type { Predicate } from '../events/predicate.js';
2
2
  export declare function readsDomState(predicate: Predicate): boolean;
3
+ /**
4
+ * #889: an `already_true` verdict says the declared consequence held before the action, so nothing
5
+ * was proven — but a `text`/`element` predicate matches DOM presence by default, not visibility (a
6
+ * caller has to pass `visible: true` to ask for that). A dialog's content mounted-but-hidden before
7
+ * the click therefore reads as "already true", identically to genuinely-visible content that was
8
+ * already on screen — and the `already_true` message named neither which node it matched nor that
9
+ * the match was invisible, which is what made it read as proof of nothing rather than as the
10
+ * mid-load/hidden-mount trap it actually was.
11
+ *
12
+ * True only when the predicate itself did not ask for a state (an explicit `visible`/other state
13
+ * constraint already means the caller saw and handled this) AND every matched element is hidden —
14
+ * one visible match among several is a fair, ordinary read and is left alone.
15
+ */
16
+ export declare function alreadyTrueHiddenMatch(predicate: Predicate, evidence: unknown): boolean;
@@ -1,15 +1,17 @@
1
1
  /**
2
2
  * Which predicates can be satisfied by something that was already true before the action.
3
3
  *
4
- * Event-based kinds (net, signal, route, console, animation, settled) are evaluated against the
4
+ * Event-based kinds (net, signal, console, animation, settled) are evaluated against the
5
5
  * event buffer floored at the act's own cursor, so a stale event cannot satisfy them — that floor is
6
- * why `act_and_wait` can trust them at all. `state` is read through the same floored path.
6
+ * why `act_and_wait` can trust them at all.
7
7
  *
8
- * `element` and `text` read the LIVE DOM, where no floor exists. A condition that held before the
8
+ * `element` and `text` read the LIVE DOM, `route` can fall back to the current route, and `state` reads
9
+ * live store memory via STATE_READ — where no event floor applies. A condition that held before the
9
10
  * click holds after it and passes instantly, whatever the action did. Measured in the field: a click
10
11
  * asserted with `{ kind: 'text', contains: 'Parallel Routes' }` returned `verified: "yes"` in 478ms
11
12
  * against `routeChanges: 0`, because the predicate matched the nav link that was already on screen —
12
- * the real navigation landed 1.8 seconds later.
13
+ * the real navigation landed 1.8 seconds later. Similarly, a pre-existing store value (e.g. cart.count == 3)
14
+ * satisfies an inert action if not checked before dispatch.
13
15
  *
14
16
  * So these are the kinds worth evaluating BEFORE the act, to find out whether the green means
15
17
  * anything.
@@ -31,9 +33,15 @@ export function readsDomState(predicate) {
31
33
  // One extra query on the act path buys `already_true`, reported as UNKNOWN with the reason
32
34
  // rather than as a pass. The fallback removed a false red; this is what stops it becoming a
33
35
  // false green, and that is the trade this codebase never makes.
36
+ //
37
+ // STATE is here for the same reason: it is evaluated via STATE_READ against live in-memory stores
38
+ // rather than through the floored event buffer. If the store already holds the expected value
39
+ // before dispatch, an inert click would immediately pass post-dispatch on the pre-existing state.
40
+ // Evaluating before dispatch routes that pre-existing condition into already_true.
34
41
  case PredicateKind.ELEMENT:
35
42
  case PredicateKind.TEXT:
36
43
  case PredicateKind.ROUTE:
44
+ case PredicateKind.STATE:
37
45
  return true;
38
46
  case PredicateKind.ALL_OF:
39
47
  case PredicateKind.ANY_OF:
@@ -44,3 +52,38 @@ export function readsDomState(predicate) {
44
52
  return false;
45
53
  }
46
54
  }
55
+ /** True when `value` looks like an element/text predicate's passing evidence — an array of descriptors. */
56
+ function isDescriptorArray(value) {
57
+ if (!Array.isArray(value))
58
+ return false;
59
+ return value.every((v) => {
60
+ if ('object' !== typeof v || null === v)
61
+ return false;
62
+ return 'boolean' === typeof v['visible'];
63
+ });
64
+ }
65
+ /**
66
+ * #889: an `already_true` verdict says the declared consequence held before the action, so nothing
67
+ * was proven — but a `text`/`element` predicate matches DOM presence by default, not visibility (a
68
+ * caller has to pass `visible: true` to ask for that). A dialog's content mounted-but-hidden before
69
+ * the click therefore reads as "already true", identically to genuinely-visible content that was
70
+ * already on screen — and the `already_true` message named neither which node it matched nor that
71
+ * the match was invisible, which is what made it read as proof of nothing rather than as the
72
+ * mid-load/hidden-mount trap it actually was.
73
+ *
74
+ * True only when the predicate itself did not ask for a state (an explicit `visible`/other state
75
+ * constraint already means the caller saw and handled this) AND every matched element is hidden —
76
+ * one visible match among several is a fair, ordinary read and is left alone.
77
+ */
78
+ export function alreadyTrueHiddenMatch(predicate, evidence) {
79
+ if (predicate.kind !== PredicateKind.ELEMENT && predicate.kind !== PredicateKind.TEXT) {
80
+ return false;
81
+ }
82
+ if (predicate.kind === PredicateKind.ELEMENT && predicate.state !== undefined)
83
+ return false;
84
+ if (predicate.kind === PredicateKind.TEXT && true === predicate.visible)
85
+ return false;
86
+ if (!isDescriptorArray(evidence) || 0 === evidence.length)
87
+ return false;
88
+ return evidence.every((el) => !el.visible);
89
+ }
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export { BlindSpotKind } from '@reticlehq/core';
8
8
  import { BlindSpotKind, type ReticleEvent } from '@reticlehq/core';
9
- export interface BlindSpot {
9
+ interface BlindSpot {
10
10
  kind: BlindSpotKind;
11
11
  count: number;
12
12
  }
@@ -89,6 +89,7 @@ interface AbsencePredicate {
89
89
  query?: {
90
90
  scope?: unknown;
91
91
  };
92
+ predicate?: AbsencePredicate;
92
93
  }
93
94
  /**
94
95
  * When an absence assertion targets a page with regions Reticle cannot observe, "the element is
@@ -127,5 +128,6 @@ export declare function isStateUnwatched(spots: readonly BlindSpot[]): boolean;
127
128
  export declare function restsOnCompleteWindow(predicate: {
128
129
  kind: string;
129
130
  absent?: boolean;
131
+ count?: number;
130
132
  predicate?: unknown;
131
133
  }): boolean;
@@ -176,7 +176,19 @@ function droppedByTransport(events) {
176
176
  * - CLOSED_SHADOW_ROOT — a subtree Reticle cannot see into
177
177
  */
178
178
  export function absenceBlindSpotNote(predicate, spots) {
179
- if ('element' !== predicate.kind || true !== predicate.absent)
179
+ // `not(element)` is the third spelling of an absence assertion — the `not` wrapper IS the
180
+ // negation, so the inner predicate will not carry `absent: true`. Unwrap and synthesize it.
181
+ // `not(element { absent: true })` is a double negative — presence — and a positive match is
182
+ // not threatened by an unobservable region.
183
+ if (PredicateKind.NOT === predicate.kind && predicate.predicate !== undefined) {
184
+ if (PredicateKind.ELEMENT === predicate.predicate.kind) {
185
+ if (true === predicate.predicate.absent)
186
+ return undefined;
187
+ return absenceBlindSpotNote({ ...predicate.predicate, absent: true }, spots);
188
+ }
189
+ return undefined;
190
+ }
191
+ if (PredicateKind.ELEMENT !== predicate.kind || true !== predicate.absent)
180
192
  return undefined;
181
193
  const relevant = spots.filter((spot) => spot.count > 0 &&
182
194
  (spot.kind === BlindSpotKind.CROSS_ORIGIN_IFRAME
@@ -221,5 +233,16 @@ export function isStateUnwatched(spots) {
221
233
  export function restsOnCompleteWindow(predicate) {
222
234
  if (PredicateKind.NOT === predicate.kind)
223
235
  return true;
236
+ // An exact cardinality of ZERO is the third spelling of an absence claim, and reading only
237
+ // `absent` missed it: `{ kind: "net", urlContains: "/api/auth/sign-in", count: 0 }` says "this
238
+ // request was never made", and the call the buffer evicted is precisely the disproof. It was
239
+ // graded `yes` over a window known to have lost scarce evidence — the exact false green the two
240
+ // clauses above exist to prevent, reached by the one spelling they did not cover (#668).
241
+ //
242
+ // Only zero. `count: 2` asserts calls were MADE and found them; events aged out elsewhere in the
243
+ // buffer do not unmake a positive finding, which is the same reason a plain presence assertion is
244
+ // left alone here.
245
+ if (0 === predicate.count)
246
+ return true;
224
247
  return true === predicate.absent;
225
248
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * What to tell a caller whose assertion needs response bodies, given what the connected SDK can do.
3
+ *
4
+ * The remedy used to be one fixed sentence naming `captureNetworkBodies`. Reported from the field:
5
+ * six verdicts came back `unknown`/`outcome_unread` advising that setting against a pinned
6
+ * `@reticlehq/react` from before it existed. The reporter set the env var, restarted, got the
7
+ * identical message, and worked it out by elimination.
8
+ *
9
+ * The daemon is TOLD the page's SDK version at HELLO and threw it away after computing skew. Nothing
10
+ * new has to be observed to say the true thing — it only has to be kept.
11
+ *
12
+ * Same class as the version-skew remedy that named a React package on Vue projects: remedy text that
13
+ * does not check whether it applies. A wrong remedy is worse than none, because it is followed.
14
+ */
15
+ /** The release that introduced `captureNetworkBodies` — see the browser observer's history. */
16
+ export declare const BODY_CAPTURE_MIN_VERSION = "2.4.0";
17
+ /**
18
+ * The remedy for this session, or the honest statement that there is none.
19
+ *
20
+ * An UNKNOWN version is treated as capable. A hand-wired connect reports none, and guessing "too
21
+ * old" there would hide a working fix from someone who could have used it; the opposite guess costs
22
+ * one wasted read. The asymmetry decides it.
23
+ */
24
+ export declare function bodyCaptureRemedy(sdkVersion: string | undefined): string;
25
+ /**
26
+ * Refuse a body clause the session cannot answer, BEFORE the action is spent.
27
+ *
28
+ * Reported: an `act_and_wait` matched the right call and returned `verified: "no"` with "a matching
29
+ * call with no recorded body", because that project's `connect()` does not pass
30
+ * `captureNetworkBodies` — and the reporter could not change it, since it was not their project's
31
+ * config to edit for an unrelated verification task. The action bought nothing that was not knowable
32
+ * in advance, and on a drive that mutates state an action is not always repeatable. That is what
33
+ * makes this a pre-flight rather than a better failure message.
34
+ *
35
+ * Refuses ONLY on a DECLARED `captureBodies: false`. An SDK too old to announce the setting sends
36
+ * nothing, and refusing on silence would break every session predating the announcement for a clause
37
+ * many of them satisfy — the same asymmetry that makes an unknown VERSION count as capable.
38
+ */
39
+ export declare function bodyClauseRefusal(predicate: unknown, session: {
40
+ captureBodies?: boolean | undefined;
41
+ sdkVersion?: string | undefined;
42
+ }): string | undefined;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * What to tell a caller whose assertion needs response bodies, given what the connected SDK can do.
3
+ *
4
+ * The remedy used to be one fixed sentence naming `captureNetworkBodies`. Reported from the field:
5
+ * six verdicts came back `unknown`/`outcome_unread` advising that setting against a pinned
6
+ * `@reticlehq/react` from before it existed. The reporter set the env var, restarted, got the
7
+ * identical message, and worked it out by elimination.
8
+ *
9
+ * The daemon is TOLD the page's SDK version at HELLO and threw it away after computing skew. Nothing
10
+ * new has to be observed to say the true thing — it only has to be kept.
11
+ *
12
+ * Same class as the version-skew remedy that named a React package on Vue projects: remedy text that
13
+ * does not check whether it applies. A wrong remedy is worse than none, because it is followed.
14
+ */
15
+ /** The release that introduced `captureNetworkBodies` — see the browser observer's history. */
16
+ export const BODY_CAPTURE_MIN_VERSION = '2.4.0';
17
+ /**
18
+ * Compare two dotted versions numerically.
19
+ *
20
+ * String comparison inverts exactly where it hurts: `'2.10.0' < '2.4.0'` lexically, so a NEWER SDK
21
+ * would be told it is too old and the working remedy withheld. A prerelease suffix is dropped rather
22
+ * than parsed — `2.13.0-rc.1` is 2.13 for this question, and nothing here needs finer.
23
+ */
24
+ function isAtLeast(version, minimum) {
25
+ const parts = (v) => v
26
+ .split('-')[0]
27
+ ?.split('.')
28
+ .map((n) => Number.parseInt(n, 10) || 0) ?? [];
29
+ const have = parts(version);
30
+ const want = parts(minimum);
31
+ for (let i = 0; i < Math.max(have.length, want.length); i += 1) {
32
+ const a = have[i] ?? 0;
33
+ const b = want[i] ?? 0;
34
+ if (a !== b)
35
+ return a > b;
36
+ }
37
+ return true;
38
+ }
39
+ /** The sentence naming the setting — only ever produced for an SDK that HAS it. */
40
+ const ENABLE_IT = 'Turn it on where your app calls connect(): `reticle.connect({ captureNetworkBodies: true })`, ' +
41
+ 'or for the Vite plugin `reticle({ captureNetworkBodies: true })` / VITE_RETICLE_CAPTURE_BODIES=1. ' +
42
+ 'Then re-run the action.';
43
+ /**
44
+ * The remedy for this session, or the honest statement that there is none.
45
+ *
46
+ * An UNKNOWN version is treated as capable. A hand-wired connect reports none, and guessing "too
47
+ * old" there would hide a working fix from someone who could have used it; the opposite guess costs
48
+ * one wasted read. The asymmetry decides it.
49
+ */
50
+ export function bodyCaptureRemedy(sdkVersion) {
51
+ if (sdkVersion !== undefined && !isAtLeast(sdkVersion, BODY_CAPTURE_MIN_VERSION)) {
52
+ return (`this page's SDK is ${sdkVersion}, and body capture needs ${BODY_CAPTURE_MIN_VERSION} or ` +
53
+ 'newer — the setting does not exist in your version, so there is nothing to switch on. ' +
54
+ 'Upgrade the SDK, or assert on something else this session can see.');
55
+ }
56
+ return ENABLE_IT;
57
+ }
58
+ /** Clause names that can only be answered from a recorded body. */
59
+ const BODY_CLAUSE_FIELDS = ['bodyContains', 'requestBodyContains'];
60
+ /** Does this predicate, or anything nested in it, ask about a body? */
61
+ function asksAboutBody(predicate) {
62
+ if (null === predicate || 'object' !== typeof predicate)
63
+ return false;
64
+ const node = predicate;
65
+ if (BODY_CLAUSE_FIELDS.some((f) => node[f] !== undefined))
66
+ return true;
67
+ // The reported shape is an `allOf` carrying route + console + the net clause that needs bodies.
68
+ // Checking only the top level would miss every realistic call.
69
+ const nested = node['predicates'] ?? node['predicate'];
70
+ if (Array.isArray(nested))
71
+ return nested.some(asksAboutBody);
72
+ return asksAboutBody(nested);
73
+ }
74
+ /**
75
+ * Refuse a body clause the session cannot answer, BEFORE the action is spent.
76
+ *
77
+ * Reported: an `act_and_wait` matched the right call and returned `verified: "no"` with "a matching
78
+ * call with no recorded body", because that project's `connect()` does not pass
79
+ * `captureNetworkBodies` — and the reporter could not change it, since it was not their project's
80
+ * config to edit for an unrelated verification task. The action bought nothing that was not knowable
81
+ * in advance, and on a drive that mutates state an action is not always repeatable. That is what
82
+ * makes this a pre-flight rather than a better failure message.
83
+ *
84
+ * Refuses ONLY on a DECLARED `captureBodies: false`. An SDK too old to announce the setting sends
85
+ * nothing, and refusing on silence would break every session predating the announcement for a clause
86
+ * many of them satisfy — the same asymmetry that makes an unknown VERSION count as capable.
87
+ */
88
+ export function bodyClauseRefusal(predicate, session) {
89
+ if (false !== session.captureBodies)
90
+ return undefined;
91
+ if (!asksAboutBody(predicate))
92
+ return undefined;
93
+ return ('this assertion reads a request/response BODY, and this session is not recording them — it ' +
94
+ `would fail whatever the app did. Nothing ran, so no action was spent. ${bodyCaptureRemedy(session.sdkVersion)}`);
95
+ }
@@ -1,4 +1,4 @@
1
- import { type Intent, type JournalAction } from '@reticlehq/core';
1
+ import { type Intent, type JournalAction } from '@reticlehq/core/artifacts';
2
2
  /**
3
3
  * Were `reticle_context` and `reticle_intent` used at all — and did using them change anything?
4
4
  *
@@ -94,7 +94,7 @@ export declare function noteToolDispatched(session: {
94
94
  capture?: CaptureLedger;
95
95
  }, tool: string): void;
96
96
  /** What one session's use of the two features looks like. Everything but `observed` is omitted when nothing was recorded. */
97
- export interface FeatureCapture {
97
+ interface FeatureCapture {
98
98
  /** False when this daemon recorded nothing for the session — "not watched", never "not used". */
99
99
  observed: boolean;
100
100
  /** The ledger dropped calls, so every count is a floor. Present only when true. */
@@ -148,3 +148,4 @@ export declare function foldFeatureCapture(input: {
148
148
  /** The session's dispatched-action count now, so a run that ended on an action is not read as idle. */
149
149
  finalActions: number;
150
150
  }): FeatureCapture;
151
+ export {};
@@ -1,4 +1,4 @@
1
- import { IntentState, JournalVerdictEffectSchema, RUN_ESTABLISHED_CAP, } from '@reticlehq/core';
1
+ import { IntentState, JournalVerdictEffectSchema, RUN_ESTABLISHED_CAP, } from '@reticlehq/core/artifacts';
2
2
  import { subjectOf } from '../runs/run-context.js';
3
3
  import { ReticleTool } from '../tools/tool-names.js';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { type InstrumentationGap } from '@reticlehq/core';
1
+ import { type InstrumentationGap } from '@reticlehq/core/artifacts';
2
2
  /**
3
3
  * What this session still cannot see, accumulated across its verdicts.
4
4
  *