@reticlehq/server 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (768) hide show
  1. package/README.md +1 -1
  2. package/dist/bridge-security.d.ts +0 -1
  3. package/dist/bridge-security.js +0 -1
  4. package/dist/bridge.d.ts +0 -1
  5. package/dist/bridge.js +60 -10
  6. package/dist/bridge.test-harness.d.ts +0 -1
  7. package/dist/bridge.test-harness.js +0 -1
  8. package/dist/capsule/capsule-store.d.ts +2 -3
  9. package/dist/capsule/capsule-store.js +0 -1
  10. package/dist/capsule/capsule.d.ts +0 -1
  11. package/dist/capsule/capsule.js +0 -1
  12. package/dist/capsule/causal-summary.d.ts +21 -1
  13. package/dist/capsule/causal-summary.js +20 -2
  14. package/dist/capsule/divergence.d.ts +0 -1
  15. package/dist/capsule/divergence.js +0 -1
  16. package/dist/capsule/minimize.d.ts +0 -1
  17. package/dist/capsule/minimize.js +0 -1
  18. package/dist/capsule/predicate-to-links.d.ts +0 -1
  19. package/dist/capsule/predicate-to-links.js +0 -1
  20. package/dist/cli-doctor.d.ts +6 -0
  21. package/dist/cli-doctor.js +60 -0
  22. package/dist/cli-flow-commands.d.ts +0 -1
  23. package/dist/cli-flow-commands.js +0 -1
  24. package/dist/cli-launch.d.ts +0 -1
  25. package/dist/cli-launch.js +7 -3
  26. package/dist/cli-parse.d.ts +52 -2
  27. package/dist/cli-parse.js +147 -3
  28. package/dist/cli-port.d.ts +0 -1
  29. package/dist/cli-port.js +0 -1
  30. package/dist/cli-verify.d.ts +2 -1
  31. package/dist/cli-verify.js +24 -3
  32. package/dist/cli.d.ts +2 -4
  33. package/dist/cli.js +109 -10
  34. package/dist/cloud/cloud-config.d.ts +36 -0
  35. package/dist/cloud/cloud-config.js +86 -0
  36. package/dist/cloud/cloud-sync.d.ts +96 -4
  37. package/dist/cloud/cloud-sync.js +131 -3
  38. package/dist/cloud-cli.d.ts +3 -0
  39. package/dist/cloud-cli.js +514 -0
  40. package/dist/crawl/crawl-tools.d.ts +0 -1
  41. package/dist/crawl/crawl-tools.js +1 -2
  42. package/dist/crawl/crawl.d.ts +17 -3
  43. package/dist/crawl/crawl.js +43 -4
  44. package/dist/daemon-resilience.d.ts +6 -1
  45. package/dist/daemon-resilience.js +63 -1
  46. package/dist/daemon.d.ts +23 -3
  47. package/dist/daemon.js +78 -21
  48. package/dist/domain/domain-model.d.ts +0 -1
  49. package/dist/domain/domain-model.js +1 -2
  50. package/dist/domain/domain-tools.d.ts +0 -7
  51. package/dist/domain/domain-tools.js +21 -4
  52. package/dist/domain/flow-risk.d.ts +0 -1
  53. package/dist/domain/flow-risk.js +0 -1
  54. package/dist/ee/audit-log.d.ts +0 -1
  55. package/dist/ee/audit-log.js +0 -1
  56. package/dist/events/body-failures.d.ts +4 -0
  57. package/dist/events/body-failures.js +113 -0
  58. package/dist/events/contradictions.d.ts +53 -0
  59. package/dist/events/contradictions.js +282 -0
  60. package/dist/events/echo-mismatch.d.ts +4 -0
  61. package/dist/events/echo-mismatch.js +138 -0
  62. package/dist/events/event-filters.d.ts +17 -3
  63. package/dist/events/event-filters.js +13 -3
  64. package/dist/events/json-salvage.d.ts +32 -0
  65. package/dist/events/json-salvage.js +96 -0
  66. package/dist/events/predicate-eval.d.ts +2 -1
  67. package/dist/events/predicate-eval.js +56 -9
  68. package/dist/events/predicate.d.ts +0 -1
  69. package/dist/events/predicate.js +56 -2
  70. package/dist/events/reaction.d.ts +0 -1
  71. package/dist/events/reaction.js +0 -1
  72. package/dist/events/reconcile.d.ts +39 -0
  73. package/dist/events/reconcile.js +211 -0
  74. package/dist/events/ring-buffer.d.ts +0 -1
  75. package/dist/events/ring-buffer.js +0 -1
  76. package/dist/events/stale-response.d.ts +4 -0
  77. package/dist/events/stale-response.js +139 -0
  78. package/dist/events/unit-mismatch.d.ts +16 -0
  79. package/dist/events/unit-mismatch.js +167 -0
  80. package/dist/flows/affected-tools.d.ts +18 -0
  81. package/dist/flows/affected-tools.js +52 -0
  82. package/dist/flows/affected.d.ts +0 -1
  83. package/dist/flows/affected.js +0 -1
  84. package/dist/flows/annotate-tools.d.ts +0 -1
  85. package/dist/flows/annotate-tools.js +21 -3
  86. package/dist/flows/annotate.d.ts +0 -1
  87. package/dist/flows/annotate.js +0 -1
  88. package/dist/flows/annotation-store.d.ts +0 -1
  89. package/dist/flows/annotation-store.js +0 -1
  90. package/dist/flows/assertion-integrity.d.ts +0 -1
  91. package/dist/flows/assertion-integrity.js +0 -1
  92. package/dist/flows/assertion-tiers-store.d.ts +0 -1
  93. package/dist/flows/assertion-tiers-store.js +0 -1
  94. package/dist/flows/buddy-status.d.ts +0 -1
  95. package/dist/flows/buddy-status.js +0 -1
  96. package/dist/flows/coverage.d.ts +0 -1
  97. package/dist/flows/coverage.js +0 -1
  98. package/dist/flows/decision.d.ts +0 -1
  99. package/dist/flows/decision.js +0 -1
  100. package/dist/flows/flake-store.d.ts +0 -1
  101. package/dist/flows/flake-store.js +0 -1
  102. package/dist/flows/flake.d.ts +0 -1
  103. package/dist/flows/flake.js +0 -1
  104. package/dist/flows/flow-classify.d.ts +0 -1
  105. package/dist/flows/flow-classify.js +0 -1
  106. package/dist/flows/flow-replay-run.d.ts +0 -1
  107. package/dist/flows/flow-replay-run.js +24 -8
  108. package/dist/flows/flow-replay.d.ts +20 -4
  109. package/dist/flows/flow-replay.js +9 -43
  110. package/dist/flows/flow-report.d.ts +0 -1
  111. package/dist/flows/flow-report.js +0 -1
  112. package/dist/flows/flow-scope.d.ts +0 -1
  113. package/dist/flows/flow-scope.js +0 -1
  114. package/dist/flows/flow-sources.d.ts +0 -1
  115. package/dist/flows/flow-sources.js +0 -1
  116. package/dist/flows/flow-step-runners.d.ts +23 -0
  117. package/dist/flows/flow-step-runners.js +102 -0
  118. package/dist/flows/flow-success.d.ts +0 -1
  119. package/dist/flows/flow-success.js +0 -1
  120. package/dist/flows/flow-tools.d.ts +0 -1
  121. package/dist/flows/flow-tools.js +54 -16
  122. package/dist/flows/flows.d.ts +6 -2
  123. package/dist/flows/flows.js +15 -2
  124. package/dist/flows/gate.d.ts +0 -1
  125. package/dist/flows/gate.js +0 -1
  126. package/dist/flows/git-changed.d.ts +0 -1
  127. package/dist/flows/git-changed.js +0 -1
  128. package/dist/flows/heal-run.d.ts +0 -1
  129. package/dist/flows/heal-run.js +0 -1
  130. package/dist/flows/heal.d.ts +0 -1
  131. package/dist/flows/heal.js +0 -1
  132. package/dist/flows/parallel-suite.d.ts +0 -1
  133. package/dist/flows/parallel-suite.js +0 -1
  134. package/dist/flows/recordings.d.ts +0 -1
  135. package/dist/flows/recordings.js +0 -1
  136. package/dist/flows/replay.d.ts +0 -1
  137. package/dist/flows/replay.js +71 -4
  138. package/dist/flows/server-verify.d.ts +15 -0
  139. package/dist/flows/server-verify.js +42 -0
  140. package/dist/flows/verify-change-tools.d.ts +2 -0
  141. package/dist/flows/verify-change-tools.js +187 -0
  142. package/dist/flows/watch-batcher.d.ts +0 -1
  143. package/dist/flows/watch-batcher.js +0 -1
  144. package/dist/honesty/accepted-write.d.ts +14 -0
  145. package/dist/honesty/accepted-write.js +17 -0
  146. package/dist/honesty/blind-spots.d.ts +18 -1
  147. package/dist/honesty/blind-spots.js +47 -5
  148. package/dist/honesty/honesty.d.ts +0 -1
  149. package/dist/honesty/honesty.js +0 -1
  150. package/dist/honesty/uncaptured-bodies.d.ts +19 -0
  151. package/dist/honesty/uncaptured-bodies.js +30 -0
  152. package/dist/honesty/unread-outcome.d.ts +2 -0
  153. package/dist/honesty/unread-outcome.js +50 -0
  154. package/dist/honesty/verified.d.ts +40 -0
  155. package/dist/honesty/verified.js +86 -0
  156. package/dist/http-server.d.ts +0 -1
  157. package/dist/http-server.js +5 -1
  158. package/dist/hunt/hunt-report.d.ts +50 -0
  159. package/dist/hunt/hunt-report.js +84 -0
  160. package/dist/idle-shutdown.d.ts +0 -1
  161. package/dist/idle-shutdown.js +0 -1
  162. package/dist/index.d.ts +0 -1
  163. package/dist/index.js +0 -1
  164. package/dist/init/agent-rules.d.ts +0 -1
  165. package/dist/init/agent-rules.js +4 -2
  166. package/dist/init/cursor.d.ts +0 -1
  167. package/dist/init/cursor.js +0 -1
  168. package/dist/init/desktop-doctor.d.ts +40 -0
  169. package/dist/init/desktop-doctor.js +198 -0
  170. package/dist/init/detect.d.ts +0 -1
  171. package/dist/init/detect.js +0 -1
  172. package/dist/init/mcp.d.ts +0 -1
  173. package/dist/init/mcp.js +0 -1
  174. package/dist/init/node-io.d.ts +0 -1
  175. package/dist/init/node-io.js +0 -1
  176. package/dist/init/plan.d.ts +4 -1
  177. package/dist/init/plan.js +23 -5
  178. package/dist/init/project-id.d.ts +0 -1
  179. package/dist/init/project-id.js +0 -1
  180. package/dist/init/run.d.ts +0 -1
  181. package/dist/init/run.js +31 -3
  182. package/dist/init/snippets.d.ts +5 -1
  183. package/dist/init/snippets.js +5 -1
  184. package/dist/init/vite-config.d.ts +0 -1
  185. package/dist/init/vite-config.js +0 -1
  186. package/dist/input/network-detail.d.ts +0 -1
  187. package/dist/input/network-detail.js +0 -1
  188. package/dist/input/network-mock-tools.d.ts +0 -1
  189. package/dist/input/network-mock-tools.js +3 -4
  190. package/dist/input/network-mock.d.ts +0 -1
  191. package/dist/input/network-mock.js +0 -1
  192. package/dist/input/real-input.d.ts +14 -1
  193. package/dist/input/real-input.js +45 -3
  194. package/dist/input/scroll-find.d.ts +0 -1
  195. package/dist/input/scroll-find.js +0 -1
  196. package/dist/input/scroll-tools.d.ts +0 -1
  197. package/dist/input/scroll-tools.js +0 -1
  198. package/dist/input/viewport-tools.d.ts +0 -1
  199. package/dist/input/viewport-tools.js +3 -4
  200. package/dist/journal/ambient-store.d.ts +0 -1
  201. package/dist/journal/ambient-store.js +0 -1
  202. package/dist/journal/ambient.d.ts +0 -1
  203. package/dist/journal/ambient.js +0 -1
  204. package/dist/journal/attach-journal.d.ts +0 -1
  205. package/dist/journal/attach-journal.js +0 -1
  206. package/dist/journal/deviation-report.d.ts +0 -1
  207. package/dist/journal/deviation-report.js +0 -1
  208. package/dist/journal/deviation-service.d.ts +0 -1
  209. package/dist/journal/deviation-service.js +0 -1
  210. package/dist/journal/envelope-store.d.ts +0 -1
  211. package/dist/journal/envelope-store.js +0 -1
  212. package/dist/journal/envelope.d.ts +8 -9
  213. package/dist/journal/envelope.js +0 -1
  214. package/dist/journal/journal-query.d.ts +0 -1
  215. package/dist/journal/journal-query.js +0 -1
  216. package/dist/journal/journal-recorder.d.ts +0 -1
  217. package/dist/journal/journal-recorder.js +0 -1
  218. package/dist/journal/retention.d.ts +0 -1
  219. package/dist/journal/retention.js +0 -1
  220. package/dist/journal/rollups.d.ts +0 -1
  221. package/dist/journal/rollups.js +0 -1
  222. package/dist/journal/session-end.d.ts +0 -1
  223. package/dist/journal/session-end.js +0 -1
  224. package/dist/journal/session-journal.d.ts +0 -1
  225. package/dist/journal/session-journal.js +0 -1
  226. package/dist/license/license.d.ts +0 -1
  227. package/dist/license/license.js +0 -1
  228. package/dist/log.d.ts +0 -1
  229. package/dist/log.js +0 -1
  230. package/dist/mcp-proxy.d.ts +0 -1
  231. package/dist/mcp-proxy.js +0 -1
  232. package/dist/mcp.d.ts +15 -1
  233. package/dist/mcp.js +145 -17
  234. package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
  235. package/dist/oracles/flow-instrument-gaps.js +0 -1
  236. package/dist/oracles/propose-consequences.d.ts +0 -1
  237. package/dist/oracles/propose-consequences.js +0 -1
  238. package/dist/oracles/self-instrument.d.ts +0 -1
  239. package/dist/oracles/self-instrument.js +0 -1
  240. package/dist/pairing-token.d.ts +0 -1
  241. package/dist/pairing-token.js +0 -1
  242. package/dist/phenomena/phenomena.d.ts +0 -1
  243. package/dist/phenomena/phenomena.js +0 -1
  244. package/dist/pool/browser-pool.d.ts +0 -1
  245. package/dist/pool/browser-pool.js +0 -1
  246. package/dist/pool/lease-reaper.d.ts +0 -1
  247. package/dist/pool/lease-reaper.js +0 -1
  248. package/dist/pool/playwright-launcher.d.ts +2 -1
  249. package/dist/pool/playwright-launcher.js +22 -2
  250. package/dist/project/baselines.d.ts +0 -1
  251. package/dist/project/baselines.js +5 -4
  252. package/dist/project/file-lock.d.ts +2 -1
  253. package/dist/project/file-lock.js +12 -2
  254. package/dist/project/fs-port.d.ts +0 -1
  255. package/dist/project/fs-port.js +0 -1
  256. package/dist/project/project-store.d.ts +0 -1
  257. package/dist/project/project-store.js +20 -9
  258. package/dist/project/project-tools.d.ts +0 -1
  259. package/dist/project/project-tools.js +57 -9
  260. package/dist/project/reticle-dir.d.ts +0 -1
  261. package/dist/project/reticle-dir.js +0 -1
  262. package/dist/runs/build-verification-run.d.ts +0 -1
  263. package/dist/runs/build-verification-run.js +0 -1
  264. package/dist/runs/profile-redact.d.ts +0 -1
  265. package/dist/runs/profile-redact.js +0 -1
  266. package/dist/runs/render-report.d.ts +0 -1
  267. package/dist/runs/render-report.js +0 -1
  268. package/dist/runs/repair-prompt.d.ts +0 -1
  269. package/dist/runs/repair-prompt.js +0 -1
  270. package/dist/runs/replay-mapping.d.ts +0 -1
  271. package/dist/runs/replay-mapping.js +0 -1
  272. package/dist/runs/reticle-runner.d.ts +0 -1
  273. package/dist/runs/reticle-runner.js +4 -2
  274. package/dist/runs/risk-classify.d.ts +0 -1
  275. package/dist/runs/risk-classify.js +0 -1
  276. package/dist/runs/run-diff.d.ts +0 -1
  277. package/dist/runs/run-diff.js +0 -1
  278. package/dist/runs/run-store.d.ts +0 -1
  279. package/dist/runs/run-store.js +0 -1
  280. package/dist/runs/run-tools.d.ts +0 -1
  281. package/dist/runs/run-tools.js +0 -1
  282. package/dist/runs/runner-port.d.ts +0 -1
  283. package/dist/runs/runner-port.js +0 -1
  284. package/dist/runs/verification-sync.d.ts +23 -0
  285. package/dist/runs/verification-sync.js +66 -0
  286. package/dist/runs/verify-http.d.ts +0 -1
  287. package/dist/runs/verify-http.js +0 -1
  288. package/dist/runs/verify-server.d.ts +0 -1
  289. package/dist/runs/verify-server.js +0 -1
  290. package/dist/server-version.d.ts +0 -1
  291. package/dist/server-version.js +0 -1
  292. package/dist/session/command-timeout.d.ts +35 -0
  293. package/dist/session/command-timeout.js +41 -0
  294. package/dist/session/control-envelope.d.ts +2 -3
  295. package/dist/session/control-envelope.js +2 -3
  296. package/dist/session/last-act.d.ts +31 -0
  297. package/dist/session/last-act.js +24 -0
  298. package/dist/session/live-control-tools.d.ts +0 -1
  299. package/dist/session/live-control-tools.js +3 -4
  300. package/dist/session/live-control.d.ts +0 -1
  301. package/dist/session/live-control.js +0 -1
  302. package/dist/session/observed-state.d.ts +12 -2
  303. package/dist/session/observed-state.js +29 -2
  304. package/dist/session/output-budget.d.ts +0 -1
  305. package/dist/session/output-budget.js +0 -1
  306. package/dist/session/pending-commands.d.ts +12 -0
  307. package/dist/session/pending-commands.js +36 -0
  308. package/dist/session/presenter-args.d.ts +0 -1
  309. package/dist/session/presenter-args.js +0 -1
  310. package/dist/session/review-store.d.ts +0 -1
  311. package/dist/session/review-store.js +0 -1
  312. package/dist/session/session-health.d.ts +26 -2
  313. package/dist/session/session-health.js +13 -1
  314. package/dist/session/session-info.d.ts +29 -0
  315. package/dist/session/session-info.js +1 -0
  316. package/dist/session/session-lease.d.ts +25 -0
  317. package/dist/session/session-lease.js +14 -0
  318. package/dist/session/session-manager.d.ts +7 -19
  319. package/dist/session/session-manager.js +29 -2
  320. package/dist/session/session-readiness.d.ts +0 -1
  321. package/dist/session/session-readiness.js +3 -4
  322. package/dist/session/session-reaper.d.ts +0 -1
  323. package/dist/session/session-reaper.js +0 -1
  324. package/dist/session/session-recommendation.d.ts +0 -1
  325. package/dist/session/session-recommendation.js +0 -1
  326. package/dist/session/session-tools.d.ts +0 -1
  327. package/dist/session/session-tools.js +2 -3
  328. package/dist/session/session.d.ts +27 -53
  329. package/dist/session/session.js +95 -66
  330. package/dist/session/state-select.d.ts +0 -1
  331. package/dist/session/state-select.js +0 -1
  332. package/dist/telemetry/argument-shape.d.ts +41 -0
  333. package/dist/telemetry/argument-shape.js +87 -0
  334. package/dist/telemetry/bug-found.d.ts +33 -0
  335. package/dist/telemetry/bug-found.js +95 -0
  336. package/dist/telemetry/cli-telemetry.d.ts +13 -0
  337. package/dist/telemetry/cli-telemetry.js +43 -0
  338. package/dist/telemetry/connect-failure.d.ts +16 -0
  339. package/dist/telemetry/connect-failure.js +44 -0
  340. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  341. package/dist/telemetry/daemon-telemetry.js +76 -0
  342. package/dist/telemetry/dev-repo.d.ts +10 -0
  343. package/dist/telemetry/dev-repo.js +80 -0
  344. package/dist/telemetry/error-fingerprint.d.ts +24 -0
  345. package/dist/telemetry/error-fingerprint.js +88 -0
  346. package/dist/telemetry/feedback-cli.d.ts +31 -0
  347. package/dist/telemetry/feedback-cli.js +102 -0
  348. package/dist/telemetry/feedback-context.d.ts +32 -0
  349. package/dist/telemetry/feedback-context.js +143 -0
  350. package/dist/telemetry/feedback.d.ts +66 -0
  351. package/dist/telemetry/feedback.js +175 -0
  352. package/dist/telemetry/git-facts.d.ts +21 -0
  353. package/dist/telemetry/git-facts.js +109 -0
  354. package/dist/telemetry/identify.d.ts +22 -0
  355. package/dist/telemetry/identify.js +73 -0
  356. package/dist/telemetry/init-telemetry.d.ts +26 -0
  357. package/dist/telemetry/init-telemetry.js +33 -0
  358. package/dist/telemetry/machine-snapshot.d.ts +6 -0
  359. package/dist/telemetry/machine-snapshot.js +39 -0
  360. package/dist/telemetry/mcp-connection.d.ts +5 -0
  361. package/dist/telemetry/mcp-connection.js +44 -0
  362. package/dist/telemetry/project-profile.d.ts +44 -0
  363. package/dist/telemetry/project-profile.js +205 -0
  364. package/dist/telemetry/run-telemetry.d.ts +21 -0
  365. package/dist/telemetry/run-telemetry.js +62 -0
  366. package/dist/telemetry/session-metrics.d.ts +103 -0
  367. package/dist/telemetry/session-metrics.js +329 -0
  368. package/dist/telemetry/telemetry.d.ts +68 -0
  369. package/dist/telemetry/telemetry.js +313 -0
  370. package/dist/token-auth.d.ts +0 -1
  371. package/dist/token-auth.js +0 -1
  372. package/dist/tools/act-capsule.d.ts +23 -0
  373. package/dist/tools/act-capsule.js +47 -0
  374. package/dist/tools/act-danger.d.ts +7 -0
  375. package/dist/tools/act-danger.js +44 -0
  376. package/dist/tools/act-helpers.d.ts +17 -0
  377. package/dist/tools/act-helpers.js +40 -0
  378. package/dist/tools/act-tools.d.ts +8 -1
  379. package/dist/tools/act-tools.js +96 -98
  380. package/dist/tools/act-view.d.ts +7 -1
  381. package/dist/tools/act-view.js +13 -1
  382. package/dist/tools/assert-grade.d.ts +22 -1
  383. package/dist/tools/assert-grade.js +46 -1
  384. package/dist/tools/assert-verdict.d.ts +21 -0
  385. package/dist/tools/assert-verdict.js +62 -0
  386. package/dist/tools/browser-tools.d.ts +0 -1
  387. package/dist/tools/browser-tools.js +2 -2
  388. package/dist/tools/contract-tools.d.ts +0 -1
  389. package/dist/tools/contract-tools.js +0 -1
  390. package/dist/tools/coverage-tools.d.ts +9 -0
  391. package/dist/tools/coverage-tools.js +92 -0
  392. package/dist/tools/dynamic-tools.d.ts +0 -1
  393. package/dist/tools/dynamic-tools.js +21 -2
  394. package/dist/tools/error-recovery.d.ts +18 -2
  395. package/dist/tools/error-recovery.js +42 -7
  396. package/dist/tools/feedback-tools.d.ts +24 -0
  397. package/dist/tools/feedback-tools.js +180 -0
  398. package/dist/tools/invoke-tool.d.ts +0 -1
  399. package/dist/tools/invoke-tool.js +116 -2
  400. package/dist/tools/lease-tools.d.ts +0 -1
  401. package/dist/tools/lease-tools.js +6 -5
  402. package/dist/tools/merge-tools.d.ts +0 -1
  403. package/dist/tools/merge-tools.js +0 -1
  404. package/dist/tools/observe-tools.d.ts +0 -1
  405. package/dist/tools/observe-tools.js +91 -39
  406. package/dist/tools/profiles.d.ts +1 -2
  407. package/dist/tools/profiles.js +43 -16
  408. package/dist/tools/query-paginate.d.ts +0 -1
  409. package/dist/tools/query-paginate.js +0 -1
  410. package/dist/tools/read-tools.d.ts +0 -1
  411. package/dist/tools/read-tools.js +10 -8
  412. package/dist/tools/reconcile-tools.d.ts +2 -0
  413. package/dist/tools/reconcile-tools.js +111 -0
  414. package/dist/tools/snapshot-delta.d.ts +0 -1
  415. package/dist/tools/snapshot-delta.js +0 -0
  416. package/dist/tools/tool-invoker.d.ts +0 -1
  417. package/dist/tools/tool-invoker.js +0 -1
  418. package/dist/tools/tool-kit.d.ts +16 -1
  419. package/dist/tools/tool-kit.js +8 -2
  420. package/dist/tools/tool-names.d.ts +6 -1
  421. package/dist/tools/tool-names.js +6 -1
  422. package/dist/tools/tools-helpers.d.ts +0 -1
  423. package/dist/tools/tools-helpers.js +0 -1
  424. package/dist/tools/tools.d.ts +0 -1
  425. package/dist/tools/tools.js +24 -4
  426. package/dist/update/update-checker.d.ts +0 -1
  427. package/dist/update/update-checker.js +26 -2
  428. package/dist/update/update-nudge.d.ts +20 -0
  429. package/dist/update/update-nudge.js +72 -0
  430. package/dist/update/updater.d.ts +14 -1
  431. package/dist/update/updater.js +33 -2
  432. package/dist/visual/visual-diff.d.ts +0 -1
  433. package/dist/visual/visual-diff.js +0 -1
  434. package/dist/visual/visual-store.d.ts +0 -1
  435. package/dist/visual/visual-store.js +0 -1
  436. package/dist/visual/visual-tools.d.ts +0 -1
  437. package/dist/visual/visual-tools.js +103 -16
  438. package/package.json +2 -2
  439. package/dist/bridge-security.d.ts.map +0 -1
  440. package/dist/bridge-security.js.map +0 -1
  441. package/dist/bridge.d.ts.map +0 -1
  442. package/dist/bridge.js.map +0 -1
  443. package/dist/bridge.test-harness.d.ts.map +0 -1
  444. package/dist/bridge.test-harness.js.map +0 -1
  445. package/dist/capsule/capsule-store.d.ts.map +0 -1
  446. package/dist/capsule/capsule-store.js.map +0 -1
  447. package/dist/capsule/capsule.d.ts.map +0 -1
  448. package/dist/capsule/capsule.js.map +0 -1
  449. package/dist/capsule/causal-summary.d.ts.map +0 -1
  450. package/dist/capsule/causal-summary.js.map +0 -1
  451. package/dist/capsule/divergence.d.ts.map +0 -1
  452. package/dist/capsule/divergence.js.map +0 -1
  453. package/dist/capsule/minimize.d.ts.map +0 -1
  454. package/dist/capsule/minimize.js.map +0 -1
  455. package/dist/capsule/predicate-to-links.d.ts.map +0 -1
  456. package/dist/capsule/predicate-to-links.js.map +0 -1
  457. package/dist/cli-flow-commands.d.ts.map +0 -1
  458. package/dist/cli-flow-commands.js.map +0 -1
  459. package/dist/cli-launch.d.ts.map +0 -1
  460. package/dist/cli-launch.js.map +0 -1
  461. package/dist/cli-parse.d.ts.map +0 -1
  462. package/dist/cli-parse.js.map +0 -1
  463. package/dist/cli-port.d.ts.map +0 -1
  464. package/dist/cli-port.js.map +0 -1
  465. package/dist/cli-verify.d.ts.map +0 -1
  466. package/dist/cli-verify.js.map +0 -1
  467. package/dist/cli.d.ts.map +0 -1
  468. package/dist/cli.js.map +0 -1
  469. package/dist/cloud/cloud-sync.d.ts.map +0 -1
  470. package/dist/cloud/cloud-sync.js.map +0 -1
  471. package/dist/crawl/crawl-tools.d.ts.map +0 -1
  472. package/dist/crawl/crawl-tools.js.map +0 -1
  473. package/dist/crawl/crawl.d.ts.map +0 -1
  474. package/dist/crawl/crawl.js.map +0 -1
  475. package/dist/daemon-resilience.d.ts.map +0 -1
  476. package/dist/daemon-resilience.js.map +0 -1
  477. package/dist/daemon.d.ts.map +0 -1
  478. package/dist/daemon.js.map +0 -1
  479. package/dist/domain/domain-model.d.ts.map +0 -1
  480. package/dist/domain/domain-model.js.map +0 -1
  481. package/dist/domain/domain-tools.d.ts.map +0 -1
  482. package/dist/domain/domain-tools.js.map +0 -1
  483. package/dist/domain/flow-risk.d.ts.map +0 -1
  484. package/dist/domain/flow-risk.js.map +0 -1
  485. package/dist/ee/audit-log.d.ts.map +0 -1
  486. package/dist/ee/audit-log.js.map +0 -1
  487. package/dist/events/event-filters.d.ts.map +0 -1
  488. package/dist/events/event-filters.js.map +0 -1
  489. package/dist/events/predicate-eval.d.ts.map +0 -1
  490. package/dist/events/predicate-eval.js.map +0 -1
  491. package/dist/events/predicate.d.ts.map +0 -1
  492. package/dist/events/predicate.js.map +0 -1
  493. package/dist/events/reaction.d.ts.map +0 -1
  494. package/dist/events/reaction.js.map +0 -1
  495. package/dist/events/ring-buffer.d.ts.map +0 -1
  496. package/dist/events/ring-buffer.js.map +0 -1
  497. package/dist/flows/affected.d.ts.map +0 -1
  498. package/dist/flows/affected.js.map +0 -1
  499. package/dist/flows/annotate-tools.d.ts.map +0 -1
  500. package/dist/flows/annotate-tools.js.map +0 -1
  501. package/dist/flows/annotate.d.ts.map +0 -1
  502. package/dist/flows/annotate.js.map +0 -1
  503. package/dist/flows/annotation-store.d.ts.map +0 -1
  504. package/dist/flows/annotation-store.js.map +0 -1
  505. package/dist/flows/assertion-integrity.d.ts.map +0 -1
  506. package/dist/flows/assertion-integrity.js.map +0 -1
  507. package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
  508. package/dist/flows/assertion-tiers-store.js.map +0 -1
  509. package/dist/flows/buddy-status.d.ts.map +0 -1
  510. package/dist/flows/buddy-status.js.map +0 -1
  511. package/dist/flows/coverage.d.ts.map +0 -1
  512. package/dist/flows/coverage.js.map +0 -1
  513. package/dist/flows/decision.d.ts.map +0 -1
  514. package/dist/flows/decision.js.map +0 -1
  515. package/dist/flows/flake-store.d.ts.map +0 -1
  516. package/dist/flows/flake-store.js.map +0 -1
  517. package/dist/flows/flake.d.ts.map +0 -1
  518. package/dist/flows/flake.js.map +0 -1
  519. package/dist/flows/flow-classify.d.ts.map +0 -1
  520. package/dist/flows/flow-classify.js.map +0 -1
  521. package/dist/flows/flow-replay-run.d.ts.map +0 -1
  522. package/dist/flows/flow-replay-run.js.map +0 -1
  523. package/dist/flows/flow-replay.d.ts.map +0 -1
  524. package/dist/flows/flow-replay.js.map +0 -1
  525. package/dist/flows/flow-report.d.ts.map +0 -1
  526. package/dist/flows/flow-report.js.map +0 -1
  527. package/dist/flows/flow-scope.d.ts.map +0 -1
  528. package/dist/flows/flow-scope.js.map +0 -1
  529. package/dist/flows/flow-sources.d.ts.map +0 -1
  530. package/dist/flows/flow-sources.js.map +0 -1
  531. package/dist/flows/flow-success.d.ts.map +0 -1
  532. package/dist/flows/flow-success.js.map +0 -1
  533. package/dist/flows/flow-tools.d.ts.map +0 -1
  534. package/dist/flows/flow-tools.js.map +0 -1
  535. package/dist/flows/flows.d.ts.map +0 -1
  536. package/dist/flows/flows.js.map +0 -1
  537. package/dist/flows/gate.d.ts.map +0 -1
  538. package/dist/flows/gate.js.map +0 -1
  539. package/dist/flows/git-changed.d.ts.map +0 -1
  540. package/dist/flows/git-changed.js.map +0 -1
  541. package/dist/flows/heal-run.d.ts.map +0 -1
  542. package/dist/flows/heal-run.js.map +0 -1
  543. package/dist/flows/heal.d.ts.map +0 -1
  544. package/dist/flows/heal.js.map +0 -1
  545. package/dist/flows/parallel-suite.d.ts.map +0 -1
  546. package/dist/flows/parallel-suite.js.map +0 -1
  547. package/dist/flows/recordings.d.ts.map +0 -1
  548. package/dist/flows/recordings.js.map +0 -1
  549. package/dist/flows/replay.d.ts.map +0 -1
  550. package/dist/flows/replay.js.map +0 -1
  551. package/dist/flows/watch-batcher.d.ts.map +0 -1
  552. package/dist/flows/watch-batcher.js.map +0 -1
  553. package/dist/honesty/blind-spots.d.ts.map +0 -1
  554. package/dist/honesty/blind-spots.js.map +0 -1
  555. package/dist/honesty/honesty.d.ts.map +0 -1
  556. package/dist/honesty/honesty.js.map +0 -1
  557. package/dist/http-server.d.ts.map +0 -1
  558. package/dist/http-server.js.map +0 -1
  559. package/dist/idle-shutdown.d.ts.map +0 -1
  560. package/dist/idle-shutdown.js.map +0 -1
  561. package/dist/index.d.ts.map +0 -1
  562. package/dist/index.js.map +0 -1
  563. package/dist/init/agent-rules.d.ts.map +0 -1
  564. package/dist/init/agent-rules.js.map +0 -1
  565. package/dist/init/cursor.d.ts.map +0 -1
  566. package/dist/init/cursor.js.map +0 -1
  567. package/dist/init/detect.d.ts.map +0 -1
  568. package/dist/init/detect.js.map +0 -1
  569. package/dist/init/mcp.d.ts.map +0 -1
  570. package/dist/init/mcp.js.map +0 -1
  571. package/dist/init/node-io.d.ts.map +0 -1
  572. package/dist/init/node-io.js.map +0 -1
  573. package/dist/init/plan.d.ts.map +0 -1
  574. package/dist/init/plan.js.map +0 -1
  575. package/dist/init/project-id.d.ts.map +0 -1
  576. package/dist/init/project-id.js.map +0 -1
  577. package/dist/init/run.d.ts.map +0 -1
  578. package/dist/init/run.js.map +0 -1
  579. package/dist/init/snippets.d.ts.map +0 -1
  580. package/dist/init/snippets.js.map +0 -1
  581. package/dist/init/vite-config.d.ts.map +0 -1
  582. package/dist/init/vite-config.js.map +0 -1
  583. package/dist/input/network-detail.d.ts.map +0 -1
  584. package/dist/input/network-detail.js.map +0 -1
  585. package/dist/input/network-mock-tools.d.ts.map +0 -1
  586. package/dist/input/network-mock-tools.js.map +0 -1
  587. package/dist/input/network-mock.d.ts.map +0 -1
  588. package/dist/input/network-mock.js.map +0 -1
  589. package/dist/input/real-input.d.ts.map +0 -1
  590. package/dist/input/real-input.js.map +0 -1
  591. package/dist/input/scroll-find.d.ts.map +0 -1
  592. package/dist/input/scroll-find.js.map +0 -1
  593. package/dist/input/scroll-tools.d.ts.map +0 -1
  594. package/dist/input/scroll-tools.js.map +0 -1
  595. package/dist/input/viewport-tools.d.ts.map +0 -1
  596. package/dist/input/viewport-tools.js.map +0 -1
  597. package/dist/journal/ambient-store.d.ts.map +0 -1
  598. package/dist/journal/ambient-store.js.map +0 -1
  599. package/dist/journal/ambient.d.ts.map +0 -1
  600. package/dist/journal/ambient.js.map +0 -1
  601. package/dist/journal/attach-journal.d.ts.map +0 -1
  602. package/dist/journal/attach-journal.js.map +0 -1
  603. package/dist/journal/deviation-report.d.ts.map +0 -1
  604. package/dist/journal/deviation-report.js.map +0 -1
  605. package/dist/journal/deviation-service.d.ts.map +0 -1
  606. package/dist/journal/deviation-service.js.map +0 -1
  607. package/dist/journal/envelope-store.d.ts.map +0 -1
  608. package/dist/journal/envelope-store.js.map +0 -1
  609. package/dist/journal/envelope.d.ts.map +0 -1
  610. package/dist/journal/envelope.js.map +0 -1
  611. package/dist/journal/journal-query.d.ts.map +0 -1
  612. package/dist/journal/journal-query.js.map +0 -1
  613. package/dist/journal/journal-recorder.d.ts.map +0 -1
  614. package/dist/journal/journal-recorder.js.map +0 -1
  615. package/dist/journal/retention.d.ts.map +0 -1
  616. package/dist/journal/retention.js.map +0 -1
  617. package/dist/journal/rollups.d.ts.map +0 -1
  618. package/dist/journal/rollups.js.map +0 -1
  619. package/dist/journal/session-end.d.ts.map +0 -1
  620. package/dist/journal/session-end.js.map +0 -1
  621. package/dist/journal/session-journal.d.ts.map +0 -1
  622. package/dist/journal/session-journal.js.map +0 -1
  623. package/dist/license/license.d.ts.map +0 -1
  624. package/dist/license/license.js.map +0 -1
  625. package/dist/log.d.ts.map +0 -1
  626. package/dist/log.js.map +0 -1
  627. package/dist/mcp-proxy.d.ts.map +0 -1
  628. package/dist/mcp-proxy.js.map +0 -1
  629. package/dist/mcp.d.ts.map +0 -1
  630. package/dist/mcp.js.map +0 -1
  631. package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
  632. package/dist/oracles/flow-instrument-gaps.js.map +0 -1
  633. package/dist/oracles/propose-consequences.d.ts.map +0 -1
  634. package/dist/oracles/propose-consequences.js.map +0 -1
  635. package/dist/oracles/self-instrument.d.ts.map +0 -1
  636. package/dist/oracles/self-instrument.js.map +0 -1
  637. package/dist/pairing-token.d.ts.map +0 -1
  638. package/dist/pairing-token.js.map +0 -1
  639. package/dist/phenomena/phenomena.d.ts.map +0 -1
  640. package/dist/phenomena/phenomena.js.map +0 -1
  641. package/dist/pool/browser-pool.d.ts.map +0 -1
  642. package/dist/pool/browser-pool.js.map +0 -1
  643. package/dist/pool/lease-reaper.d.ts.map +0 -1
  644. package/dist/pool/lease-reaper.js.map +0 -1
  645. package/dist/pool/playwright-launcher.d.ts.map +0 -1
  646. package/dist/pool/playwright-launcher.js.map +0 -1
  647. package/dist/project/baselines.d.ts.map +0 -1
  648. package/dist/project/baselines.js.map +0 -1
  649. package/dist/project/file-lock.d.ts.map +0 -1
  650. package/dist/project/file-lock.js.map +0 -1
  651. package/dist/project/fs-port.d.ts.map +0 -1
  652. package/dist/project/fs-port.js.map +0 -1
  653. package/dist/project/project-store.d.ts.map +0 -1
  654. package/dist/project/project-store.js.map +0 -1
  655. package/dist/project/project-tools.d.ts.map +0 -1
  656. package/dist/project/project-tools.js.map +0 -1
  657. package/dist/project/reticle-dir.d.ts.map +0 -1
  658. package/dist/project/reticle-dir.js.map +0 -1
  659. package/dist/runs/build-verification-run.d.ts.map +0 -1
  660. package/dist/runs/build-verification-run.js.map +0 -1
  661. package/dist/runs/profile-redact.d.ts.map +0 -1
  662. package/dist/runs/profile-redact.js.map +0 -1
  663. package/dist/runs/render-report.d.ts.map +0 -1
  664. package/dist/runs/render-report.js.map +0 -1
  665. package/dist/runs/repair-prompt.d.ts.map +0 -1
  666. package/dist/runs/repair-prompt.js.map +0 -1
  667. package/dist/runs/replay-mapping.d.ts.map +0 -1
  668. package/dist/runs/replay-mapping.js.map +0 -1
  669. package/dist/runs/reticle-runner.d.ts.map +0 -1
  670. package/dist/runs/reticle-runner.js.map +0 -1
  671. package/dist/runs/risk-classify.d.ts.map +0 -1
  672. package/dist/runs/risk-classify.js.map +0 -1
  673. package/dist/runs/run-diff.d.ts.map +0 -1
  674. package/dist/runs/run-diff.js.map +0 -1
  675. package/dist/runs/run-store.d.ts.map +0 -1
  676. package/dist/runs/run-store.js.map +0 -1
  677. package/dist/runs/run-tools.d.ts.map +0 -1
  678. package/dist/runs/run-tools.js.map +0 -1
  679. package/dist/runs/runner-port.d.ts.map +0 -1
  680. package/dist/runs/runner-port.js.map +0 -1
  681. package/dist/runs/verify-http.d.ts.map +0 -1
  682. package/dist/runs/verify-http.js.map +0 -1
  683. package/dist/runs/verify-server.d.ts.map +0 -1
  684. package/dist/runs/verify-server.js.map +0 -1
  685. package/dist/server-version.d.ts.map +0 -1
  686. package/dist/server-version.js.map +0 -1
  687. package/dist/session/control-envelope.d.ts.map +0 -1
  688. package/dist/session/control-envelope.js.map +0 -1
  689. package/dist/session/live-control-tools.d.ts.map +0 -1
  690. package/dist/session/live-control-tools.js.map +0 -1
  691. package/dist/session/live-control.d.ts.map +0 -1
  692. package/dist/session/live-control.js.map +0 -1
  693. package/dist/session/observed-state.d.ts.map +0 -1
  694. package/dist/session/observed-state.js.map +0 -1
  695. package/dist/session/output-budget.d.ts.map +0 -1
  696. package/dist/session/output-budget.js.map +0 -1
  697. package/dist/session/presenter-args.d.ts.map +0 -1
  698. package/dist/session/presenter-args.js.map +0 -1
  699. package/dist/session/review-store.d.ts.map +0 -1
  700. package/dist/session/review-store.js.map +0 -1
  701. package/dist/session/session-health.d.ts.map +0 -1
  702. package/dist/session/session-health.js.map +0 -1
  703. package/dist/session/session-manager.d.ts.map +0 -1
  704. package/dist/session/session-manager.js.map +0 -1
  705. package/dist/session/session-readiness.d.ts.map +0 -1
  706. package/dist/session/session-readiness.js.map +0 -1
  707. package/dist/session/session-reaper.d.ts.map +0 -1
  708. package/dist/session/session-reaper.js.map +0 -1
  709. package/dist/session/session-recommendation.d.ts.map +0 -1
  710. package/dist/session/session-recommendation.js.map +0 -1
  711. package/dist/session/session-tools.d.ts.map +0 -1
  712. package/dist/session/session-tools.js.map +0 -1
  713. package/dist/session/session.d.ts.map +0 -1
  714. package/dist/session/session.js.map +0 -1
  715. package/dist/session/state-select.d.ts.map +0 -1
  716. package/dist/session/state-select.js.map +0 -1
  717. package/dist/token-auth.d.ts.map +0 -1
  718. package/dist/token-auth.js.map +0 -1
  719. package/dist/tools/act-tools.d.ts.map +0 -1
  720. package/dist/tools/act-tools.js.map +0 -1
  721. package/dist/tools/act-view.d.ts.map +0 -1
  722. package/dist/tools/act-view.js.map +0 -1
  723. package/dist/tools/assert-grade.d.ts.map +0 -1
  724. package/dist/tools/assert-grade.js.map +0 -1
  725. package/dist/tools/browser-tools.d.ts.map +0 -1
  726. package/dist/tools/browser-tools.js.map +0 -1
  727. package/dist/tools/contract-tools.d.ts.map +0 -1
  728. package/dist/tools/contract-tools.js.map +0 -1
  729. package/dist/tools/dynamic-tools.d.ts.map +0 -1
  730. package/dist/tools/dynamic-tools.js.map +0 -1
  731. package/dist/tools/error-recovery.d.ts.map +0 -1
  732. package/dist/tools/error-recovery.js.map +0 -1
  733. package/dist/tools/invoke-tool.d.ts.map +0 -1
  734. package/dist/tools/invoke-tool.js.map +0 -1
  735. package/dist/tools/lease-tools.d.ts.map +0 -1
  736. package/dist/tools/lease-tools.js.map +0 -1
  737. package/dist/tools/merge-tools.d.ts.map +0 -1
  738. package/dist/tools/merge-tools.js.map +0 -1
  739. package/dist/tools/observe-tools.d.ts.map +0 -1
  740. package/dist/tools/observe-tools.js.map +0 -1
  741. package/dist/tools/profiles.d.ts.map +0 -1
  742. package/dist/tools/profiles.js.map +0 -1
  743. package/dist/tools/query-paginate.d.ts.map +0 -1
  744. package/dist/tools/query-paginate.js.map +0 -1
  745. package/dist/tools/read-tools.d.ts.map +0 -1
  746. package/dist/tools/read-tools.js.map +0 -1
  747. package/dist/tools/snapshot-delta.d.ts.map +0 -1
  748. package/dist/tools/snapshot-delta.js.map +0 -1
  749. package/dist/tools/tool-invoker.d.ts.map +0 -1
  750. package/dist/tools/tool-invoker.js.map +0 -1
  751. package/dist/tools/tool-kit.d.ts.map +0 -1
  752. package/dist/tools/tool-kit.js.map +0 -1
  753. package/dist/tools/tool-names.d.ts.map +0 -1
  754. package/dist/tools/tool-names.js.map +0 -1
  755. package/dist/tools/tools-helpers.d.ts.map +0 -1
  756. package/dist/tools/tools-helpers.js.map +0 -1
  757. package/dist/tools/tools.d.ts.map +0 -1
  758. package/dist/tools/tools.js.map +0 -1
  759. package/dist/update/update-checker.d.ts.map +0 -1
  760. package/dist/update/update-checker.js.map +0 -1
  761. package/dist/update/updater.d.ts.map +0 -1
  762. package/dist/update/updater.js.map +0 -1
  763. package/dist/visual/visual-diff.d.ts.map +0 -1
  764. package/dist/visual/visual-diff.js.map +0 -1
  765. package/dist/visual/visual-store.d.ts.map +0 -1
  766. package/dist/visual/visual-store.js.map +0 -1
  767. package/dist/visual/visual-tools.d.ts.map +0 -1
  768. package/dist/visual/visual-tools.js.map +0 -1
@@ -0,0 +1,514 @@
1
+ /**
2
+ * Cloud subcommands for the `reticle` CLI — the user/agent door to Reticle Cloud, folded into the ONE
3
+ * tool (was the standalone `reticle-cloud` bootstrap script). These are THIN clients over the `/v1` API:
4
+ * the moat is the server, not these verbs, and OSS reticle already ships the cloud-sync client — this just
5
+ * surfaces it. Creds live under `~/.reticle`: `session.json` (human token from `reticle login`) and
6
+ * `credentials.json` (per-project api keys from `reticle link`). The non-secret repo binding + sync policy
7
+ * is `<repo>/.reticle/cloud.json`. Auth for a command = `RETICLE_CLOUD_KEY` env (agent) OR the login token.
8
+ */
9
+ import { mkdir, writeFile, readFile } from 'node:fs/promises';
10
+ import { spawn } from 'node:child_process';
11
+ import { setTimeout as sleep } from 'node:timers/promises';
12
+ import { homedir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ import { z } from 'zod';
15
+ import { createNodeFileSystem } from './project/fs-port.js';
16
+ import { RunStore } from './runs/run-store.js';
17
+ import { resolveProjectCloud } from './cloud/cloud-config.js';
18
+ import { syncRunToCloud, SyncOutcome } from './cloud/cloud-sync.js';
19
+ const DEFAULT_URL = 'http://localhost:8890';
20
+ const RETICLE_DIR = '.reticle';
21
+ const SESSION_FILE = 'session.json';
22
+ const CREDENTIALS_FILE = 'credentials.json';
23
+ const CLOUD_LINK_FILE = 'cloud.json';
24
+ const DEFAULT_PROJECT_ID = 'default';
25
+ const CLOUD_COMMANDS = new Set([
26
+ 'login',
27
+ 'logout',
28
+ 'whoami',
29
+ 'link',
30
+ 'project',
31
+ 'config',
32
+ 'push',
33
+ 'runs',
34
+ 'regression',
35
+ 'share',
36
+ ]);
37
+ export const isCloudCommand = (cmd) => cmd !== undefined && CLOUD_COMMANDS.has(cmd);
38
+ const home = () => join(homedir(), RETICLE_DIR);
39
+ const err = (msg) => {
40
+ process.stderr.write(`reticle: ${msg}\n`);
41
+ };
42
+ /** A next-step nudge on stderr (humans read it; agents parse stdout JSON and ignore this). */
43
+ const hint = (msg) => {
44
+ process.stderr.write(`→ ${msg}\n`);
45
+ };
46
+ const emit = (obj) => {
47
+ process.stdout.write(`${JSON.stringify(obj, null, 2)}\n`);
48
+ };
49
+ /** Read + parse a JSON file, or null when missing/malformed (never throws). */
50
+ const readJson = async (path) => {
51
+ try {
52
+ return JSON.parse(await readFile(path, 'utf8'));
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ };
58
+ /** Parse `--flag value` pairs out of an argv tail. */
59
+ const flags = (argv) => {
60
+ const f = {};
61
+ for (let i = 0; i < argv.length; i += 1) {
62
+ const a = argv[i];
63
+ if (a !== undefined && a.startsWith('--') && i + 1 < argv.length) {
64
+ const v = argv[i + 1];
65
+ if (v !== undefined)
66
+ f[a.slice(2)] = v;
67
+ i += 1;
68
+ }
69
+ }
70
+ return f;
71
+ };
72
+ const SessionSchema = z.object({ url: z.string(), token: z.string(), orgName: z.string() });
73
+ const readSession = async () => {
74
+ const parsed = SessionSchema.safeParse(await readJson(join(home(), SESSION_FILE)));
75
+ return parsed.success ? parsed.data : null;
76
+ };
77
+ const baseUrl = (session) => {
78
+ const env = process.env['RETICLE_CLOUD_URL'];
79
+ return env !== undefined && env.length > 0
80
+ ? env.replace(/\/+$/, '')
81
+ : (session?.url ?? DEFAULT_URL);
82
+ };
83
+ /** Bearer for a command: an explicit api key (agent) wins, else the human login token. */
84
+ const bearer = (session) => {
85
+ const key = process.env['RETICLE_CLOUD_KEY'];
86
+ if (key !== undefined && key.length > 0)
87
+ return key;
88
+ return session?.token ?? null;
89
+ };
90
+ /** One `/v1` call. Throws a friendly Error on a non-2xx so the command surfaces it and exits 1. */
91
+ const api = async (method, url, token, body) => {
92
+ const headers = {};
93
+ if (token !== null)
94
+ headers['authorization'] = `Bearer ${token}`;
95
+ if (body !== undefined)
96
+ headers['content-type'] = 'application/json';
97
+ const init = {
98
+ method,
99
+ headers,
100
+ };
101
+ if (body !== undefined)
102
+ init.body = JSON.stringify(body);
103
+ const res = await fetch(url, init);
104
+ const text = await res.text();
105
+ let json = null;
106
+ if (text.length > 0) {
107
+ try {
108
+ json = JSON.parse(text);
109
+ }
110
+ catch {
111
+ throw new Error(`expected JSON from ${method} ${url} but got: ${text.slice(0, 120)}`);
112
+ }
113
+ }
114
+ if (!res.ok) {
115
+ const parsed = z.object({ error: z.object({ message: z.string() }) }).safeParse(json);
116
+ throw new Error(parsed.success ? parsed.data.error.message : `${res.status} ${res.statusText}`);
117
+ }
118
+ return json;
119
+ };
120
+ const LoginSchema = z.object({ token: z.string(), org: z.object({ name: z.string() }) });
121
+ const KeySchema = z.object({ projectId: z.string(), projectName: z.string(), key: z.string() });
122
+ const WhoamiSchema = z.object({ projectId: z.string(), projectName: z.string() });
123
+ const CreatedProjectSchema = z.object({ projectId: z.string(), name: z.string() });
124
+ const ProjectsListSchema = z.object({
125
+ projects: z.array(z.object({ projectId: z.string(), name: z.string() })),
126
+ });
127
+ /** Resolve a --project value that may be a slug id OR a display name into the canonical projectId. */
128
+ const resolveProjectId = async (url, token, wanted) => {
129
+ const { projects } = ProjectsListSchema.parse(await api('GET', `${url}/v1/projects`, token));
130
+ const lc = wanted.toLowerCase();
131
+ const match = projects.find((p) => p.projectId === wanted || p.name.toLowerCase() === lc);
132
+ if (match === undefined)
133
+ throw new Error(`no project "${wanted}" — create it with \`reticle project create "${wanted}"\``);
134
+ return match.projectId;
135
+ };
136
+ /**
137
+ * `reticle login --email <e> [--org <name>] [--code <123456>]` — sign in, cache the token under
138
+ * ~/.reticle.
139
+ *
140
+ * TWO STEPS, because the cloud proves you own the inbox before it hands out a session: ask for a code,
141
+ * then exchange it. (It used to take an email alone — which meant anyone who knew your address owned your
142
+ * org.) `--org` is only consulted when the account is brand new; a returning user never needs it.
143
+ *
144
+ * Without `--code` we request one and stop, telling the user to re-run with it. The one exception is a
145
+ * LOCAL cloud, whose dev mailer cannot actually deliver mail and so echoes the code back in its response
146
+ * (`devCode`) — there we complete the login in a single command rather than asking a developer to read a
147
+ * code out of a server log they may not even be tailing.
148
+ */
149
+ const RequestCodeSchema = z.object({ devCode: z.string().optional() });
150
+ const DeviceStartSchema = z.object({
151
+ deviceCode: z.string(),
152
+ userCode: z.string(),
153
+ verificationUri: z.string(),
154
+ verificationUriComplete: z.string(),
155
+ interval: z.number(),
156
+ expiresAt: z.number(),
157
+ });
158
+ const DevicePollSchema = z.object({
159
+ status: z.string(),
160
+ token: z.string().optional(),
161
+ org: z.object({ name: z.string() }).optional(),
162
+ });
163
+ /** Best-effort open the approval page in the default browser; the printed URL is the headless fallback. */
164
+ const openBrowser = (target) => {
165
+ const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
166
+ const args = process.platform === 'win32' ? ['/c', 'start', '', target] : [target];
167
+ try {
168
+ const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
169
+ child.on('error', () => undefined);
170
+ child.unref();
171
+ }
172
+ catch {
173
+ /* no opener available — the user opens the printed URL manually */
174
+ }
175
+ };
176
+ /** Persist a session token under ~/.reticle and print the next step. Shared by both login paths. */
177
+ const writeSession = async (url, token, orgName) => {
178
+ await mkdir(home(), { recursive: true });
179
+ await writeFile(join(home(), SESSION_FILE), `${JSON.stringify({ url, token, orgName }, null, 2)}\n`);
180
+ emit({ loggedIn: orgName, session: join(home(), SESSION_FILE) });
181
+ hint('next: `reticle link` to bind this repo to your Default project (or `reticle project create <name>` first)');
182
+ };
183
+ /**
184
+ * Browser device flow — the DEFAULT `reticle login` (like `gh auth login`): fetch a device + user code,
185
+ * open the browser to approve, then poll until the user confirms. No email to type, no code to copy back.
186
+ */
187
+ const cmdLoginDevice = async () => {
188
+ const url = baseUrl(null);
189
+ const started = DeviceStartSchema.parse(await api('POST', `${url}/v1/auth/device/start`, null, {}));
190
+ hint(`Opening ${started.verificationUri} — confirm this code in the browser: ${started.userCode}`);
191
+ openBrowser(started.verificationUriComplete);
192
+ const intervalMs = Math.max(1, started.interval) * 1000;
193
+ for (;;) {
194
+ await sleep(intervalMs);
195
+ const poll = DevicePollSchema.parse(await api('POST', `${url}/v1/auth/device/token`, null, { deviceCode: started.deviceCode }));
196
+ if (poll.status === 'approved' && poll.token !== undefined && poll.org !== undefined) {
197
+ await writeSession(url, poll.token, poll.org.name);
198
+ return 0;
199
+ }
200
+ if (poll.status === 'pending') {
201
+ if (Date.now() > started.expiresAt) {
202
+ err('device login expired — run `reticle login` again');
203
+ return 1;
204
+ }
205
+ continue;
206
+ }
207
+ err(poll.status === 'denied'
208
+ ? 'device login was denied in the browser'
209
+ : 'device login expired — run `reticle login` again');
210
+ return 1;
211
+ }
212
+ };
213
+ /**
214
+ * `reticle login` — browser device flow by default; `--email <e>` (or a positional email) keeps the
215
+ * headless two-step code path for CI/servers where opening a browser makes no sense.
216
+ */
217
+ const cmdLogin = async (argv) => {
218
+ const f = flags(argv);
219
+ const positional = argv[0] !== undefined && !argv[0].startsWith('--') ? argv[0] : undefined;
220
+ const email = f['email'] ?? positional;
221
+ if (email === undefined)
222
+ return cmdLoginDevice();
223
+ const org = f['org'];
224
+ const url = baseUrl(null);
225
+ let code = f['code'];
226
+ if (code === undefined) {
227
+ const requested = RequestCodeSchema.parse(await api('POST', `${url}/v1/auth/request-code`, null, {
228
+ email,
229
+ ...(org !== undefined ? { orgName: org } : {}),
230
+ }));
231
+ // A real cloud mails the code and never echoes it; a local one cannot mail, so it hands it back.
232
+ if (requested.devCode === undefined) {
233
+ emit({ codeSent: true, to: email });
234
+ hint(`check your inbox, then: \`reticle login --email ${email} --code <the 6-digit code>\``);
235
+ return 0;
236
+ }
237
+ code = requested.devCode;
238
+ }
239
+ const parsed = LoginSchema.parse(await api('POST', `${url}/v1/auth/login`, null, { email, code }));
240
+ await writeSession(url, parsed.token, parsed.org.name);
241
+ return 0;
242
+ };
243
+ /** `reticle logout` — forget the cached session token (per-project keys under credentials.json stay). */
244
+ const cmdLogout = async () => {
245
+ await writeFile(join(home(), SESSION_FILE), '').catch(() => undefined);
246
+ emit({ loggedOut: true });
247
+ return 0;
248
+ };
249
+ /**
250
+ * `reticle whoami` — the one call an agent (or a confused human) makes to know its state: who am I logged
251
+ * in as, and is THIS repo attached to a cloud project (and with what sync policy / verify mode)?
252
+ */
253
+ const cmdWhoami = async () => {
254
+ const session = await readSession();
255
+ const fs = createNodeFileSystem();
256
+ const cloud = await resolveProjectCloud(fs, join(process.cwd(), RETICLE_DIR), homedir(), process.env);
257
+ emit({
258
+ loggedInAs: session?.orgName ?? null,
259
+ repo: {
260
+ attached: cloud.config !== null,
261
+ projectId: cloud.projectId,
262
+ url: cloud.config?.url ?? null,
263
+ sync: cloud.policy,
264
+ verify: cloud.verify,
265
+ },
266
+ });
267
+ if (cloud.config === null)
268
+ hint('this repo is not attached — run `reticle link`');
269
+ return 0;
270
+ };
271
+ /** `reticle project ls` / `reticle project create <name>` — key- or session-authed. */
272
+ const cmdProject = async (argv) => {
273
+ const session = await readSession();
274
+ const token = bearer(session);
275
+ const url = baseUrl(session);
276
+ if (token === null) {
277
+ err('run `reticle login` first, or set RETICLE_CLOUD_KEY');
278
+ return 2;
279
+ }
280
+ const sub = argv[0];
281
+ if (sub === 'ls') {
282
+ emit(await api('GET', `${url}/v1/projects`, token));
283
+ return 0;
284
+ }
285
+ if (sub === 'create') {
286
+ const name = argv.slice(1).join(' ').trim();
287
+ if (name.length === 0) {
288
+ err('usage: reticle project create <name>');
289
+ return 2;
290
+ }
291
+ const created = CreatedProjectSchema.parse(await api('POST', `${url}/v1/projects`, token, { name }));
292
+ emit(created);
293
+ hint(`next: \`reticle link --project ${created.projectId}\` to bind this repo`);
294
+ return 0;
295
+ }
296
+ if (sub === 'rename') {
297
+ const id = argv[1];
298
+ const name = argv.slice(2).join(' ').trim();
299
+ if (id === undefined || name.length === 0) {
300
+ err('usage: reticle project rename <projectId> <new name>');
301
+ return 2;
302
+ }
303
+ emit(await api('PATCH', `${url}/v1/projects/${encodeURIComponent(id)}`, token, { name }));
304
+ return 0;
305
+ }
306
+ if (sub === 'rm' || sub === 'delete') {
307
+ const id = argv[1];
308
+ if (id === undefined) {
309
+ err('usage: reticle project rm <projectId>');
310
+ return 2;
311
+ }
312
+ emit(await api('DELETE', `${url}/v1/projects/${encodeURIComponent(id)}`, token));
313
+ return 0;
314
+ }
315
+ err('usage: reticle project <ls|create <name>|rename <id> <name>|rm <id>>');
316
+ return 2;
317
+ };
318
+ /**
319
+ * `reticle link [--project <id>]` — bind THIS repo to a cloud project. With a login token it MINTS a
320
+ * project-scoped key (no pasting); with a pre-set RETICLE_CLOUD_KEY it resolves the key's project via
321
+ * whoami. Writes the non-secret binding to <repo>/.reticle/cloud.json and the secret key to
322
+ * ~/.reticle/credentials.json (keyed by projectId).
323
+ */
324
+ const cmdLink = async (argv) => {
325
+ const f = flags(argv);
326
+ const session = await readSession();
327
+ const url = baseUrl(session);
328
+ const envKey = process.env['RETICLE_CLOUD_KEY'];
329
+ let projectId;
330
+ let projectName;
331
+ let key;
332
+ if (envKey !== undefined && envKey.length > 0) {
333
+ const who = WhoamiSchema.parse(await api('GET', `${url}/v1/cloud/whoami`, envKey));
334
+ projectId = who.projectId;
335
+ projectName = who.projectName;
336
+ key = envKey;
337
+ }
338
+ else if (session !== null) {
339
+ // --project accepts a slug id OR a display name; default when omitted. Resolve to the canonical id.
340
+ const wanted = f['project'];
341
+ const targetId = wanted === undefined
342
+ ? DEFAULT_PROJECT_ID
343
+ : await resolveProjectId(url, session.token, wanted);
344
+ const minted = KeySchema.parse(await api('POST', `${url}/v1/keys`, session.token, {
345
+ name: 'reticle-cli',
346
+ projectId: targetId,
347
+ }));
348
+ projectId = minted.projectId;
349
+ projectName = minted.projectName;
350
+ key = minted.key;
351
+ }
352
+ else {
353
+ err('run `reticle login` first, or set RETICLE_CLOUD_KEY to link with an existing key');
354
+ return 2;
355
+ }
356
+ const reticleDir = join(process.cwd(), RETICLE_DIR);
357
+ await mkdir(reticleDir, { recursive: true });
358
+ const linkPath = join(reticleDir, CLOUD_LINK_FILE);
359
+ const prev = await readJson(linkPath);
360
+ const prevObj = typeof prev === 'object' && prev !== null ? prev : {};
361
+ const cloudJson = {
362
+ projectId,
363
+ projectName,
364
+ url,
365
+ sync: prevObj['sync'] ?? { runs: true, memory: true, flows: true },
366
+ verify: prevObj['verify'] ?? 'local',
367
+ };
368
+ await writeFile(linkPath, `${JSON.stringify(cloudJson, null, 2)}\n`);
369
+ await mkdir(home(), { recursive: true });
370
+ const credPath = join(home(), CREDENTIALS_FILE);
371
+ const creds = (await readJson(credPath)) ?? {};
372
+ const credObj = typeof creds === 'object' && creds !== null ? creds : {};
373
+ credObj[projectId] = key;
374
+ await writeFile(credPath, `${JSON.stringify(credObj, null, 2)}\n`);
375
+ emit({ linked: projectName, projectId, cloudJson: linkPath, credentials: credPath });
376
+ hint('linked ✓ runs auto-push on `reticle verify`; `reticle push` sends existing local runs; `reticle whoami` shows state');
377
+ return 0;
378
+ };
379
+ /** `reticle config [--runs on|off] [--memory on|off] [--flows on|off] [--verify local|server]`. */
380
+ const cmdConfig = async (argv) => {
381
+ const f = flags(argv);
382
+ const linkPath = join(process.cwd(), RETICLE_DIR, CLOUD_LINK_FILE);
383
+ const raw = await readJson(linkPath);
384
+ if (raw === null || typeof raw !== 'object') {
385
+ err('no .reticle/cloud.json here — run `reticle link` first');
386
+ return 2;
387
+ }
388
+ const cfg = raw;
389
+ const sync = typeof cfg['sync'] === 'object' && cfg['sync'] !== null
390
+ ? cfg['sync']
391
+ : { runs: true, memory: true, flows: true };
392
+ const onoff = (v) => v === 'on' ? true : v === 'off' ? false : undefined;
393
+ for (const k of ['runs', 'memory', 'flows']) {
394
+ if (f[k] === undefined)
395
+ continue;
396
+ const b = onoff(f[k]);
397
+ if (b === undefined) {
398
+ err(`--${k} must be on|off`);
399
+ return 2;
400
+ }
401
+ sync[k] = b;
402
+ }
403
+ cfg['sync'] = sync;
404
+ if (f['verify'] !== undefined) {
405
+ if (f['verify'] !== 'local' && f['verify'] !== 'server') {
406
+ err('--verify must be local|server');
407
+ return 2;
408
+ }
409
+ cfg['verify'] = f['verify'];
410
+ }
411
+ await writeFile(linkPath, `${JSON.stringify(cfg, null, 2)}\n`);
412
+ emit({ updated: linkPath, sync: cfg['sync'], verify: cfg['verify'] });
413
+ return 0;
414
+ };
415
+ /** `reticle push` — best-effort push of local run artifacts to the linked project (honors sync policy). */
416
+ const cmdPush = async () => {
417
+ const fs = createNodeFileSystem();
418
+ const reticleRoot = join(process.cwd(), RETICLE_DIR);
419
+ const cloud = await resolveProjectCloud(fs, reticleRoot, homedir(), process.env);
420
+ if (cloud.config === null) {
421
+ err('cloud not attached here — run `reticle link` (or set RETICLE_CLOUD_URL/KEY)');
422
+ return 1;
423
+ }
424
+ if (!cloud.policy.runs) {
425
+ emit({ pushed: 0, skipped: 'sync.runs is off for this project (reticle config --runs on)' });
426
+ return 0;
427
+ }
428
+ const store = new RunStore(fs, reticleRoot);
429
+ const ids = await store.list();
430
+ let pushed = 0;
431
+ let failed = 0;
432
+ for (const id of ids) {
433
+ const read = await store.read(id);
434
+ if (!read.ok)
435
+ continue;
436
+ const res = await syncRunToCloud(read.run, cloud.config, (u, init) => fetch(u, init));
437
+ if (res.outcome === SyncOutcome.SYNCED)
438
+ pushed += 1;
439
+ else if (res.outcome === SyncOutcome.FAILED)
440
+ failed += 1;
441
+ }
442
+ emit({ pushed, failed, total: ids.length, project: cloud.projectId });
443
+ if (pushed > 0)
444
+ hint(`pushed ✓ see them in the dashboard Runs tab (${cloud.config.url})`);
445
+ return 0;
446
+ };
447
+ /** Resolve THIS repo's linked cloud (url + project-scoped key). Throws a friendly error if not attached. */
448
+ const repoCloud = async () => {
449
+ const fs = createNodeFileSystem();
450
+ const cloud = await resolveProjectCloud(fs, join(process.cwd(), RETICLE_DIR), homedir(), process.env);
451
+ if (cloud.config === null)
452
+ throw new Error('cloud not attached here — run `reticle link` (or set RETICLE_CLOUD_URL/KEY)');
453
+ return cloud.config;
454
+ };
455
+ /** `reticle runs` — the linked project's recent run artifacts (the key scopes it server-side). */
456
+ const cmdRuns = async () => {
457
+ const { url, apiKey } = await repoCloud();
458
+ emit(await api('GET', `${url}/v1/runs`, apiKey));
459
+ return 0;
460
+ };
461
+ /** `reticle regression` — the CI gate: broken flows vs before. Exit 3 if any regressed (pipeline-friendly). */
462
+ const cmdRegression = async () => {
463
+ const { url, apiKey } = await repoCloud();
464
+ const report = await api('GET', `${url}/v1/project/regression`, apiKey);
465
+ emit(report);
466
+ const parsed = z.object({ broken: z.array(z.unknown()) }).safeParse(report);
467
+ return parsed.success && parsed.data.broken.length > 0 ? 3 : 0;
468
+ };
469
+ /** `reticle share <runId>` — mint a public proof link for one run. */
470
+ const cmdShare = async (argv) => {
471
+ const runId = argv[0];
472
+ if (runId === undefined) {
473
+ err('usage: reticle share <runId>');
474
+ return 2;
475
+ }
476
+ const { url, apiKey } = await repoCloud();
477
+ emit(await api('POST', `${url}/v1/runs/${encodeURIComponent(runId)}/share`, apiKey));
478
+ return 0;
479
+ };
480
+ /** Dispatch a cloud subcommand. Returns the process exit code. */
481
+ export const runCloudCommand = async (argv) => {
482
+ const [cmd, ...rest] = argv;
483
+ try {
484
+ switch (cmd) {
485
+ case 'login':
486
+ return await cmdLogin(rest);
487
+ case 'logout':
488
+ return await cmdLogout();
489
+ case 'whoami':
490
+ return await cmdWhoami();
491
+ case 'project':
492
+ return await cmdProject(rest);
493
+ case 'link':
494
+ return await cmdLink(rest);
495
+ case 'config':
496
+ return await cmdConfig(rest);
497
+ case 'push':
498
+ return await cmdPush();
499
+ case 'runs':
500
+ return await cmdRuns();
501
+ case 'regression':
502
+ return await cmdRegression();
503
+ case 'share':
504
+ return await cmdShare(rest);
505
+ default:
506
+ err(`unknown cloud command '${cmd ?? ''}'`);
507
+ return 2;
508
+ }
509
+ }
510
+ catch (e) {
511
+ err(e instanceof Error ? e.message : String(e));
512
+ return 1;
513
+ }
514
+ };
@@ -5,4 +5,3 @@ import type { ToolDef } from '../tools/tools.js';
5
5
  * it drives the app — so it's an explicit, bounded tool, never part of a passive read.
6
6
  */
7
7
  export declare const CRAWL_TOOLS: ToolDef[];
8
- //# sourceMappingURL=crawl-tools.d.ts.map
@@ -11,7 +11,7 @@ const nodeSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
11
11
  export const CRAWL_TOOLS = [
12
12
  {
13
13
  name: ReticleTool.CRAWL,
14
- description: 'Autonomously click every reachable interactive control (bounded by maxSteps, default 25) and report anomalies WITHOUT a script: console errors, failed requests (status ≥ 400), and DEAD controls (dispatched but the app did nothing). DESTRUCTIVE — it really clicks (may navigate/mutate state); use reticle_explore first for a non-destructive list. Returns { interactiveFound, stepsRun, anomalies[{kind,ref,desc,detail}], counts, visited, truncated }.',
14
+ description: 'Autonomously click every reachable interactive control (bounded by maxSteps, default 25) and report anomalies WITHOUT a script. Two classes: single-channel faults (console errors, failed requests ≥400, DEAD controls that dispatched but did nothing) and CONTRADICTIONS — two channels disagreeing about the same click, e.g. the UI advanced while its write failed, a success signal fired over a failed request, a write succeeded and nothing changed, the same write fired twice, or the UI moved on over an in-flight request. Contradictions are the false greens a human cannot see, because a human watches one channel (the screen) and it looks correct. DESTRUCTIVE — it really clicks (may navigate/mutate state); use reticle_explore first for a non-destructive list. Returns { interactiveFound, stepsRun, anomalies[{kind,ref,desc,detail}], counts, visited, truncated }.',
15
15
  inputSchema: {
16
16
  maxSteps: z.number().optional().describe('Maximum number of controls to click. Default: 25.'),
17
17
  settleMs: z
@@ -70,4 +70,3 @@ export const CRAWL_TOOLS = [
70
70
  },
71
71
  },
72
72
  ];
73
- //# sourceMappingURL=crawl-tools.js.map
@@ -1,4 +1,4 @@
1
- import { CrawlAnomalyKind, type CommandResult, type ReticleEvent } from '@reticlehq/core';
1
+ import { CrawlAnomalyKind, ContradictionKind, type CommandResult, type ReticleEvent } from '@reticlehq/core';
2
2
  /** The slice of Session the crawler needs — so tests inject a fake without a live browser. */
3
3
  export interface CrawlSession {
4
4
  command(name: string, args?: Record<string, unknown>): Promise<CommandResult>;
@@ -16,7 +16,13 @@ export interface CrawlSession {
16
16
  }
17
17
  type CrawlSleep = (ms: number) => Promise<void>;
18
18
  export interface CrawlAnomaly {
19
- kind: CrawlAnomalyKind;
19
+ /**
20
+ * A single-channel fault (something bad in one stream) or a CONTRADICTION (two channels
21
+ * disagreeing about the same click). The second kind is why an autonomous crawl is worth more
22
+ * than a human clicking the same buttons: a person sees only the screen, so a UI that advanced
23
+ * while its write failed looks like success to them and always will.
24
+ */
25
+ kind: CrawlAnomalyKind | ContradictionKind;
20
26
  /** The control that triggered it. */
21
27
  ref: string;
22
28
  desc: string;
@@ -41,6 +47,7 @@ export interface CrawlReport {
41
47
  consoleErrors: number;
42
48
  failedRequests: number;
43
49
  deadControls: number;
50
+ contradictions: number;
44
51
  };
45
52
  /** Descriptions of the controls actually clicked. */
46
53
  visited: string[];
@@ -62,6 +69,13 @@ export interface CrawlOptions {
62
69
  * orchestration over a CrawlSession: no browser/Node imports, fully unit-testable with a fake.
63
70
  * Single-pass by design (no re-discovery) so it always terminates and never explodes on navigation.
64
71
  */
72
+ /**
73
+ * Controls whose correct behaviour IS to do nothing when clicked.
74
+ *
75
+ * Read off the same descriptor the crawler already has, so no extra round trip: `[disabled]` is inert
76
+ * by definition, an already `[checked]` radio/checkbox is idempotent, and clicking a text field
77
+ * focuses it rather than changing anything.
78
+ */
79
+ export declare function legitimatelyInert(desc: string): boolean;
65
80
  export declare function crawl(session: CrawlSession, opts: CrawlOptions, sleep: CrawlSleep): Promise<CrawlReport>;
66
81
  export {};
67
- //# sourceMappingURL=crawl.d.ts.map
@@ -1,6 +1,7 @@
1
- import { ActionType, CRAWL_DEFAULTS, CrawlAnomalyKind, DANGEROUS_ACTION_CONFIRM_ARG, EventType, ReticleCommand, } from '@reticlehq/core';
1
+ import { ActionType, CRAWL_DEFAULTS, CrawlAnomalyKind, ContradictionKind, DANGEROUS_ACTION_CONFIRM_ARG, EventType, ReticleCommand, } from '@reticlehq/core';
2
2
  import { parseInteractive, asRecord, asNumber, asString, sourceOf, } from '../tools/tools-helpers.js';
3
3
  import { ReticleTool } from '../tools/tool-names.js';
4
+ import { findContradictions } from '../events/contradictions.js';
4
5
  /** Said out loud when the page was larger than one snapshot, so a clean sweep cannot mean "all clear". */
5
6
  export const CAPPED_SNAPSHOT_NOTE = 'the page exceeded one snapshot, so controls past the cap were never seen — interactiveFound is a floor, not a total; re-run with a narrower `scope` to cover the rest';
6
7
  /** Any buffer event that proves the app reacted to a click (vs a dead/no-op control). */
@@ -33,6 +34,20 @@ function failedRequests(events, floor) {
33
34
  * orchestration over a CrawlSession: no browser/Node imports, fully unit-testable with a fake.
34
35
  * Single-pass by design (no re-discovery) so it always terminates and never explodes on navigation.
35
36
  */
37
+ /**
38
+ * Controls whose correct behaviour IS to do nothing when clicked.
39
+ *
40
+ * Read off the same descriptor the crawler already has, so no extra round trip: `[disabled]` is inert
41
+ * by definition, an already `[checked]` radio/checkbox is idempotent, and clicking a text field
42
+ * focuses it rather than changing anything.
43
+ */
44
+ export function legitimatelyInert(desc) {
45
+ if (desc.includes('[disabled]'))
46
+ return true;
47
+ if (desc.includes('[checked]'))
48
+ return true;
49
+ return /\b(textbox|searchbox|combobox|spinbutton)\b/.test(desc);
50
+ }
36
51
  export async function crawl(session, opts, sleep) {
37
52
  const maxSteps = opts.maxSteps ?? CRAWL_DEFAULTS.MAX_STEPS;
38
53
  const settleMs = opts.settleMs ?? CRAWL_DEFAULTS.SETTLE_MS;
@@ -50,7 +65,7 @@ export async function crawl(session, opts, sleep) {
50
65
  const coverageCapped = snapshot.truncated === true;
51
66
  const anomalies = [];
52
67
  const visited = [];
53
- const counts = { consoleErrors: 0, failedRequests: 0, deadControls: 0 };
68
+ const counts = { consoleErrors: 0, failedRequests: 0, deadControls: 0, contradictions: 0 };
54
69
  const seen = new Set();
55
70
  let stepsRun = 0;
56
71
  for (const item of items) {
@@ -107,9 +122,34 @@ export async function crawl(session, opts, sleep) {
107
122
  ...source,
108
123
  });
109
124
  }
125
+ // CONTRADICTIONS: the channels disagree about what this click did. Reported per control, so a
126
+ // crawl of an unknown app surfaces its false greens without anyone knowing where to look.
127
+ for (const c of findContradictions(events)) {
128
+ counts.contradictions += 1;
129
+ anomalies.push({
130
+ kind: c.kind,
131
+ ref: item.ref,
132
+ desc: item.desc,
133
+ detail: `${c.claim}, but ${c.counter} — ${c.detail}`,
134
+ ...source,
135
+ });
136
+ }
110
137
  // DEAD: the click dispatched but the app produced no activity and no error to explain it.
138
+ //
139
+ // Unless the control is SUPPOSED to be inert. Measured on a shipments console: every one of the
140
+ // crawler's three anomalies was a control behaving correctly — a `[disabled]` button, an already
141
+ // `[checked]` radio, and a text input (a click focuses it; mutating would be the surprise). An
142
+ // anomaly list that is 100% false on a real app is worse than no anomaly list, because the agent
143
+ // spends its budget disproving it and learns to skip the field.
144
+ //
145
+ // Deliberately NOT fixed by counting focus as activity: focus moving is not the app reacting, and
146
+ // treating it as such would make a genuinely dead button that takes focus look alive — trading
147
+ // noise for the false negative this check exists to catch.
111
148
  const dispatched = asRecord(act.result)['dispatched'] !== false && act.ok;
112
- if (dispatched && errs.length === 0 && !events.some(isActivity)) {
149
+ if (dispatched &&
150
+ errs.length === 0 &&
151
+ !events.some(isActivity) &&
152
+ !legitimatelyInert(item.desc)) {
113
153
  counts.deadControls += 1;
114
154
  anomalies.push({
115
155
  kind: CrawlAnomalyKind.DEAD_CONTROL,
@@ -133,4 +173,3 @@ export async function crawl(session, opts, sleep) {
133
173
  ...(coverageCapped ? { coverageNote: CAPPED_SNAPSHOT_NOTE } : {}),
134
174
  };
135
175
  }
136
- //# sourceMappingURL=crawl.js.map
@@ -12,6 +12,11 @@ export interface ProcessLike {
12
12
  on(event: string, listener: (arg: unknown) => void): unknown;
13
13
  }
14
14
  type LogFn = (event: string, data: Record<string, unknown>) => void;
15
+ /** The two ways a failure reaches the top of the process. Named so the analytics can tell them apart. */
16
+ export declare const CrashKind: {
17
+ readonly UNHANDLED_REJECTION: "unhandled_rejection";
18
+ readonly UNCAUGHT_EXCEPTION: "uncaught_exception";
19
+ };
20
+ export type CrashKind = (typeof CrashKind)[keyof typeof CrashKind];
15
21
  export declare function installDaemonResilience(proc: ProcessLike, log: LogFn, onFatal: () => void): void;
16
22
  export {};
17
- //# sourceMappingURL=daemon-resilience.d.ts.map