@reticlehq/server 2.11.0 → 2.13.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 (513) hide show
  1. package/SKILL.md +93 -111
  2. package/dist/bridge/auth-failure-reason.d.ts +6 -2
  3. package/dist/bridge/auth-failure-reason.js +15 -8
  4. package/dist/bridge/bridge.d.ts +18 -14
  5. package/dist/bridge/bridge.js +248 -165
  6. package/dist/bridge/bridge.test-harness.d.ts +2 -0
  7. package/dist/bridge/bridge.test-harness.js +8 -1
  8. package/dist/bridge/pairing-token.d.ts +5 -0
  9. package/dist/bridge/pairing-token.js +28 -0
  10. package/dist/bridge/protocol-skew.d.ts +37 -0
  11. package/dist/bridge/protocol-skew.js +45 -0
  12. package/dist/capsule/capsule-store.d.ts +8 -7
  13. package/dist/capsule/capsule-store.js +1 -1
  14. package/dist/capsule/causal-summary.d.ts +2 -2
  15. package/dist/capsule/causal-summary.js +7 -2
  16. package/dist/chromium-launch-options.d.ts +28 -0
  17. package/dist/chromium-launch-options.js +29 -0
  18. package/dist/cli/cli-doctor.js +39 -1
  19. package/dist/cli/cli-flow-commands.d.ts +3 -1
  20. package/dist/cli/cli-flow-commands.js +34 -4
  21. package/dist/cli/cli-kill.d.ts +2 -1
  22. package/dist/cli/cli-launch.d.ts +11 -1
  23. package/dist/cli/cli-launch.js +59 -10
  24. package/dist/cli/cli-parse.d.ts +17 -1
  25. package/dist/cli/cli-parse.js +238 -12
  26. package/dist/cli/cli-update-commands.js +20 -1
  27. package/dist/cli/cli-verify.d.ts +2 -1
  28. package/dist/cli/cli-verify.js +5 -4
  29. package/dist/cli/cloud-cli.js +428 -253
  30. package/dist/cli/cloud-keystore.d.ts +37 -0
  31. package/dist/cli/cloud-keystore.js +97 -0
  32. package/dist/cli/cloud-kit.d.ts +37 -0
  33. package/dist/cli/cloud-kit.js +121 -0
  34. package/dist/cli/cloud-login.d.ts +17 -0
  35. package/dist/cli/cloud-login.js +183 -0
  36. package/dist/cli/cloud-session.d.ts +48 -0
  37. package/dist/cli/cloud-session.js +53 -0
  38. package/dist/cli/config-discovery.d.ts +2 -1
  39. package/dist/cli/config-discovery.js +1 -0
  40. package/dist/cli/daemon-start-options.d.ts +32 -0
  41. package/dist/cli/daemon-start-options.js +38 -0
  42. package/dist/cli/device-flow.d.ts +76 -0
  43. package/dist/cli/device-flow.js +56 -0
  44. package/dist/cli/doctor-rows.d.ts +12 -1
  45. package/dist/cli/doctor-rows.js +12 -1
  46. package/dist/cli/drive-attach.d.ts +13 -0
  47. package/dist/cli/drive-attach.js +18 -0
  48. package/dist/cli/drive-command.js +7 -3
  49. package/dist/cli/gate-exit.d.ts +21 -0
  50. package/dist/cli/gate-exit.js +21 -0
  51. package/dist/cli/gate-hook-message.d.ts +33 -0
  52. package/dist/cli/gate-hook-message.js +46 -0
  53. package/dist/cli/mcp-command.d.ts +25 -0
  54. package/dist/cli/mcp-command.js +174 -0
  55. package/dist/cli/project-name.d.ts +30 -0
  56. package/dist/cli/project-name.js +44 -0
  57. package/dist/cli/sibling-ports.d.ts +37 -0
  58. package/dist/cli/sibling-ports.js +56 -0
  59. package/dist/cli/status-next-action.d.ts +14 -0
  60. package/dist/cli/status-next-action.js +4 -4
  61. package/dist/cli.d.ts +1 -0
  62. package/dist/cli.js +167 -186
  63. package/dist/cloud/cloud-config.d.ts +24 -2
  64. package/dist/cloud/cloud-config.js +64 -5
  65. package/dist/cloud/cloud-sync.d.ts +16 -5
  66. package/dist/cloud/cloud-sync.js +64 -1
  67. package/dist/cloud/sync-cycle.d.ts +110 -0
  68. package/dist/cloud/sync-cycle.js +270 -0
  69. package/dist/cloud/sync-daemon.d.ts +69 -0
  70. package/dist/cloud/sync-daemon.js +260 -0
  71. package/dist/cloud/sync-disk.d.ts +9 -0
  72. package/dist/cloud/sync-disk.js +191 -0
  73. package/dist/cloud/sync-hash.d.ts +2 -0
  74. package/dist/cloud/sync-hash.js +35 -0
  75. package/dist/crawl/crawl-tools.js +5 -3
  76. package/dist/crawl/crawl.d.ts +12 -13
  77. package/dist/crawl/crawl.js +25 -3
  78. package/dist/daemon/daemon-resolve.d.ts +122 -0
  79. package/dist/daemon/daemon-resolve.js +187 -0
  80. package/dist/daemon/dev-servers.d.ts +15 -0
  81. package/dist/daemon/dev-servers.js +68 -0
  82. package/dist/daemon/free-port.d.ts +29 -0
  83. package/dist/daemon/free-port.js +55 -0
  84. package/dist/daemon/heartbeat.d.ts +0 -4
  85. package/dist/daemon/heartbeat.js +2 -2
  86. package/dist/daemon/wake-decision.d.ts +32 -0
  87. package/dist/daemon/wake-decision.js +38 -0
  88. package/dist/dev/stale-issue-guard.d.ts +0 -2
  89. package/dist/dev/stale-issue-guard.js +1 -1
  90. package/dist/domain/domain-tools.js +2 -2
  91. package/dist/events/contradictions.d.ts +59 -0
  92. package/dist/events/contradictions.js +253 -27
  93. package/dist/events/declared.d.ts +17 -0
  94. package/dist/events/declared.js +43 -1
  95. package/dist/events/echo-mismatch.js +65 -1
  96. package/dist/events/event-filters.d.ts +8 -0
  97. package/dist/events/event-filters.js +19 -2
  98. package/dist/events/observed-in-window.d.ts +12 -0
  99. package/dist/events/observed-in-window.js +17 -0
  100. package/dist/events/predicate-asks.d.ts +13 -0
  101. package/dist/events/predicate-asks.js +22 -0
  102. package/dist/events/predicate-eval.js +117 -27
  103. package/dist/events/predicate-parse.d.ts +0 -6
  104. package/dist/events/predicate-parse.js +43 -3
  105. package/dist/events/predicate-precheck.d.ts +8 -0
  106. package/dist/events/predicate-precheck.js +41 -0
  107. package/dist/events/predicate-route.d.ts +14 -0
  108. package/dist/events/predicate-route.js +36 -8
  109. package/dist/events/predicate-schema.d.ts +44 -0
  110. package/dist/events/predicate-schema.js +126 -23
  111. package/dist/events/predicate.d.ts +20 -0
  112. package/dist/events/predicate.js +77 -6
  113. package/dist/events/split-text-miss.d.ts +30 -0
  114. package/dist/events/split-text-miss.js +44 -0
  115. package/dist/flows/coverage.d.ts +0 -8
  116. package/dist/flows/coverage.js +1 -1
  117. package/dist/flows/decision.d.ts +5 -1
  118. package/dist/flows/decision.js +33 -7
  119. package/dist/flows/flake.d.ts +6 -8
  120. package/dist/flows/flake.js +1 -1
  121. package/dist/flows/flow-intent.d.ts +52 -0
  122. package/dist/flows/flow-intent.js +123 -0
  123. package/dist/flows/flow-memory-consult.d.ts +55 -0
  124. package/dist/flows/flow-memory-consult.js +38 -0
  125. package/dist/flows/flow-replay-run.d.ts +18 -7
  126. package/dist/flows/flow-replay-run.js +263 -23
  127. package/dist/flows/flow-replay.js +11 -2
  128. package/dist/flows/flow-step-runners.d.ts +8 -0
  129. package/dist/flows/flow-step-runners.js +8 -2
  130. package/dist/flows/flow-store-for-session.d.ts +31 -0
  131. package/dist/flows/flow-store-for-session.js +33 -0
  132. package/dist/flows/flow-success.js +15 -3
  133. package/dist/flows/flow-tools.js +87 -33
  134. package/dist/flows/flows.d.ts +14 -1
  135. package/dist/flows/flows.js +502 -24
  136. package/dist/flows/heal-run.js +5 -2
  137. package/dist/flows/predicate-to-expect.d.ts +17 -12
  138. package/dist/flows/predicate-to-expect.js +36 -15
  139. package/dist/flows/recordings.d.ts +13 -1
  140. package/dist/flows/recordings.js +17 -2
  141. package/dist/flows/replay.d.ts +22 -2
  142. package/dist/flows/replay.js +28 -2
  143. package/dist/flows/server-verify.js +16 -2
  144. package/dist/flows/verify-change-tools.js +9 -3
  145. package/dist/honesty/blind-spots.d.ts +51 -15
  146. package/dist/honesty/blind-spots.js +64 -4
  147. package/dist/honesty/feature-capture.d.ts +150 -0
  148. package/dist/honesty/feature-capture.js +233 -0
  149. package/dist/honesty/honesty.d.ts +24 -0
  150. package/dist/honesty/honesty.js +25 -1
  151. package/dist/honesty/instrumentation-gaps.d.ts +39 -6
  152. package/dist/honesty/instrumentation-gaps.js +88 -5
  153. package/dist/honesty/tool-hit-rate.d.ts +86 -0
  154. package/dist/honesty/tool-hit-rate.js +90 -0
  155. package/dist/honesty/undeclared-change.d.ts +51 -0
  156. package/dist/honesty/undeclared-change.js +56 -0
  157. package/dist/honesty/verified.d.ts +16 -0
  158. package/dist/honesty/verified.js +84 -5
  159. package/dist/http-server.d.ts +0 -1
  160. package/dist/http-server.js +13 -1
  161. package/dist/hunt/hunt-report.d.ts +0 -2
  162. package/dist/hunt/hunt-report.js +1 -1
  163. package/dist/impact/impact-recorder.d.ts +31 -8
  164. package/dist/impact/impact-recorder.js +104 -21
  165. package/dist/impact/impact-store.d.ts +13 -4
  166. package/dist/impact/impact-store.js +44 -3
  167. package/dist/index.d.ts +4 -1
  168. package/dist/index.js +113 -7
  169. package/dist/init/agent-rules.d.ts +30 -6
  170. package/dist/init/agent-rules.js +54 -13
  171. package/dist/init/astro-patch.d.ts +16 -0
  172. package/dist/init/astro-patch.js +28 -0
  173. package/dist/init/capabilities.d.ts +4 -3
  174. package/dist/init/capabilities.js +23 -3
  175. package/dist/init/closing-hint.d.ts +36 -0
  176. package/dist/init/closing-hint.js +120 -0
  177. package/dist/init/confirm.d.ts +27 -28
  178. package/dist/init/confirm.js +51 -11
  179. package/dist/init/cra.d.ts +34 -5
  180. package/dist/init/cra.js +96 -25
  181. package/dist/init/csp-check.js +17 -2
  182. package/dist/init/csp-doctor.d.ts +8 -1
  183. package/dist/init/csp-doctor.js +8 -3
  184. package/dist/init/dev-script.d.ts +50 -0
  185. package/dist/init/dev-script.js +66 -0
  186. package/dist/init/format-generated.d.ts +18 -0
  187. package/dist/init/format-generated.js +39 -0
  188. package/dist/init/install-hint.d.ts +9 -0
  189. package/dist/init/install-hint.js +29 -0
  190. package/dist/init/mcp-clients.d.ts +7 -0
  191. package/dist/init/mcp-clients.js +7 -0
  192. package/dist/init/mcp.d.ts +17 -6
  193. package/dist/init/mcp.js +27 -11
  194. package/dist/init/node-io.js +11 -1
  195. package/dist/init/plan-framework.d.ts +0 -5
  196. package/dist/init/plan-framework.js +147 -37
  197. package/dist/init/plan.d.ts +30 -37
  198. package/dist/init/plan.js +50 -60
  199. package/dist/init/preflight.d.ts +28 -0
  200. package/dist/init/preflight.js +38 -0
  201. package/dist/init/refresh-rules.d.ts +39 -0
  202. package/dist/init/refresh-rules.js +51 -0
  203. package/dist/init/run.d.ts +32 -35
  204. package/dist/init/run.js +151 -202
  205. package/dist/init/slash-command.d.ts +1 -1
  206. package/dist/init/snippets.js +90 -31
  207. package/dist/init/vite-config.d.ts +1 -1
  208. package/dist/init/vite-config.js +39 -25
  209. package/dist/init/workspace-apps.d.ts +17 -10
  210. package/dist/init/workspace-apps.js +110 -0
  211. package/dist/input/network-mock-tools.js +3 -6
  212. package/dist/input/real-input.d.ts +2 -0
  213. package/dist/input/real-input.js +28 -7
  214. package/dist/input/scroll-find.d.ts +7 -4
  215. package/dist/input/scroll-find.js +63 -25
  216. package/dist/input/scroll-tools.js +4 -6
  217. package/dist/input/viewport-tools.js +5 -4
  218. package/dist/intent/inline-intent.d.ts +37 -0
  219. package/dist/intent/inline-intent.js +193 -0
  220. package/dist/intent/intent-shard-store.d.ts +72 -0
  221. package/dist/intent/intent-shard-store.js +203 -0
  222. package/dist/intent/intent-shard.d.ts +411 -0
  223. package/dist/intent/intent-shard.js +176 -0
  224. package/dist/intent/intent-store.d.ts +49 -0
  225. package/dist/intent/intent-store.js +133 -0
  226. package/dist/intent/intent-subject.d.ts +45 -0
  227. package/dist/intent/intent-subject.js +177 -0
  228. package/dist/intent/intent-tools.d.ts +2 -0
  229. package/dist/intent/intent-tools.js +143 -0
  230. package/dist/intent/open-intents.d.ts +42 -0
  231. package/dist/intent/open-intents.js +40 -0
  232. package/dist/journal/envelope.d.ts +26 -26
  233. package/dist/journal/journal-recorder.d.ts +23 -0
  234. package/dist/journal/journal-recorder.js +35 -0
  235. package/dist/license/license-env.d.ts +29 -0
  236. package/dist/license/license-env.js +148 -0
  237. package/dist/loopback-agent.d.ts +31 -0
  238. package/dist/loopback-agent.js +57 -0
  239. package/dist/mcp/attach-memory.d.ts +83 -0
  240. package/dist/mcp/attach-memory.js +185 -0
  241. package/dist/mcp/client-identity.d.ts +31 -0
  242. package/dist/mcp/client-identity.js +51 -0
  243. package/dist/mcp/mcp-post-transport.d.ts +26 -0
  244. package/dist/mcp/mcp-post-transport.js +109 -0
  245. package/dist/mcp/mcp-proxy.d.ts +2 -8
  246. package/dist/mcp/mcp-proxy.js +64 -62
  247. package/dist/mcp/mcp.d.ts +2 -0
  248. package/dist/mcp/mcp.js +52 -24
  249. package/dist/mcp/proxy-backoff.d.ts +11 -0
  250. package/dist/mcp/proxy-backoff.js +13 -0
  251. package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
  252. package/dist/mcp/proxy-daemon-probe.js +7 -1
  253. package/dist/mcp/proxy-handshake.d.ts +23 -0
  254. package/dist/mcp/proxy-handshake.js +31 -0
  255. package/dist/mcp/server-instructions.js +45 -3
  256. package/dist/mcp/tool-catalog-cache.d.ts +16 -0
  257. package/dist/mcp/tool-catalog-cache.js +22 -0
  258. package/dist/memory/memory-tools.d.ts +2 -0
  259. package/dist/memory/memory-tools.js +82 -0
  260. package/dist/memory/project-memory.d.ts +34 -0
  261. package/dist/memory/project-memory.js +96 -0
  262. package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
  263. package/dist/oracles/flow-instrument-gaps.js +4 -5
  264. package/dist/oracles/propose-consequences.js +12 -3
  265. package/dist/oracles/self-instrument.d.ts +9 -9
  266. package/dist/oracles/self-instrument.js +19 -13
  267. package/dist/pool/browser-pool.d.ts +75 -5
  268. package/dist/pool/browser-pool.js +144 -5
  269. package/dist/pool/playwright-launcher.js +12 -1
  270. package/dist/project/fs-port.d.ts +3 -0
  271. package/dist/project/fs-port.js +3 -2
  272. package/dist/project/memory-fs.js +6 -1
  273. package/dist/project/project-tools.js +6 -35
  274. package/dist/project/reticle-dir.d.ts +17 -2
  275. package/dist/project/reticle-dir.js +22 -4
  276. package/dist/runs/context-tools.d.ts +2 -0
  277. package/dist/runs/context-tools.js +89 -0
  278. package/dist/runs/run-context.d.ts +40 -0
  279. package/dist/runs/run-context.js +158 -0
  280. package/dist/runs/run-diff.d.ts +2 -1
  281. package/dist/runs/run-store.d.ts +10 -0
  282. package/dist/runs/run-store.js +10 -0
  283. package/dist/runs/verification-sync.d.ts +0 -11
  284. package/dist/runs/verification-sync.js +24 -3
  285. package/dist/runs/verify-server.d.ts +8 -1
  286. package/dist/runs/verify-server.js +14 -2
  287. package/dist/session/command-timeout.d.ts +5 -2
  288. package/dist/session/command-timeout.js +5 -4
  289. package/dist/session/dev-server-probe.d.ts +0 -8
  290. package/dist/session/dev-server-probe.js +1 -1
  291. package/dist/session/last-act.d.ts +7 -1
  292. package/dist/session/last-act.js +2 -2
  293. package/dist/session/lease-visibility.d.ts +67 -0
  294. package/dist/session/lease-visibility.js +76 -0
  295. package/dist/session/live-control-tools.js +1 -42
  296. package/dist/session/no-session-diagnosis.d.ts +33 -0
  297. package/dist/session/no-session-diagnosis.js +82 -24
  298. package/dist/session/no-session-next-action.d.ts +12 -0
  299. package/dist/session/no-session-next-action.js +77 -6
  300. package/dist/session/no-session-watch.d.ts +18 -6
  301. package/dist/session/no-session-watch.js +125 -75
  302. package/dist/session/output-budget.js +4 -1
  303. package/dist/session/pending-commands.d.ts +11 -1
  304. package/dist/session/pending-commands.js +12 -2
  305. package/dist/session/resolve-within.d.ts +34 -0
  306. package/dist/session/resolve-within.js +53 -0
  307. package/dist/session/session-health.d.ts +9 -0
  308. package/dist/session/session-health.js +23 -0
  309. package/dist/session/session-info.d.ts +18 -0
  310. package/dist/session/session-info.js +11 -0
  311. package/dist/session/session-manager.d.ts +14 -0
  312. package/dist/session/session-manager.js +111 -4
  313. package/dist/session/session-mirror.d.ts +16 -0
  314. package/dist/session/session-mirror.js +22 -0
  315. package/dist/session/session-recommendation.d.ts +19 -5
  316. package/dist/session/session-recommendation.js +25 -9
  317. package/dist/session/session-successor.d.ts +37 -0
  318. package/dist/session/session-successor.js +113 -0
  319. package/dist/session/session-tools.js +2 -2
  320. package/dist/session/session.d.ts +53 -3
  321. package/dist/session/session.js +162 -9
  322. package/dist/session/wall-clock.d.ts +12 -0
  323. package/dist/session/wall-clock.js +14 -0
  324. package/dist/setup/agent-configs.d.ts +96 -0
  325. package/dist/setup/agent-configs.js +333 -0
  326. package/dist/setup/agent-io.d.ts +9 -0
  327. package/dist/setup/agent-io.js +16 -0
  328. package/dist/setup/agent-writer.d.ts +51 -0
  329. package/dist/setup/agent-writer.js +115 -0
  330. package/dist/setup/approval-migration.d.ts +47 -0
  331. package/dist/setup/approval-migration.js +68 -0
  332. package/dist/setup/auto-approve.d.ts +85 -0
  333. package/dist/setup/auto-approve.js +150 -0
  334. package/dist/setup/bridge-port.d.ts +15 -0
  335. package/dist/setup/bridge-port.js +24 -0
  336. package/dist/setup/desktop-shape.d.ts +57 -0
  337. package/dist/setup/desktop-shape.js +63 -0
  338. package/dist/setup/dev-server-wait.d.ts +60 -0
  339. package/dist/setup/dev-server-wait.js +65 -0
  340. package/dist/setup/drive-agent.d.ts +71 -0
  341. package/dist/setup/drive-agent.js +171 -0
  342. package/dist/setup/drive-plan.d.ts +68 -0
  343. package/dist/setup/drive-plan.js +130 -0
  344. package/dist/setup/ensure-daemon.d.ts +29 -0
  345. package/dist/setup/ensure-daemon.js +58 -0
  346. package/dist/setup/init-runtime.d.ts +47 -0
  347. package/dist/setup/init-runtime.js +160 -0
  348. package/dist/setup/interrupt.d.ts +25 -0
  349. package/dist/setup/interrupt.js +40 -0
  350. package/dist/setup/license-key.d.ts +39 -0
  351. package/dist/setup/license-key.js +72 -0
  352. package/dist/setup/listeners.d.ts +37 -0
  353. package/dist/setup/listeners.js +85 -0
  354. package/dist/setup/node-effects.d.ts +60 -0
  355. package/dist/setup/node-effects.js +210 -0
  356. package/dist/setup/page-probe.d.ts +39 -0
  357. package/dist/setup/page-probe.js +49 -0
  358. package/dist/setup/relaunch.d.ts +36 -0
  359. package/dist/setup/relaunch.js +57 -0
  360. package/dist/setup/remaining-steps.d.ts +19 -0
  361. package/dist/setup/remaining-steps.js +31 -0
  362. package/dist/setup/run-setup.d.ts +99 -0
  363. package/dist/setup/run-setup.js +187 -0
  364. package/dist/setup/session-pick.d.ts +47 -0
  365. package/dist/setup/session-pick.js +51 -0
  366. package/dist/setup/setup-command.d.ts +45 -0
  367. package/dist/setup/setup-command.js +199 -0
  368. package/dist/setup/setup-options.d.ts +74 -0
  369. package/dist/setup/setup-options.js +67 -0
  370. package/dist/setup/transcripts.d.ts +16 -0
  371. package/dist/setup/transcripts.js +43 -0
  372. package/dist/status-payload.d.ts +14 -1
  373. package/dist/status-payload.js +23 -1
  374. package/dist/telemetry/automation-hint.d.ts +2 -1
  375. package/dist/telemetry/daemon-telemetry.d.ts +8 -1
  376. package/dist/telemetry/daemon-telemetry.js +52 -5
  377. package/dist/telemetry/error-class.js +1 -1
  378. package/dist/telemetry/feedback-context.d.ts +9 -1
  379. package/dist/telemetry/feedback-context.js +60 -29
  380. package/dist/telemetry/feedback-local.d.ts +15 -0
  381. package/dist/telemetry/feedback-local.js +56 -0
  382. package/dist/telemetry/feedback-outbox.d.ts +2 -1
  383. package/dist/telemetry/feedback.d.ts +11 -0
  384. package/dist/telemetry/feedback.js +19 -6
  385. package/dist/telemetry/init-telemetry.d.ts +2 -0
  386. package/dist/telemetry/init-telemetry.js +2 -0
  387. package/dist/telemetry/install-source.d.ts +14 -0
  388. package/dist/telemetry/install-source.js +30 -0
  389. package/dist/telemetry/license-activation.d.ts +7 -1
  390. package/dist/telemetry/license-activation.js +9 -5
  391. package/dist/telemetry/mcp-connection.js +7 -0
  392. package/dist/telemetry/project-profile.d.ts +12 -9
  393. package/dist/telemetry/project-profile.js +12 -7
  394. package/dist/telemetry/proxy-telemetry.d.ts +3 -0
  395. package/dist/telemetry/proxy-telemetry.js +21 -0
  396. package/dist/telemetry/run-telemetry.d.ts +0 -2
  397. package/dist/telemetry/run-telemetry.js +1 -1
  398. package/dist/telemetry/session-metrics.d.ts +12 -0
  399. package/dist/telemetry/session-metrics.js +35 -1
  400. package/dist/telemetry/telemetry.js +17 -2
  401. package/dist/telemetry/tool-refused.d.ts +3 -1
  402. package/dist/telemetry/tool-refused.js +34 -2
  403. package/dist/telemetry/verification-of.js +2 -2
  404. package/dist/tools/act-capsule.d.ts +10 -0
  405. package/dist/tools/act-capsule.js +8 -2
  406. package/dist/tools/act-danger.d.ts +2 -1
  407. package/dist/tools/act-danger.js +11 -3
  408. package/dist/tools/act-observation.d.ts +41 -0
  409. package/dist/tools/act-observation.js +36 -0
  410. package/dist/tools/act-preflight.d.ts +20 -0
  411. package/dist/tools/act-preflight.js +98 -0
  412. package/dist/tools/act-sequence-retry.d.ts +45 -0
  413. package/dist/tools/act-sequence-retry.js +58 -0
  414. package/dist/tools/act-sequence-tool.d.ts +13 -0
  415. package/dist/tools/act-sequence-tool.js +135 -0
  416. package/dist/tools/act-target.d.ts +14 -0
  417. package/dist/tools/act-target.js +47 -0
  418. package/dist/tools/act-tools.d.ts +21 -1
  419. package/dist/tools/act-tools.js +196 -204
  420. package/dist/tools/assert-source.d.ts +22 -0
  421. package/dist/tools/assert-source.js +53 -0
  422. package/dist/tools/assert-verdict.d.ts +20 -3
  423. package/dist/tools/assert-verdict.js +58 -20
  424. package/dist/tools/browser-tools.js +6 -22
  425. package/dist/tools/complete-snapshot.d.ts +48 -0
  426. package/dist/tools/complete-snapshot.js +75 -0
  427. package/dist/tools/coverage-tools.d.ts +10 -1
  428. package/dist/tools/coverage-tools.js +123 -69
  429. package/dist/tools/dynamic-tools.js +53 -13
  430. package/dist/tools/error-recovery.d.ts +25 -14
  431. package/dist/tools/error-recovery.js +78 -9
  432. package/dist/tools/feedback-tools.d.ts +1 -1
  433. package/dist/tools/feedback-tools.js +2 -2
  434. package/dist/tools/invoke-tool.js +121 -11
  435. package/dist/tools/lease-hint.d.ts +10 -0
  436. package/dist/tools/lease-hint.js +53 -4
  437. package/dist/tools/lease-tools.d.ts +35 -5
  438. package/dist/tools/lease-tools.js +191 -13
  439. package/dist/tools/merged-name-redirect.d.ts +13 -0
  440. package/dist/tools/merged-name-redirect.js +22 -0
  441. package/dist/tools/navigate-arrival.d.ts +0 -2
  442. package/dist/tools/navigate-arrival.js +1 -1
  443. package/dist/tools/numeric-bounds.d.ts +100 -0
  444. package/dist/tools/numeric-bounds.js +125 -0
  445. package/dist/tools/observe-tools.js +109 -65
  446. package/dist/tools/read-tools.js +31 -8
  447. package/dist/tools/real-input-attempt.d.ts +32 -0
  448. package/dist/tools/real-input-attempt.js +212 -2
  449. package/dist/tools/reconcile-tools.js +22 -8
  450. package/dist/tools/resolve-target.d.ts +0 -7
  451. package/dist/tools/sdk-marker-probe.d.ts +29 -0
  452. package/dist/tools/sdk-marker-probe.js +57 -0
  453. package/dist/tools/snapshot-delta.d.ts +1 -1
  454. package/dist/tools/tool-kit.d.ts +24 -0
  455. package/dist/tools/tool-kit.js +21 -0
  456. package/dist/tools/tool-names.d.ts +5 -0
  457. package/dist/tools/tool-names.js +5 -0
  458. package/dist/tools/tool-surface.d.ts +85 -6
  459. package/dist/tools/tool-surface.js +122 -2
  460. package/dist/tools/tools-helpers.d.ts +19 -0
  461. package/dist/tools/tools-helpers.js +46 -0
  462. package/dist/tools/tools.d.ts +2 -0
  463. package/dist/tools/tools.js +78 -12
  464. package/dist/tools/unadvertised-help.js +4 -4
  465. package/dist/tools/verify-next-baton.d.ts +53 -0
  466. package/dist/tools/verify-next-baton.js +52 -0
  467. package/dist/update/reticle-deps.d.ts +9 -0
  468. package/dist/update/reticle-deps.js +27 -0
  469. package/dist/update/sdk-sync.d.ts +1 -2
  470. package/dist/update/sdk-sync.js +1 -21
  471. package/dist/update/update-nudge.d.ts +25 -10
  472. package/dist/update/update-nudge.js +32 -3
  473. package/dist/update/updater.d.ts +1 -1
  474. package/dist/version/peer-announce.js +4 -2
  475. package/dist/version/sdk-fix.d.ts +47 -0
  476. package/dist/version/sdk-fix.js +127 -0
  477. package/dist/version/version-nudge.d.ts +14 -0
  478. package/dist/version/version-nudge.js +21 -0
  479. package/dist/version/version-skew.d.ts +38 -3
  480. package/dist/version/version-skew.js +83 -7
  481. package/dist/visual/visual-store.d.ts +6 -6
  482. package/dist/visual/visual-store.js +18 -16
  483. package/dist/visual/visual-tools.js +57 -12
  484. package/docs/README.md +2 -1
  485. package/docs/cli/cloud.mdx +1 -1
  486. package/docs/cli/doctor.mdx +2 -0
  487. package/docs/cli/serve.mdx +4 -2
  488. package/docs/cli/verify.mdx +4 -5
  489. package/docs/cli.mdx +7 -3
  490. package/docs/desktop.mdx +1 -1
  491. package/docs/docs.json +2 -2
  492. package/docs/gates.md +1 -1
  493. package/docs/getting-started.md +19 -3
  494. package/docs/index.mdx +9 -6
  495. package/docs/install-agentic.mdx +38 -12
  496. package/docs/install-manual.mdx +1 -1
  497. package/docs/packages/browser.mdx +2 -2
  498. package/docs/packages/server.mdx +1 -1
  499. package/docs/packages.mdx +8 -6
  500. package/docs/platform-integration.md +17 -0
  501. package/docs/predicates.mdx +8 -0
  502. package/docs/reticle-manual.md +106 -0
  503. package/docs/skill-file.mdx +3 -3
  504. package/docs/telemetry-contract.md +108 -4
  505. package/docs/tools-act-sequence.mdx +16 -0
  506. package/docs/tools-tools-and-run.mdx +2 -4
  507. package/docs/troubleshooting.mdx +9 -0
  508. package/docs/usage.md +4 -3
  509. package/package.json +4 -3
  510. package/dist/init/cursor.d.ts +0 -24
  511. package/dist/init/cursor.js +0 -80
  512. package/dist/session/session-readiness.d.ts +0 -34
  513. package/dist/session/session-readiness.js +0 -36
@@ -1,4 +1,5 @@
1
1
  import { span } from '../trace.js';
2
+ import { routePathOf } from '../events/predicate-route.js';
2
3
  import { AnchorKind, DriftReason, EventType, ReticleCommand, QueryBy, PredicateKind, } from '@reticlehq/core';
3
4
  import { asRecord, asString } from '../tools/tools-helpers.js';
4
5
  import { replayActionArgs, ambiguousTestidNote, queryRefs } from './replay.js';
@@ -198,8 +199,14 @@ function currentRoute(session) {
198
199
  if (last === undefined)
199
200
  return undefined;
200
201
  const data = last.data ?? {};
202
+ // The ROUTER's path. This field answers "which page did this step run on", and the document
203
+ // pathname is `/` on every page of a hash-routed app — so a whole desktop replay reported `/` for
204
+ // every step. Sixth place the same reading was wrong; see routePathOf.
201
205
  const pathname = asString(data['pathname']) ?? asString(data['to']);
202
- return pathname !== undefined && pathname.length > 0 ? pathname : undefined;
206
+ if (pathname === undefined || 0 === pathname.length)
207
+ return undefined;
208
+ const routed = routePathOf(pathname, asString(data['hash']) ?? '');
209
+ return routed.length > 0 ? routed : undefined;
203
210
  }
204
211
  /** Pathname only (drop origin + query) so a net URL stays terse in the journey. */
205
212
  function trimUrl(url) {
@@ -294,7 +301,9 @@ async function runTestidStep(session, step, index, value, dynamic, confirmDanger
294
301
  act = await session.command(ReticleCommand.ACT, {
295
302
  ref,
296
303
  action: step.action ?? '',
297
- args: replayActionArgs(step.args, confirmDangerous),
304
+ // `value` is the anchor's own name — the field this step types into — so a redacted fill can
305
+ // be supplied from RETICLE_SECRET_<FIELD> without the flow carrying the secret.
306
+ args: replayActionArgs(step.args, confirmDangerous, value),
298
307
  });
299
308
  }
300
309
  finally {
@@ -30,6 +30,14 @@ export declare function runComponentStep(session: FlowReplaySession, step: FlowS
30
30
  */
31
31
  export declare function isDegradedAnchor(anchor: FlowAnchor): boolean;
32
32
  export declare function degradedStepResult(step: FlowStep, index: number, label: string): FlowStepResult;
33
+ /**
34
+ * QUERY args for an element anchor — null when the anchor addresses no element.
35
+ *
36
+ * Exported for `arriveAtStartPath`, which has to ask "can step 1 resolve where we already are?"
37
+ * before deciding to navigate. Sharing this mapping rather than repeating it keeps that question and
38
+ * the step runner's own resolution asking the same thing of the same anchor.
39
+ */
40
+ export declare function anchorQueryArgs(anchor: FlowAnchor): Record<string, unknown> | null;
33
41
  /**
34
42
  * Run an act_sequence step: resolve every sub-step's OWN anchor, then dispatch the whole thing as one
35
43
  * ACT_SEQUENCE — the same shape `replayProgram` already uses, so a recorded sequence and a saved one
@@ -181,8 +181,14 @@ export function degradedStepResult(step, index, label) {
181
181
  },
182
182
  };
183
183
  }
184
- /** QUERY args for an element anchor — null when the anchor addresses no element. */
185
- function anchorQueryArgs(anchor) {
184
+ /**
185
+ * QUERY args for an element anchor — null when the anchor addresses no element.
186
+ *
187
+ * Exported for `arriveAtStartPath`, which has to ask "can step 1 resolve where we already are?"
188
+ * before deciding to navigate. Sharing this mapping rather than repeating it keeps that question and
189
+ * the step runner's own resolution asking the same thing of the same anchor.
190
+ */
191
+ export function anchorQueryArgs(anchor) {
186
192
  if (anchor.kind === AnchorKind.TESTID)
187
193
  return { by: QueryBy.TESTID, value: anchor.value };
188
194
  if (anchor.kind === AnchorKind.COMPONENT)
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The flow store a SESSION's flows belong in.
3
+ *
4
+ * `deps.flows` is bound to the daemon's own root at construction, which is right only when the
5
+ * daemon happens to have been started in the project it is driving. A user-scoped MCP registration
6
+ * is the common case and the editor starts it wherever it likes, so "where the daemon was launched"
7
+ * and "which app is being verified" are usually different directories.
8
+ *
9
+ * This used to live inside flow-tools and was applied at exactly ONE of ten call sites. The result
10
+ * is the half-applied state `sessionRoot` warns about in its own comment, reached in practice:
11
+ *
12
+ * - the HUD listed the daemon repo's flows while driving somebody else's app — Electron and Tauri
13
+ * flows shown over a React dashboard, none of which existed in the checkout being verified
14
+ * - `flow_replay` answered `flow_not_found` for a flow sitting on disk, because it looked in the
15
+ * daemon's root while `reticle verify` (which roots itself at cwd) replayed the same flow fine
16
+ * - and the two save paths disagreed with each other, so where a flow landed depended on which
17
+ * tool wrote it
18
+ *
19
+ * Reported as "running the daemon from here but taking the directory from there", which is exactly
20
+ * what it was.
21
+ *
22
+ * Rebinding is cheap — a FlowStore is a filesystem port, a root and a clock — and the common case
23
+ * allocates nothing: when no resolver is wired, or it names the root already in use, `deps.flows` is
24
+ * returned unchanged.
25
+ */
26
+ import { FlowStore } from './flows.js';
27
+ import type { ToolDeps } from '../tools/tool-kit.js';
28
+ export declare function flowsForSession(deps: ToolDeps, projectId: string | undefined): {
29
+ flows: FlowStore;
30
+ root: string;
31
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The flow store a SESSION's flows belong in.
3
+ *
4
+ * `deps.flows` is bound to the daemon's own root at construction, which is right only when the
5
+ * daemon happens to have been started in the project it is driving. A user-scoped MCP registration
6
+ * is the common case and the editor starts it wherever it likes, so "where the daemon was launched"
7
+ * and "which app is being verified" are usually different directories.
8
+ *
9
+ * This used to live inside flow-tools and was applied at exactly ONE of ten call sites. The result
10
+ * is the half-applied state `sessionRoot` warns about in its own comment, reached in practice:
11
+ *
12
+ * - the HUD listed the daemon repo's flows while driving somebody else's app — Electron and Tauri
13
+ * flows shown over a React dashboard, none of which existed in the checkout being verified
14
+ * - `flow_replay` answered `flow_not_found` for a flow sitting on disk, because it looked in the
15
+ * daemon's root while `reticle verify` (which roots itself at cwd) replayed the same flow fine
16
+ * - and the two save paths disagreed with each other, so where a flow landed depended on which
17
+ * tool wrote it
18
+ *
19
+ * Reported as "running the daemon from here but taking the directory from there", which is exactly
20
+ * what it was.
21
+ *
22
+ * Rebinding is cheap — a FlowStore is a filesystem port, a root and a clock — and the common case
23
+ * allocates nothing: when no resolver is wired, or it names the root already in use, `deps.flows` is
24
+ * returned unchanged.
25
+ */
26
+ import { FlowStore } from './flows.js';
27
+ export function flowsForSession(deps, projectId) {
28
+ const resolved = deps.artifactRootFor?.(projectId);
29
+ if (resolved === undefined || resolved.root === deps.reticleRoot) {
30
+ return { flows: deps.flows, root: deps.reticleRoot };
31
+ }
32
+ return { flows: new FlowStore(deps.fs, resolved.root, { now: deps.now }), root: resolved.root };
33
+ }
@@ -38,9 +38,21 @@ export function successLabel(success) {
38
38
  export function successToPredicate(success, dynamic) {
39
39
  const parts = [];
40
40
  if (success.signal !== undefined) {
41
- parts.push(success.signalData !== undefined
42
- ? { kind: PredicateKind.SIGNAL, name: success.signal, dataMatches: success.signalData }
43
- : { kind: PredicateKind.SIGNAL, name: success.signal });
41
+ const signal = {
42
+ kind: PredicateKind.SIGNAL,
43
+ name: success.signal,
44
+ };
45
+ if (success.signalData !== undefined)
46
+ signal.dataMatches = success.signalData;
47
+ if (success.signalCount !== undefined) {
48
+ signal.count = success.signalCount;
49
+ // Same post-settle reasoning as net.count: the success waiter is wait-until-true, so an exact
50
+ // count is transiently satisfied the instant the FIRST matching signal fires — before a
51
+ // double-fire's duplicate arrives. Gating on `settled` forces the count to be read only after
52
+ // the app goes quiet, by which point the duplicate IS counted and the over-count fails.
53
+ parts.push({ kind: PredicateKind.SETTLED });
54
+ }
55
+ parts.push(signal);
44
56
  }
45
57
  if (success.net !== undefined) {
46
58
  const net = { kind: PredicateKind.NET };
@@ -5,8 +5,9 @@ import { FlowErrorCode, RecordedSaveError, ReplayStatus, } from '@reticlehq/core
5
5
  import { recordSuiteFlakes } from './suite-flakes.js';
6
6
  import { ReticleTool } from '../tools/tool-names.js';
7
7
  import { asNumber, asString } from '../tools/tools-helpers.js';
8
+ import { workerCountSchema } from '../tools/numeric-bounds.js';
8
9
  import { log } from '../log.js';
9
- import { syncFlowToCloud, SyncOutcome } from '../cloud/cloud-sync.js';
10
+ import { cloudFetch, syncFlowToCloud, SyncOutcome } from '../cloud/cloud-sync.js';
10
11
  import { mapWithConcurrency, resolveConcurrency } from './parallel-suite.js';
11
12
  import { acquireLeasedSession } from '../tools/lease-tools.js';
12
13
  import { homedir } from 'node:os';
@@ -14,14 +15,15 @@ import { resolveProjectCloud } from '../cloud/cloud-config.js';
14
15
  import { buildSuiteVerdict } from './decision.js';
15
16
  import { classifyFlowAssertions } from './flow-classify.js';
16
17
  import { isValidFlowName, flowPath } from '../project/reticle-dir.js';
17
- import { FlowStore } from './flows.js';
18
+ import {} from './flows.js';
19
+ import { flowsForSession } from './flow-store-for-session.js';
18
20
  import { replayNamedFlow, flowErrorMessage, latestRecordedFlow, sessionProjectId, } from './flow-replay-run.js';
19
21
  import { persistAndSyncVerificationRun } from '../runs/verification-sync.js';
20
22
  import { runServerVerify } from './server-verify.js';
21
23
  import { healFlow } from './heal-run.js';
22
24
  export { replayNamedFlow } from './flow-replay-run.js';
23
25
  /**
24
- * Best-effort mirror of a just-saved flow to Reticle Cloud (only when logged in — both cloud env vars
26
+ * Best-effort mirror of a just-saved flow to Reticle (only when logged in — both cloud env vars
25
27
  * set). Fire-and-forget: resolves the config, POSTs via the platform fetch, and logs the outcome. Any
26
28
  * failure is swallowed so a network hiccup never affects the local save.
27
29
  */
@@ -30,7 +32,7 @@ async function syncSavedFlowToCloud(deps, flow, projectId) {
30
32
  const cloud = await resolveProjectCloud(deps.fs, deps.reticleRoot, homedir(), process.env);
31
33
  if (null === cloud.config || !cloud.policy.flows)
32
34
  return; // not attached / flows disabled → local only
33
- const result = await syncFlowToCloud(flow, cloud.config, projectId, (url, init) => fetch(url, init));
35
+ const result = await syncFlowToCloud(flow, cloud.config, projectId, cloudFetch);
34
36
  if (result.outcome !== SyncOutcome.SYNCED) {
35
37
  log('cloud-flow-sync-failed', { flow: flow.name, status: result.status, error: result.error });
36
38
  }
@@ -69,23 +71,16 @@ export function leaseFailureReplay(name, error) {
69
71
  /** Stand-in path for a flow whose name fails the path-segment guard — never a real join. */
70
72
  const INVALID_FLOW_NAME_PATH = '(invalid flow name — not a usable path)';
71
73
  /**
72
- * The flow store a SESSION's artifacts belong in, and the root it resolved to.
74
+ * How a save reports that nobody said what the flow is for.
73
75
  *
74
- * `deps.flows` is bound to the daemon's own root at construction, which is right only when the
75
- * daemon happens to have been started in the project it is driving. When a resolver is wired and it
76
- * names a different project, the write has to go there instead — so the store is rebound for this
77
- * call. Rebinding is cheap: a FlowStore is a filesystem port, a root and a clock.
78
- *
79
- * Returns `deps.flows` unchanged when nothing is wired or the roots already agree, so the common
80
- * case allocates nothing and behaves exactly as before.
76
+ * Declared once and shared by every save tool: an undeclared field is stripped from
77
+ * `structuredContent` by a schema-strict MCP client, so a save path that forgot this line would
78
+ * report the nudge to the unit tests and to nobody else.
81
79
  */
82
- function flowsForSession(deps, projectId) {
83
- const resolved = deps.artifactRootFor?.(projectId);
84
- if (resolved === undefined || resolved.root === deps.reticleRoot) {
85
- return { flows: deps.flows, root: deps.reticleRoot };
86
- }
87
- return { flows: new FlowStore(deps.fs, resolved.root, { now: deps.now }), root: resolved.root };
88
- }
80
+ const INTENT_GAP_FIELD = z
81
+ .unknown()
82
+ .optional()
83
+ .describe('Present ONLY when the flow was saved with nothing saying what it is for: { kind, missing, cost, fix }. The flow is on disk either way — this never blocks a save. Close it by saving again with `intent`, or by setting the flow file’s `intentId` to an intent already in the ledger. Nothing here is ever derived from the flow name, the steps or the assertions: a guessed goal reads as the author’s own words.');
89
84
  export const FLOW_TOOLS = [
90
85
  {
91
86
  name: ReticleTool.FLOW_SAVE,
@@ -97,7 +92,15 @@ export const FLOW_TOOLS = [
97
92
  .describe('Alias for `flowName` (the name reticle_annotate uses).'),
98
93
  flowName: z
99
94
  .string()
100
- .describe('Name for the flow file (saved to .reticle/flows/<flowName>.json). Use again in reticle_flow{action:"load"} / reticle_flow_replay.'),
95
+ .describe('Which RECORDING to save — the name reticle_record{start} was called with. This is a lookup key, not the filename: pass `saveAs` to choose that.'),
96
+ saveAs: z
97
+ .string()
98
+ .optional()
99
+ .describe('Name for the flow file (.reticle/flows/<saveAs>.json), and the name reticle_flow{action:"load"} / reticle_flow_replay take. Omit to reuse the recording name.'),
100
+ intent: z
101
+ .string()
102
+ .optional()
103
+ .describe('What this flow is FOR, in prose: which user does what, and what should become true. Answer it here rather than in a second call. Without it the flow still saves, but the day it goes red the report can only name the step that broke, not the thing that stopped being true.'),
101
104
  sessionId: z
102
105
  .string()
103
106
  .optional()
@@ -124,6 +127,7 @@ export const FLOW_TOOLS = [
124
127
  warning: z.string().optional(),
125
128
  })
126
129
  .optional(),
130
+ intentGap: INTENT_GAP_FIELD,
127
131
  error: z.string().optional(),
128
132
  code: z.string().optional(),
129
133
  },
@@ -131,14 +135,44 @@ export const FLOW_TOOLS = [
131
135
  const name = asString(aliasParam(args, 'flowName', ['flow'])['flowName']) ?? '';
132
136
  const program = deps.recordings.getCompiled(name);
133
137
  if (program === undefined) {
138
+ /*
139
+ * Name what DOES exist.
140
+ *
141
+ * `flowName` here is the RECORDING's name, while every other flow tool reads it as the name
142
+ * to save AS — so recording `default` and saving as `sign-in` looks obviously right and
143
+ * answers "no compiled recording by that name". The old message then said "record one
144
+ * first", which is advice to repeat the step that just succeeded. Cost a real investigation
145
+ * before the names were compared.
146
+ */
147
+ const held = deps.recordings.compiled();
134
148
  return Promise.resolve({
135
- error: flowErrorMessage(FlowErrorCode.NO_RECORDING),
149
+ error: 0 === held.length
150
+ ? flowErrorMessage(FlowErrorCode.NO_RECORDING)
151
+ : `no recording named '${name}'. This is the name the RECORDING was made under, not ` +
152
+ `the name to save it as — stopped and ready to save: ${held.map((n) => `'${n}'`).join(', ')}.`,
136
153
  code: FlowErrorCode.NO_RECORDING,
137
154
  });
138
155
  }
156
+ // The name to save AS, which is not the name looked up above.
157
+ //
158
+ // `flowName` selects the recording; a recording is named at `record{start}`, often `default`
159
+ // or whatever the drive began as. Every other flow tool reads a flow name as the thing you
160
+ // load and replay, so a caller naming their flow at save time had no way to do it and had to
161
+ // `mv` the file on disk. The error message below already had to explain this ambiguity; that
162
+ // it needed explaining is the bug (#698).
163
+ const saveAs = asString(args['saveAs']);
164
+ if (saveAs !== undefined && !isValidFlowName(saveAs)) {
165
+ return Promise.resolve({
166
+ error: `'${saveAs}' is not a usable flow name — it becomes a filename under .reticle/flows/.`,
167
+ code: FlowErrorCode.INVALID_NAME,
168
+ });
169
+ }
139
170
  // fold any structured annotations (expect/dynamic/success/intent) onto the saved flow.
171
+ // Keyed by the RECORDING name: annotations were left against the recording, not the file.
140
172
  const success = deps.annotations.success(name);
141
- const intent = deps.annotations.intent(name);
173
+ // The inline argument wins over an annotation left from an earlier call: it is the more recent
174
+ // statement, and it is the one the author just typed.
175
+ const intent = asString(args['intent']) ?? deps.annotations.intent(name);
142
176
  const annotations = {
143
177
  stepExpect: deps.annotations.stepExpect(name),
144
178
  dynamic: deps.annotations.dynamic(name),
@@ -152,7 +186,8 @@ export const FLOW_TOOLS = [
152
186
  if (emptyRefusal !== undefined)
153
187
  return Promise.resolve(emptyRefusal);
154
188
  const { flows, root } = flowsForSession(deps, projectId);
155
- return flows.save(program, annotations, projectId).then(async (res) => {
189
+ const toSave = saveAs === undefined ? program : { ...program, name: saveAs };
190
+ return flows.save(toSave, annotations, projectId).then(async (res) => {
156
191
  if (!res.ok)
157
192
  return { error: flowErrorMessage(res.code), code: res.code };
158
193
  deps.annotations.clear(name);
@@ -193,7 +228,10 @@ export const FLOW_TOOLS = [
193
228
  // received string") — caught driving the live demo.
194
229
  handler: (deps, args) => {
195
230
  const projectId = sessionProjectId(deps, asString(args['sessionId']));
196
- return deps.flows.list(projectId).then((names) => ({
231
+ // The APP's flows, not the daemon's. Listing where the daemon was launched is what showed a
232
+ // React dashboard a HUD full of Electron and Tauri flows from an unrelated checkout.
233
+ const { flows: store, root } = flowsForSession(deps, projectId);
234
+ return store.list(projectId).then((names) => ({
197
235
  // `list` deliberately returns invalid names so they are reported rather than silently
198
236
  // dropped — but the declared outputSchema requires `path` on EVERY entry, and omitting it made
199
237
  // a strict MCP client reject the whole listing (the agent then sees no flows at all, which is
@@ -201,7 +239,7 @@ export const FLOW_TOOLS = [
201
239
  // gets an explanatory marker instead of a joined filesystem path, which is what must never
202
240
  // happen for a traversal-shaped name.
203
241
  flows: names.map((name) => isValidFlowName(name)
204
- ? { name, path: flowPath(deps.reticleRoot, name, projectId) }
242
+ ? { name, path: flowPath(root, name, projectId) }
205
243
  : { name, path: INVALID_FLOW_NAME_PATH }),
206
244
  }));
207
245
  },
@@ -350,8 +388,7 @@ export const FLOW_TOOLS = [
350
388
  .array(z.string())
351
389
  .optional()
352
390
  .describe('Flow names to verify. Omit to verify every saved flow.'),
353
- parallel: z
354
- .number()
391
+ parallel: workerCountSchema
355
392
  .optional()
356
393
  .describe('Run this many flows at once, each in its own isolated leased browser context (needs the browser pool). Clamped to the pool capacity and the flow count. Omit for the sequential single-tab run.'),
357
394
  sessionId: z
@@ -380,7 +417,7 @@ export const FLOW_TOOLS = [
380
417
  const projectId = sessionProjectId(deps, sessionId);
381
418
  const requested = Array.isArray(args['names'])
382
419
  ? args['names'].filter((n) => 'string' === typeof n)
383
- : await deps.flows.list(projectId);
420
+ : await flowsForSession(deps, projectId).flows.list(projectId);
384
421
  // verify:server — hand the whole suite to the hosted runner; it records the verification itself.
385
422
  const cloud = await resolveProjectCloud(deps.fs, deps.reticleRoot, homedir(), process.env);
386
423
  const server = await runServerVerify(deps, cloud, sessionId, requested);
@@ -417,7 +454,9 @@ export const FLOW_TOOLS = [
417
454
  const parallelRuns = await Promise.all(outcomes.map(async (o, i) => {
418
455
  const name = requested[i] ?? '';
419
456
  const replay = o.ok && o.value !== undefined ? o.value.replay : leaseFailureReplay(name, o.error);
420
- const loaded = await deps.flows.load(name, projectId).catch(() => null);
457
+ const loaded = await flowsForSession(deps, projectId)
458
+ .flows.load(name, projectId)
459
+ .catch(() => null);
421
460
  const flow = loaded !== null && loaded.ok ? loaded.value : undefined;
422
461
  return flow === undefined ? { replay } : { replay, flow };
423
462
  }));
@@ -441,7 +480,9 @@ export const FLOW_TOOLS = [
441
480
  for (const flowName of requested) {
442
481
  const start = deps.now();
443
482
  const replay = await replayNamedFlow(deps, { flowName, sessionId });
444
- const loaded = await deps.flows.load(flowName, projectId).catch(() => null);
483
+ const loaded = await flowsForSession(deps, projectId)
484
+ .flows.load(flowName, projectId)
485
+ .catch(() => null);
445
486
  const flow = loaded !== null && loaded.ok ? loaded.value : undefined;
446
487
  runs.push(flow === undefined ? { replay } : { replay, flow });
447
488
  timed.push({ replay, durationMs: deps.now() - start });
@@ -477,6 +518,10 @@ export const FLOW_TOOLS = [
477
518
  .string()
478
519
  .optional()
479
520
  .describe('Override the flow name embedded in the recorded flow. Omit to use the recorder-assigned name.'),
521
+ intent: z
522
+ .string()
523
+ .optional()
524
+ .describe('What this flow is FOR, in prose: which user does what, and what should become true. The recorder captures clicks, not goals, so this is the only place the goal can come from. Without it the flow still saves, but the day it goes red the report can only name the step that broke.'),
480
525
  ...{
481
526
  sessionId: z
482
527
  .string()
@@ -491,6 +536,7 @@ export const FLOW_TOOLS = [
491
536
  stepCount: z.number().optional(),
492
537
  degraded: z.number().optional(),
493
538
  empty: z.boolean().optional(),
539
+ intentGap: INTENT_GAP_FIELD,
494
540
  error: z.string().optional(),
495
541
  code: z.string().optional(),
496
542
  },
@@ -504,16 +550,24 @@ export const FLOW_TOOLS = [
504
550
  };
505
551
  }
506
552
  const override = asString(aliasParam(args, 'flowName', ['flow'])['flowName']);
507
- const flow = override !== undefined ? { ...recorded.flow, name: override } : recorded.flow;
553
+ const intent = asString(args['intent']);
554
+ const flow = {
555
+ ...recorded.flow,
556
+ ...(override === undefined ? {} : { name: override }),
557
+ ...(intent === undefined ? {} : { intent }),
558
+ };
508
559
  // The store stamps the project into the file AND routes it to the per-project subdir (a shared
509
560
  // daemon serves many apps), so location and content agree from one source of truth.
510
561
  const emptyRecorded = emptyFlowRefusal(flow.steps.length, flow.name);
511
562
  if (emptyRecorded !== undefined)
512
563
  return emptyRecorded;
513
- const res = await deps.flows.saveFlow(flow, session.projectId);
564
+ // Resolved like every other path now. This save used to go to the daemon's root while the
565
+ // recorded-flow save resolved per session, so where a flow landed depended on which tool wrote
566
+ // it — and the pair that disagreed were the two ways to save the same thing.
567
+ const res = await flowsForSession(deps, session.projectId).flows.saveFlow(flow, session.projectId);
514
568
  if (!res.ok)
515
569
  return { error: flowErrorMessage(res.code), code: res.code };
516
- // If logged into Reticle Cloud, mirror the saved flow to the team's regression suite. Best-effort
570
+ // If logged in to Reticle, mirror the saved flow to the team's regression suite. Best-effort
517
571
  // and non-blocking: the flow is already on disk, so a sync failure never fails the save.
518
572
  void syncSavedFlowToCloud(deps, flow, session.projectId);
519
573
  // Return the SaveSummary as-is ({ name, stepCount, degraded, empty }) — the outputSchema
@@ -1,5 +1,5 @@
1
1
  import { FlowErrorCode } from '@reticlehq/core';
2
- import type { FlowAnchor, FlowExpect, FlowFile, FlowStep, HealChange } from '@reticlehq/core';
2
+ import type { FlowAnchor, FlowExpect, FlowFile, FlowStep, HealChange, InstrumentationGap } from '@reticlehq/core';
3
3
  import type { CompiledProgram, RecordedStep } from './recordings.js';
4
4
  import type { FileSystemPort } from '../project/fs-port.js';
5
5
  /** A monotonic clock injected for createdAt — never call Date.now inside the store (rule 7). */
@@ -19,6 +19,14 @@ export declare function anchorForStep(args: Record<string, unknown>): {
19
19
  anchor: FlowAnchor;
20
20
  degraded: boolean;
21
21
  };
22
+ /**
23
+ * What a redacted fill value is replaced WITH.
24
+ *
25
+ * Replaced, never dropped. Replay still needs a step there, and a flow that silently loses its
26
+ * password step drifts at sign-in forever with no explanation of why. The placeholder also tells a
27
+ * reader what to do: the value belongs in the environment, not in a file they are about to commit.
28
+ */
29
+ export declare const REDACTED_FILL = "<redacted: supply at replay>";
22
30
  /**
23
31
  * Pure: map one normalized RecordedStep → FlowStep with a semantic anchor (+ degraded marker).
24
32
  * A ref-only (stable:false) step is recorded with a best-effort anchor and degraded:true —
@@ -30,6 +38,11 @@ interface SaveSummary {
30
38
  stepCount: number;
31
39
  degraded: number;
32
40
  empty: boolean;
41
+ /**
42
+ * Present only when the flow was saved with nothing saying what it is for. Never blocks the save,
43
+ * and absent the moment the flow carries prose or an `intentId`. See `flowIntentGap`.
44
+ */
45
+ intentGap?: InstrumentationGap;
33
46
  }
34
47
  /**
35
48
  * The structured annotations folded onto a flow at save time: per-step