@reticlehq/server 3.8.2 → 3.10.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 (477) hide show
  1. package/LICENSE +201 -104
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/SKILL.md +13 -12
  5. package/bin/launch.js +13 -0
  6. package/bin/package.json +3 -0
  7. package/bin/reticle.js +66 -8
  8. package/dist/chromium-launch-options.d.ts +25 -0
  9. package/dist/chromium-launch-options.js +21 -1
  10. package/dist/command/cli/adhoc-suite.js +2 -0
  11. package/dist/command/cli/adhoc-verdict.d.ts +2 -43
  12. package/dist/command/cli/adhoc-verdict.js +50 -160
  13. package/dist/command/cli/answers/gate-exit.d.ts +6 -2
  14. package/dist/command/cli/answers/gate-exit.js +12 -2
  15. package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
  16. package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
  17. package/dist/command/cli/ci-hint.d.ts +44 -0
  18. package/dist/command/cli/ci-hint.js +72 -0
  19. package/dist/command/cli/cli-doctor.d.ts +6 -1
  20. package/dist/command/cli/cli-doctor.js +46 -5
  21. package/dist/command/cli/cli-flow-commands.d.ts +7 -1
  22. package/dist/command/cli/cli-flow-commands.js +39 -24
  23. package/dist/command/cli/cli-kill.d.ts +21 -0
  24. package/dist/command/cli/cli-kill.js +47 -4
  25. package/dist/command/cli/cli-parse-compare.d.ts +22 -0
  26. package/dist/command/cli/cli-parse-compare.js +75 -0
  27. package/dist/command/cli/cli-parse-grade.d.ts +36 -0
  28. package/dist/command/cli/cli-parse-grade.js +75 -0
  29. package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
  30. package/dist/command/cli/cli-parse-grammar.js +18 -20
  31. package/dist/command/cli/cli-parse-verify.d.ts +10 -0
  32. package/dist/command/cli/cli-parse-verify.js +63 -14
  33. package/dist/command/cli/cli-parse.d.ts +22 -17
  34. package/dist/command/cli/cli-parse.js +54 -32
  35. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  36. package/dist/command/cli/cli-update-commands.js +29 -20
  37. package/dist/command/cli/cli-usage.js +61 -31
  38. package/dist/command/cli/cli-verify.d.ts +17 -3
  39. package/dist/command/cli/cli-verify.js +59 -21
  40. package/dist/command/cli/cloud-cli.js +2 -119
  41. package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
  42. package/dist/command/cli/daemon-link/daemon-client.js +205 -0
  43. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
  44. package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
  45. package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
  46. package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
  47. package/dist/command/cli/doctor/doctor-fix.js +89 -0
  48. package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
  49. package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
  50. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  51. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  52. package/dist/command/cli/doctor-repairs.d.ts +64 -0
  53. package/dist/command/cli/doctor-repairs.js +214 -0
  54. package/dist/command/cli/drive/drive-command.js +3 -7
  55. package/dist/command/cli/ensure-daemon.d.ts +26 -0
  56. package/dist/command/cli/ensure-daemon.js +57 -0
  57. package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
  58. package/dist/command/cli/finished-run/grade-command.js +180 -0
  59. package/dist/command/cli/first-use-checks.d.ts +41 -0
  60. package/dist/command/cli/first-use-checks.js +127 -0
  61. package/dist/command/cli/first-verdict-node.d.ts +3 -0
  62. package/dist/command/cli/first-verdict-node.js +189 -0
  63. package/dist/command/cli/first-verdict.d.ts +126 -0
  64. package/dist/command/cli/first-verdict.js +267 -0
  65. package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
  66. package/dist/command/cli/launch/sdk-version-match.js +3 -2
  67. package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
  68. package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
  69. package/dist/command/cli/mcp-command.js +13 -4
  70. package/dist/command/cli/ports/port-holder.d.ts +11 -0
  71. package/dist/command/cli/ports/port-holder.js +36 -4
  72. package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
  73. package/dist/command/cli/setup-mcp-cli.js +98 -23
  74. package/dist/command/cli/status/status-lines.d.ts +2 -0
  75. package/dist/command/cli/status/status-lines.js +72 -17
  76. package/dist/command/cli/status-fields.d.ts +5 -1
  77. package/dist/command/cli/status-fields.js +24 -6
  78. package/dist/command/cli/try-command.d.ts +7 -0
  79. package/dist/command/cli/try-command.js +11 -3
  80. package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
  81. package/dist/command/cli/two-builds/compare-command.js +314 -0
  82. package/dist/command/cli/verify-against.d.ts +61 -0
  83. package/dist/command/cli/verify-against.js +187 -0
  84. package/dist/command/cli/verify-no-session.d.ts +2 -0
  85. package/dist/command/cli/verify-no-session.js +13 -0
  86. package/dist/command/cli/verify-results.d.ts +35 -2
  87. package/dist/command/cli/verify-results.js +76 -10
  88. package/dist/command/cli.js +112 -70
  89. package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
  90. package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
  91. package/dist/command/daemon/daemon-argv.d.ts +9 -0
  92. package/dist/command/daemon/daemon-argv.js +11 -0
  93. package/dist/command/daemon/daemon-resolve.d.ts +8 -1
  94. package/dist/command/daemon/daemon-resolve.js +27 -1
  95. package/dist/command/daemon/daemon.d.ts +22 -4
  96. package/dist/command/daemon/daemon.js +52 -10
  97. package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
  98. package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
  99. package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
  100. package/dist/command/daemon/lifetime/death-cause.js +149 -0
  101. package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
  102. package/dist/command/daemon/lifetime/heartbeat.js +11 -15
  103. package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
  104. package/dist/command/daemon/lifetime/startup-failure.js +62 -0
  105. package/dist/command/daemon/port-state.d.ts +14 -0
  106. package/dist/command/daemon/port-state.js +31 -0
  107. package/dist/command/setup/agent-configs.d.ts +2 -0
  108. package/dist/command/setup/agent-configs.js +42 -15
  109. package/dist/command/setup/agent-next-steps.d.ts +77 -0
  110. package/dist/command/setup/agent-next-steps.js +284 -0
  111. package/dist/command/setup/agent-writer.js +11 -6
  112. package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
  113. package/dist/command/setup/bringup/dev-server-files.js +17 -0
  114. package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
  115. package/dist/command/setup/bringup/static-page-server.js +43 -9
  116. package/dist/command/setup/init/init-host.js +2 -0
  117. package/dist/command/setup/init/init-runtime.d.ts +6 -1
  118. package/dist/command/setup/init/init-runtime.js +63 -21
  119. package/dist/command/setup/mcp-launcher.d.ts +3 -0
  120. package/dist/command/setup/mcp-launcher.js +11 -0
  121. package/dist/command/setup/node-effects.d.ts +3 -2
  122. package/dist/command/setup/node-effects.js +9 -3
  123. package/dist/command/setup/remaining-steps.d.ts +8 -0
  124. package/dist/command/setup/remaining-steps.js +10 -0
  125. package/dist/command/setup/run-setup.d.ts +2 -0
  126. package/dist/command/setup/run-setup.js +9 -1
  127. package/dist/command/setup/setup-command.js +36 -15
  128. package/dist/command/setup/setup-mcp.d.ts +8 -0
  129. package/dist/command/setup/setup-mcp.js +47 -20
  130. package/dist/command/setup/start-dev-server.d.ts +8 -0
  131. package/dist/command/setup/start-dev-server.js +43 -0
  132. package/dist/command/update/updater.js +6 -0
  133. package/dist/command/version/identity/server-version.d.ts +2 -0
  134. package/dist/command/version/identity/server-version.js +2 -0
  135. package/dist/command/version/version-skew.d.ts +7 -0
  136. package/dist/command/version/version-skew.js +14 -3
  137. package/dist/features/compare/action-plan.d.ts +260 -0
  138. package/dist/features/compare/action-plan.js +543 -0
  139. package/dist/features/compare/behaviour-compare.d.ts +24 -0
  140. package/dist/features/compare/behaviour-compare.js +85 -0
  141. package/dist/features/compare/behaviour-diff.d.ts +97 -0
  142. package/dist/features/compare/behaviour-diff.js +202 -0
  143. package/dist/features/compare/behaviour-report.d.ts +40 -0
  144. package/dist/features/compare/behaviour-report.js +128 -0
  145. package/dist/features/compare/build-readings.d.ts +106 -0
  146. package/dist/features/compare/build-readings.js +250 -0
  147. package/dist/features/compare/compare-diff.d.ts +62 -0
  148. package/dist/features/compare/compare-diff.js +177 -0
  149. package/dist/features/compare/compare-report-html.d.ts +6 -0
  150. package/dist/features/compare/compare-report-html.js +102 -0
  151. package/dist/features/compare/compare-report.d.ts +15 -0
  152. package/dist/features/compare/compare-report.js +73 -0
  153. package/dist/features/compare/compare-run.d.ts +60 -0
  154. package/dist/features/compare/compare-run.js +123 -0
  155. package/dist/features/compare/outside/effect-lines.d.ts +26 -0
  156. package/dist/features/compare/outside/effect-lines.js +103 -0
  157. package/dist/features/compare/outside/state-sources.d.ts +76 -0
  158. package/dist/features/compare/outside/state-sources.js +164 -0
  159. package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
  160. package/dist/features/compare/outside/value-dictionary.js +227 -0
  161. package/dist/features/compare/visible-content.d.ts +20 -0
  162. package/dist/features/compare/visible-content.js +125 -0
  163. package/dist/features/crawl/crawl-empty.js +2 -1
  164. package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
  165. package/dist/features/crawl/crawl-exhaustive.js +138 -0
  166. package/dist/features/crawl/crawl-tools.d.ts +9 -2
  167. package/dist/features/crawl/crawl-tools.js +28 -12
  168. package/dist/features/crawl/crawl.d.ts +8 -9
  169. package/dist/features/crawl/crawl.js +61 -65
  170. package/dist/features/exhaust/app-coverage.d.ts +5 -1
  171. package/dist/features/exhaust/app-coverage.js +3 -1
  172. package/dist/features/exhaust/code-coverage.js +8 -4
  173. package/dist/features/exhaust/edge-cases.d.ts +133 -0
  174. package/dist/features/exhaust/edge-cases.js +310 -0
  175. package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
  176. package/dist/features/exhaust/edges/edge-drive.js +364 -0
  177. package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
  178. package/dist/features/exhaust/edges/edge-run.js +169 -0
  179. package/dist/features/exhaust/explorer.d.ts +87 -14
  180. package/dist/features/exhaust/explorer.js +159 -25
  181. package/dist/features/exhaust/failure-branches.d.ts +5 -0
  182. package/dist/features/exhaust/failure-branches.js +29 -11
  183. package/dist/features/exhaust/invariants.d.ts +112 -0
  184. package/dist/features/exhaust/invariants.js +188 -0
  185. package/dist/features/exhaust/ledger.d.ts +68 -0
  186. package/dist/features/exhaust/ledger.js +121 -13
  187. package/dist/features/exhaust/session-fold.d.ts +10 -0
  188. package/dist/features/exhaust/session-fold.js +46 -3
  189. package/dist/features/exhaust/session-port.d.ts +3 -1
  190. package/dist/features/exhaust/session-port.js +97 -28
  191. package/dist/features/grade/grade-answer.d.ts +99 -0
  192. package/dist/features/grade/grade-answer.js +112 -0
  193. package/dist/features/grade/grade-noise.d.ts +27 -0
  194. package/dist/features/grade/grade-noise.js +55 -0
  195. package/dist/features/grade/grade-renumber.d.ts +12 -0
  196. package/dist/features/grade/grade-renumber.js +86 -0
  197. package/dist/features/grade/grade-state.d.ts +50 -0
  198. package/dist/features/grade/grade-state.js +93 -0
  199. package/dist/features/grade/grade-suggest.d.ts +33 -0
  200. package/dist/features/grade/grade-suggest.js +98 -0
  201. package/dist/features/license/license.d.ts +11 -71
  202. package/dist/features/license/license.js +43 -136
  203. package/dist/features/visual/desktop-capture.d.ts +33 -0
  204. package/dist/features/visual/desktop-capture.js +94 -0
  205. package/dist/features/visual/step-shots.js +139 -35
  206. package/dist/features/visual/visual-tools.d.ts +0 -18
  207. package/dist/features/visual/visual-tools.js +67 -99
  208. package/dist/import-graph.js +5 -6
  209. package/dist/index.d.ts +3 -1
  210. package/dist/index.js +19 -7
  211. package/dist/judgement/capsule/causal-summary.js +9 -2
  212. package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
  213. package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
  214. package/dist/judgement/runs/reticle-runner.js +16 -2
  215. package/dist/judgement/runs/run-ledger.d.ts +7 -5
  216. package/dist/judgement/runs/run-ledger.js +98 -69
  217. package/dist/judgement/runs/runner-port.d.ts +2 -0
  218. package/dist/judgement/runs/runner-port.js +23 -5
  219. package/dist/judgement/runs/verification-sync.d.ts +6 -3
  220. package/dist/judgement/runs/verification-sync.js +21 -10
  221. package/dist/language/flows/affected-tools.d.ts +1 -1
  222. package/dist/language/flows/affected-tools.js +49 -30
  223. package/dist/language/flows/change/git-changed.d.ts +2 -1
  224. package/dist/language/flows/change/git-changed.js +19 -2
  225. package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
  226. package/dist/language/flows/fields/flow-secret-field.js +77 -21
  227. package/dist/language/flows/flow-anchor.d.ts +60 -2
  228. package/dist/language/flows/flow-anchor.js +125 -20
  229. package/dist/language/flows/flow-classify.d.ts +20 -0
  230. package/dist/language/flows/flow-classify.js +90 -12
  231. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  232. package/dist/language/flows/flow-cross-step.js +25 -1
  233. package/dist/language/flows/flow-journey.d.ts +38 -4
  234. package/dist/language/flows/flow-journey.js +138 -8
  235. package/dist/language/flows/flow-replay-run.d.ts +0 -16
  236. package/dist/language/flows/flow-replay-run.js +76 -14
  237. package/dist/language/flows/flow-replay-types.d.ts +4 -2
  238. package/dist/language/flows/flow-replay.d.ts +19 -1
  239. package/dist/language/flows/flow-replay.js +169 -52
  240. package/dist/language/flows/flow-replayable.js +7 -1
  241. package/dist/language/flows/flow-start-path.d.ts +34 -5
  242. package/dist/language/flows/flow-start-path.js +202 -15
  243. package/dist/language/flows/flow-step-runners.d.ts +14 -13
  244. package/dist/language/flows/flow-step-runners.js +184 -109
  245. package/dist/language/flows/flow-store-for-session.d.ts +26 -25
  246. package/dist/language/flows/flow-store-for-session.js +51 -5
  247. package/dist/language/flows/flow-tools.js +46 -33
  248. package/dist/language/flows/flows.js +176 -76
  249. package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
  250. package/dist/language/flows/recording/tape/recordings.js +112 -49
  251. package/dist/language/flows/replay.d.ts +36 -12
  252. package/dist/language/flows/replay.js +193 -50
  253. package/dist/language/flows/steps/page-steps.d.ts +68 -0
  254. package/dist/language/flows/steps/page-steps.js +198 -0
  255. package/dist/language/flows/suite/sequential-run.d.ts +68 -0
  256. package/dist/language/flows/suite/sequential-run.js +96 -0
  257. package/dist/language/flows/verify-change-tools.js +26 -15
  258. package/dist/launch-chromium.d.ts +1 -0
  259. package/dist/launch-chromium.js +49 -12
  260. package/dist/memory/cloud/background-sync.d.ts +13 -0
  261. package/dist/memory/cloud/background-sync.js +24 -3
  262. package/dist/memory/cloud/sync-daemon.js +26 -27
  263. package/dist/memory/cloud/sync-screenshots.js +6 -1
  264. package/dist/memory/journal/attach-journal.js +2 -1
  265. package/dist/memory/journal/drive-flow.d.ts +7 -0
  266. package/dist/memory/journal/drive-flow.js +44 -13
  267. package/dist/memory/journal/journal-recorder.d.ts +4 -2
  268. package/dist/memory/journal/session-journal.d.ts +7 -0
  269. package/dist/memory/journal/session-journal.js +58 -10
  270. package/dist/memory/project/root-claims.d.ts +9 -0
  271. package/dist/memory/project/root-claims.js +9 -4
  272. package/dist/portal/bridge/bridge.d.ts +13 -4
  273. package/dist/portal/bridge/bridge.js +10 -9
  274. package/dist/portal/input/download-capture.d.ts +7 -0
  275. package/dist/portal/input/download-capture.js +92 -0
  276. package/dist/portal/input/network-detail.d.ts +6 -0
  277. package/dist/portal/input/network-detail.js +12 -1
  278. package/dist/portal/input/network-mock-tools.js +49 -13
  279. package/dist/portal/input/network-mock.d.ts +8 -0
  280. package/dist/portal/input/network-mock.js +30 -10
  281. package/dist/portal/input/page-capture.d.ts +24 -0
  282. package/dist/portal/input/page-capture.js +33 -0
  283. package/dist/portal/input/real-input.d.ts +35 -18
  284. package/dist/portal/input/real-input.js +99 -33
  285. package/dist/portal/input/viewport-tools.d.ts +8 -0
  286. package/dist/portal/input/viewport-tools.js +81 -21
  287. package/dist/portal/pool/browser-pool.d.ts +16 -30
  288. package/dist/portal/pool/browser-pool.js +64 -52
  289. package/dist/portal/pool/context-permissions.d.ts +34 -17
  290. package/dist/portal/pool/context-permissions.js +94 -1
  291. package/dist/portal/pool/csp-widen.d.ts +62 -0
  292. package/dist/portal/pool/csp-widen.js +132 -0
  293. package/dist/portal/pool/determinism.d.ts +52 -0
  294. package/dist/portal/pool/determinism.js +259 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +34 -1
  296. package/dist/portal/pool/lease-emulation.js +18 -0
  297. package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
  298. package/dist/portal/pool/lease-marker-stamp.js +15 -1
  299. package/dist/portal/pool/lease-page-error.d.ts +56 -0
  300. package/dist/portal/pool/lease-page-error.js +160 -0
  301. package/dist/portal/pool/page-error-journal.d.ts +63 -0
  302. package/dist/portal/pool/page-error-journal.js +208 -0
  303. package/dist/portal/pool/playwright-launcher.js +71 -15
  304. package/dist/portal/pool/pool-contract.d.ts +49 -1
  305. package/dist/portal/pool/pool-lease.d.ts +70 -2
  306. package/dist/portal/pool/pool-lease.js +23 -0
  307. package/dist/portal/pool/zero-install.d.ts +8 -0
  308. package/dist/portal/pool/zero-install.js +91 -1
  309. package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
  310. package/dist/portal/session/dev-server/dev-command.js +110 -16
  311. package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
  312. package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
  313. package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
  314. package/dist/portal/session/dev-server/project-ports.js +62 -0
  315. package/dist/portal/session/facts/departed-network.d.ts +66 -0
  316. package/dist/portal/session/facts/departed-network.js +142 -0
  317. package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
  318. package/dist/portal/session/no-session-diagnosis.js +76 -27
  319. package/dist/portal/session/no-session-next-action.d.ts +14 -0
  320. package/dist/portal/session/no-session-next-action.js +56 -7
  321. package/dist/portal/session/no-session-watch.d.ts +6 -0
  322. package/dist/portal/session/no-session-watch.js +41 -4
  323. package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
  324. package/dist/portal/session/page-commands/undeclared-command.js +16 -7
  325. package/dist/portal/session/recorded-gaps.d.ts +1 -1
  326. package/dist/portal/session/recorded-gaps.js +5 -2
  327. package/dist/portal/session/serving-directory.d.ts +10 -0
  328. package/dist/portal/session/serving-directory.js +39 -8
  329. package/dist/portal/session/session-manager.d.ts +10 -0
  330. package/dist/portal/session/session-manager.js +211 -81
  331. package/dist/portal/session/session.js +4 -3
  332. package/dist/portal/session/zero-install-first-call.d.ts +20 -1
  333. package/dist/portal/session/zero-install-first-call.js +34 -2
  334. package/dist/start-wiring.d.ts +30 -2
  335. package/dist/start-wiring.js +74 -9
  336. package/dist/surface/mcp/mcp-proxy.js +10 -2
  337. package/dist/surface/mcp/mcp.js +8 -5
  338. package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
  339. package/dist/surface/mcp/peer/agents-connected.js +58 -0
  340. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
  341. package/dist/surface/mcp/shared-params.d.ts +2 -0
  342. package/dist/surface/mcp/shared-params.js +31 -0
  343. package/dist/surface/tools/act/act-observation.d.ts +40 -2
  344. package/dist/surface/tools/act/act-observation.js +118 -12
  345. package/dist/surface/tools/act/act-preflight.js +38 -18
  346. package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
  347. package/dist/surface/tools/act/act-sequence-retry.js +61 -5
  348. package/dist/surface/tools/act/act-target.js +3 -1
  349. package/dist/surface/tools/act/after-match.d.ts +10 -0
  350. package/dist/surface/tools/act/after-match.js +40 -0
  351. package/dist/surface/tools/act/already-true.js +1 -1
  352. package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
  353. package/dist/surface/tools/act/navigation/reload-result.js +25 -2
  354. package/dist/surface/tools/act/resolve-target.d.ts +17 -1
  355. package/dist/surface/tools/act/resolve-target.js +59 -9
  356. package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
  357. package/dist/surface/tools/act/sequence-grade.js +45 -27
  358. package/dist/surface/tools/act/settle-in-flight.js +27 -15
  359. package/dist/surface/tools/act-command.d.ts +23 -0
  360. package/dist/surface/tools/act-command.js +50 -0
  361. package/dist/surface/tools/act-sequence-tool.js +81 -50
  362. package/dist/surface/tools/act-tools.d.ts +1 -13
  363. package/dist/surface/tools/act-tools.js +83 -95
  364. package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
  365. package/dist/surface/tools/agent/build-staleness.js +1 -1
  366. package/dist/surface/tools/assert/assert-verdict.js +18 -12
  367. package/dist/surface/tools/browser-tools.js +87 -13
  368. package/dist/surface/tools/compare-tools.d.ts +11 -0
  369. package/dist/surface/tools/compare-tools.js +94 -0
  370. package/dist/surface/tools/coverage-tools.js +1 -1
  371. package/dist/surface/tools/dynamic-tools.js +11 -3
  372. package/dist/surface/tools/empty-session-list.d.ts +2 -0
  373. package/dist/surface/tools/empty-session-list.js +4 -2
  374. package/dist/surface/tools/error-recovery.d.ts +12 -1
  375. package/dist/surface/tools/error-recovery.js +131 -40
  376. package/dist/surface/tools/explore-tools.js +1 -1
  377. package/dist/surface/tools/invoke-tool.js +29 -21
  378. package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
  379. package/dist/surface/tools/lease-coverage-tools.js +128 -0
  380. package/dist/surface/tools/lease-hint.d.ts +42 -1
  381. package/dist/surface/tools/lease-hint.js +52 -3
  382. package/dist/surface/tools/lease-readiness.d.ts +47 -0
  383. package/dist/surface/tools/lease-readiness.js +126 -0
  384. package/dist/surface/tools/lease-seed.d.ts +16 -1
  385. package/dist/surface/tools/lease-seed.js +37 -4
  386. package/dist/surface/tools/lease-tools.d.ts +3 -41
  387. package/dist/surface/tools/lease-tools.js +104 -124
  388. package/dist/surface/tools/lease-url-identity.d.ts +46 -0
  389. package/dist/surface/tools/lease-url-identity.js +97 -0
  390. package/dist/surface/tools/merge-tools.js +99 -2
  391. package/dist/surface/tools/merged-name-redirect.js +5 -1
  392. package/dist/surface/tools/observe-tools.js +15 -9
  393. package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
  394. package/dist/surface/tools/read/console-pre-attach.js +23 -0
  395. package/dist/surface/tools/read-tools.js +33 -30
  396. package/dist/surface/tools/real-input-attempt.d.ts +0 -8
  397. package/dist/surface/tools/real-input-attempt.js +143 -28
  398. package/dist/surface/tools/repeat-hint.d.ts +40 -0
  399. package/dist/surface/tools/repeat-hint.js +171 -0
  400. package/dist/surface/tools/run-report.d.ts +2 -2
  401. package/dist/surface/tools/run-report.js +27 -15
  402. package/dist/surface/tools/session-ports.d.ts +14 -0
  403. package/dist/surface/tools/session-ports.js +53 -0
  404. package/dist/surface/tools/tool-kit.d.ts +18 -0
  405. package/dist/surface/tools/tool-kit.js +9 -3
  406. package/dist/surface/tools/tool-surface.js +0 -1
  407. package/dist/surface/tools/tools.js +54 -18
  408. package/dist/surface/tools/type-spelling.d.ts +13 -0
  409. package/dist/surface/tools/type-spelling.js +36 -0
  410. package/dist/telemetry/agent-client.d.ts +6 -0
  411. package/dist/telemetry/agent-client.js +10 -0
  412. package/dist/telemetry/argument-shape.js +17 -7
  413. package/dist/telemetry/cli-telemetry.d.ts +10 -1
  414. package/dist/telemetry/cli-telemetry.js +15 -0
  415. package/dist/telemetry/init-telemetry.d.ts +2 -1
  416. package/dist/telemetry/init-telemetry.js +47 -2
  417. package/dist/telemetry/install-trace.js +23 -4
  418. package/dist/telemetry/onboarding-funnel.d.ts +19 -2
  419. package/dist/telemetry/onboarding-funnel.js +25 -3
  420. package/dist/telemetry/proxy-telemetry.d.ts +2 -1
  421. package/dist/telemetry/proxy-telemetry.js +2 -2
  422. package/dist/telemetry/session-metrics.d.ts +1 -1
  423. package/dist/telemetry/session-metrics.js +67 -27
  424. package/dist/telemetry/telemetry.d.ts +3 -1
  425. package/dist/telemetry/telemetry.js +60 -28
  426. package/dist/telemetry/tool-refused.d.ts +6 -3
  427. package/dist/telemetry/tool-refused.js +15 -3
  428. package/docs/actions.mdx +3 -3
  429. package/docs/agent-cheatsheet.md +1 -1
  430. package/docs/architecture.md +3 -6
  431. package/docs/capabilities.mdx +61 -1
  432. package/docs/cli/affected.mdx +9 -7
  433. package/docs/cli/cloud.mdx +3 -3
  434. package/docs/cli/compare.mdx +94 -0
  435. package/docs/cli/doctor.mdx +41 -2
  436. package/docs/cli/grade.mdx +97 -0
  437. package/docs/cli/help.mdx +4 -2
  438. package/docs/cli/license.mdx +13 -12
  439. package/docs/cli/restart.mdx +7 -5
  440. package/docs/cli/rollback.mdx +5 -5
  441. package/docs/cli/setup.mdx +13 -2
  442. package/docs/cli/status.mdx +4 -0
  443. package/docs/cli/stop.mdx +3 -3
  444. package/docs/cli/update.mdx +2 -2
  445. package/docs/cli/verify.mdx +23 -1
  446. package/docs/cli.mdx +34 -24
  447. package/docs/deploy-checks.md +25 -0
  448. package/docs/desktop.mdx +1 -1
  449. package/docs/enterprise.md +17 -22
  450. package/docs/environment.mdx +1 -0
  451. package/docs/first-drive.md +1 -1
  452. package/docs/flows.md +11 -1
  453. package/docs/frameworks.mdx +9 -9
  454. package/docs/getting-started.md +1 -1
  455. package/docs/install-manual.mdx +16 -1
  456. package/docs/license-activation.mdx +3 -3
  457. package/docs/packages/engine.mdx +1 -1
  458. package/docs/packages/server.mdx +1 -1
  459. package/docs/packages/tauri.mdx +1 -1
  460. package/docs/packages/test.mdx +1 -1
  461. package/docs/packages.mdx +1 -1
  462. package/docs/platform-integration.md +1 -1
  463. package/docs/predicates.mdx +1 -1
  464. package/docs/quickstart.mdx +68 -49
  465. package/docs/skill-setup.md +1 -1
  466. package/docs/skill.md +14 -13
  467. package/docs/telemetry.md +6 -4
  468. package/docs/tools/navigate.mdx +1 -1
  469. package/docs/tools/verify.mdx +4 -1
  470. package/docs/troubleshooting.mdx +1 -1
  471. package/docs/usage.md +17 -14
  472. package/package.json +18 -14
  473. package/LICENSE-ENTERPRISE +0 -37
  474. package/dist/features/ee/audit-log.d.ts +0 -14
  475. package/dist/features/ee/audit-log.js +0 -11
  476. package/dist/features/exhaust/exhaust-run.d.ts +0 -33
  477. package/dist/features/exhaust/exhaust-run.js +0 -82
@@ -1,14 +1,21 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
- import { claudeAddCommand, McpClient, probeCli, terminalWidth, wrapForTerminal, } from '@reticlehq/init';
4
+ import { mcpLauncher } from '../setup/mcp-launcher.js';
5
+ import { claudePluginInstalled, probeCli, terminalWidth, wrapForTerminal } from '@reticlehq/init';
5
6
  import { tutorialShownSteps } from './tutorial.js';
6
7
  import { setupMcp, knownClientLabels } from '../setup/setup-mcp.js';
7
8
  import { reportInstallSteps } from '../setup/setup-install.js';
8
9
  import { registerOtherAgents } from '../setup/setup-command.js';
10
+ import { agentLines, agentRows, awaitedClients, claudeStateDir, connectionLines, installedAgentRows, waitForAgents, } from '../setup/agent-next-steps.js';
11
+ import { connectedAgentClients } from '../../surface/mcp/peer/agents-connected.js';
12
+ import { reticleStateHome } from '../daemon/daemon.js';
9
13
  /** How many coding agents on this machine have Reticle's tools after this run. */
10
- export function handleSetupMcp(reportStep, standalone = true) {
14
+ export function handleSetupMcp(reportStep, standalone = true,
15
+ /** Wait for the agents to connect. The caller decides: a terminal, and not CI. */
16
+ waitForConnect = false) {
11
17
  const io = {
18
+ launcher: mcpLauncher(),
12
19
  exists: (p) => existsSync(p),
13
20
  readFile: (p) => {
14
21
  try {
@@ -48,25 +55,12 @@ export function handleSetupMcp(reportStep, standalone = true) {
48
55
  : `No coding agent config found. Looked for: ${knownClientLabels().join(', ')}. Install one, then run \`reticle setup mcp\` again.`);
49
56
  return 0;
50
57
  }
51
- for (const id of result.registered)
52
- io.print(` ✓ ${id}`);
53
- for (const id of result.alreadyThere)
54
- io.print(` ✓ ${id} (already set up)`);
55
- for (const id of result.failed) {
56
- io.print(` ⚠ ${id}: Reticle registration failed; this agent may not have the tools.`);
57
- io.print(id === McpClient.CLAUDE_CODE
58
- ? ` Run this command to see the error and retry: ${claudeAddCommand().display}`
59
- : ' Check your agent config file permissions, then retry: reticle setup mcp');
58
+ const rows = agentRows(result, io.launcher);
59
+ for (const line of agentLines(rows)) {
60
+ io.print(line);
60
61
  }
61
- if (result.failed.length > 0)
62
+ if (result.failed.length > 0) {
62
63
  process.exitCode = 1;
63
- // Said, not skipped. These are the clients whose format we will not rewrite, and they used to be
64
- // counted as registered: the line below is the difference between a user who adds four lines to
65
- // one file and a user who believes they are set up and has no tools.
66
- for (const client of result.manual) {
67
- io.print(` ⚠ ${client.id}: add the reticle entry to ${client.configPath} by hand`);
68
- if (client.docs !== undefined)
69
- io.print(` see ${client.docs}`);
70
64
  }
71
65
  /*
72
66
  * The OTHER agents, which `init` already reaches and this did not.
@@ -90,10 +84,14 @@ export function handleSetupMcp(reportStep, standalone = true) {
90
84
  // closing's Next list, where it belongs with the other things to do, not between the stages.
91
85
  if (standalone) {
92
86
  io.print('');
93
- io.print('Restart your agent for it to pick up the new server.');
94
87
  io.print('Then: cd <your project> && reticle init');
88
+ if (waitForConnect) {
89
+ void reportConnections(rows, (line) => {
90
+ io.print(line);
91
+ });
92
+ }
95
93
  }
96
- return result.registered.length + result.alreadyThere.length;
94
+ return result.registered.length + result.alreadyThere.length + result.pluginActive.length;
97
95
  }
98
96
  /**
99
97
  * The one line the launchers read and strip: what they cannot know and the next steps depend on.
@@ -107,11 +105,18 @@ export const INSTALL_RESULT_PREFIX = 'RETICLE_INSTALL';
107
105
  const APP_MARKERS = ['package.json', 'index.html'];
108
106
  /** Whether the folder the installer ran in is an app: `init` runs here, or after a `cd`. */
109
107
  export const InstallAppHere = { HERE: 'here', NONE: 'none' };
108
+ /**
109
+ * `wait=yes`: this CLI has `reticle setup wait-agents`, and an agent has Reticle to wait for. A
110
+ * launcher runs the wait only when it reads this, so a launcher served from main never runs a
111
+ * subcommand that an older CLI does not have.
112
+ */
113
+ const INSTALL_WAIT = ' wait=yes';
110
114
  export function installResultLine(agents, cwd) {
111
115
  const app = APP_MARKERS.some((file) => existsSync(join(cwd, file)))
112
116
  ? InstallAppHere.HERE
113
117
  : InstallAppHere.NONE;
114
- return `${INSTALL_RESULT_PREFIX} agents=${String(agents)} app=${app}`;
118
+ const wait = 0 < agents ? INSTALL_WAIT : '';
119
+ return `${INSTALL_RESULT_PREFIX} agents=${String(agents)} app=${app}${wait}`;
115
120
  }
116
121
  /**
117
122
  * `reticle setup install` — the Node half of the one-line installer.
@@ -132,7 +137,77 @@ export function handleSetupInstall(opts, reportStep) {
132
137
  // No closing here: the installer prints the next step and the agent prompt itself, right after
133
138
  // this returns, so what this prints is progress and nothing else. Those two blocks are what the
134
139
  // ONBOARD steps below now stand for: what Reticle is for, shown before anything is asked of anyone.
135
- for (const step of tutorialShownSteps())
140
+ for (const step of tutorialShownSteps()) {
136
141
  reportStep(step);
142
+ }
137
143
  process.stdout.write(`${installResultLine(agents, process.cwd())}\n`);
138
144
  }
145
+ /** How long to wait for an agent to connect. Short: the person may not restart now. */
146
+ const CONNECT_WAIT_MS = 60_000;
147
+ const CONNECT_POLL_MS = 1000;
148
+ /** Wait only where a person watches: a terminal, and not CI. */
149
+ export function shouldWaitForAgents(isTty, isCi) {
150
+ return true === isTty && !isCi;
151
+ }
152
+ const nodeWait = {
153
+ read: () => connectedAgentClients(reticleStateHome()),
154
+ clock: {
155
+ now: () => Date.now(),
156
+ sleep: (ms) => new Promise((resolve) => {
157
+ setTimeout(resolve, ms);
158
+ }),
159
+ },
160
+ };
161
+ /** Wait (bounded) for the registered agents to connect, then say which did and what is missing. */
162
+ export async function reportConnections(rows, print, wait = nodeWait) {
163
+ const want = awaitedClients(rows);
164
+ if (0 === want.length) {
165
+ return;
166
+ }
167
+ print('');
168
+ print(`Waiting up to ${String(CONNECT_WAIT_MS / 1000)}s for your agents to connect. Press Ctrl+C to skip.`);
169
+ const seen = await waitForAgents(want, wait.read, wait.clock, CONNECT_WAIT_MS, CONNECT_POLL_MS);
170
+ for (const line of connectionLines(rows, seen)) {
171
+ print(line);
172
+ }
173
+ }
174
+ /**
175
+ * `reticle init`: the same block and wait as `reticle setup mcp`, after its restart notice. Print the
176
+ * "Your agents:" block now. Returns the wait, for the caller to run last: a no-op when
177
+ * nobody watches.
178
+ */
179
+ export function agentsBlock(rows, print, interactive, wait = nodeWait) {
180
+ for (const line of agentLines(rows)) {
181
+ print(line);
182
+ }
183
+ return interactive ? () => reportConnections(rows, print, wait) : () => Promise.resolve();
184
+ }
185
+ /** The agents on this machine and whether Reticle is in each config. Read only. */
186
+ export function readAgentRows(cwd) {
187
+ const io = {
188
+ exists: (p) => existsSync(p),
189
+ readFile: (p) => {
190
+ try {
191
+ return readFileSync(p, 'utf8');
192
+ }
193
+ catch {
194
+ return null;
195
+ }
196
+ },
197
+ homeDir: () => homedir(),
198
+ };
199
+ return installedAgentRows(io, cwd, claudePluginInstalled(io), claudeStateDir(), mcpLauncher());
200
+ }
201
+ /**
202
+ * `reticle setup wait-agents`: the installer's last step. The installer sends `setup install` output
203
+ * to a file, so that run cannot wait; this one runs with the terminal attached. Waits only where a
204
+ * person watches.
205
+ */
206
+ export async function handleSetupWaitAgents(interactive) {
207
+ if (!interactive) {
208
+ return;
209
+ }
210
+ await reportConnections(readAgentRows(process.cwd()), (line) => {
211
+ process.stdout.write(`${line}\n`);
212
+ });
213
+ }
@@ -19,10 +19,12 @@ export declare const StatusLabel: {
19
19
  readonly DAEMON: "daemon";
20
20
  readonly SESSIONS: "sessions";
21
21
  readonly AGENT_LINK: "agent link";
22
+ readonly AGENTS: "agents";
22
23
  readonly ACCOUNT: "account";
23
24
  readonly NEXT: "next";
24
25
  readonly SPLIT_BRAIN: "split brain";
25
26
  readonly UPDATE: "update";
27
+ readonly LICENSE: "license";
26
28
  };
27
29
  export type StatusLabel = (typeof StatusLabel)[keyof typeof StatusLabel];
28
30
  /** The block to print on stdout, one string per line, heading first. */
@@ -14,15 +14,18 @@
14
14
  * trusting it, and prints what it can recognise. A status that cannot be rendered must still be
15
15
  * logged, so nothing here may throw.
16
16
  */
17
+ import { mcpConnectionHint } from '../answers/mcp-connection-hint.js';
17
18
  /** Every row label this block can print. The one spelling; nothing writes a label inline. */
18
19
  export const StatusLabel = {
19
20
  DAEMON: 'daemon',
20
21
  SESSIONS: 'sessions',
21
22
  AGENT_LINK: 'agent link',
23
+ AGENTS: 'agents',
22
24
  ACCOUNT: 'account',
23
25
  NEXT: 'next',
24
26
  SPLIT_BRAIN: 'split brain',
25
27
  UPDATE: 'update',
28
+ LICENSE: 'license',
26
29
  };
27
30
  const LABELS = Object.values(StatusLabel);
28
31
  /** The heading, so a reader can tell which command produced the block. */
@@ -49,11 +52,13 @@ function num(fields, key) {
49
52
  }
50
53
  function sessionViews(fields) {
51
54
  const raw = fields['sessions'];
52
- if (!Array.isArray(raw))
55
+ if (!Array.isArray(raw)) {
53
56
  return [];
57
+ }
54
58
  return raw.flatMap((s) => {
55
- if ('object' !== typeof s || null === s)
59
+ if ('object' !== typeof s || null === s) {
56
60
  return [];
61
+ }
57
62
  const r = s;
58
63
  // Each of these explains something a reader would otherwise call a bug: a throttled or hidden
59
64
  // tab answers slowly, a stale one answers about a page that has moved on, and an unresponsive
@@ -77,17 +82,22 @@ export function statusLines(fields) {
77
82
  lines.push(row(StatusLabel.DAEMON, running
78
83
  ? `${OK} running${at}${pid === undefined ? '' : ` (pid ${String(pid)})`}`
79
84
  : `${NOT_OK} not running${at}`));
85
+ if (running && port !== undefined) {
86
+ lines.push(continuation(mcpConnectionHint(port)));
87
+ }
80
88
  // What was actually ON the port, when the pid file said nothing useful. "A stranger holds this"
81
89
  // and "nothing is here" were the same output once, and the true sentence was said by nothing a
82
90
  // person sees — so the word belongs in the prose, not only in the event.
83
91
  const presence = str(fields, 'presence');
84
- if (presence !== undefined)
92
+ if (presence !== undefined) {
85
93
  lines.push(continuation(`port presence: ${presence}`));
94
+ }
86
95
  // The refusal a FOREIGN port produces. It is the whole answer when it is present, so it rides the
87
96
  // daemon row rather than waiting for a `next` that is not built in that branch.
88
97
  const reason = str(fields, 'reason');
89
- if (reason !== undefined)
98
+ if (reason !== undefined) {
90
99
  lines.push(continuation(reason));
100
+ }
91
101
  if (running) {
92
102
  const count = num(fields, 'sessionCount') ?? 0;
93
103
  lines.push(row(StatusLabel.SESSIONS, count > 0
@@ -99,8 +109,9 @@ export function statusLines(fields) {
99
109
  // The daemon's own explanation for an empty session list, which outranks anything this command
100
110
  // could infer — it is the one holding the connection.
101
111
  const why = str(fields, 'why');
102
- if (why !== undefined)
112
+ if (why !== undefined) {
103
113
  lines.push(continuation(why));
114
+ }
104
115
  }
105
116
  // Who is signed in, and whether this repo is linked: what `whoami` used to answer. Only when the
106
117
  // caller looked, which is what the key being present means.
@@ -112,29 +123,33 @@ export function statusLines(fields) {
112
123
  // A key the platform refused at the last sync is the answer, not "not signed in": a member
113
124
  // removed from the workspace was told to connect while the key was set, and refused.
114
125
  const refused = str(fields, 'keyRefused');
115
- lines.push(row(StatusLabel.ACCOUNT, refused !== undefined
116
- ? `${NOT_OK} refused at the last sync: ${refused}`
117
- : who === undefined
118
- ? `${NOT_OK} not signed in`
119
- : `${OK} signed in as ${who}`));
126
+ lines.push(row(StatusLabel.ACCOUNT, accountText(refused, who)));
120
127
  const apps = appLinks(fields['workspaceApps']);
121
- if (project === undefined && 0 < apps.length)
122
- for (const { app, project: linked } of apps)
128
+ if (project === undefined && 0 < apps.length) {
129
+ for (const { app, project: linked } of apps) {
123
130
  lines.push(continuation(null === linked
124
131
  ? `${app} is not linked: run \`reticle connect\` in ${app}`
125
132
  : `${app} is linked to ${linked}`));
126
- else
133
+ }
134
+ }
135
+ else {
127
136
  lines.push(continuation(project === undefined
128
137
  ? 'this repo is not linked: run `reticle connect`'
129
138
  : `this repo is linked to ${project}${workspace === undefined ? '' : ` in workspace "${workspace}"`}`));
139
+ }
130
140
  }
131
141
  const client = str(fields, 'mcpClient');
132
142
  if (client !== undefined) {
133
143
  // The state in words (`mcpClientSaid`), never the record's own name for it.
134
144
  lines.push(row(StatusLabel.AGENT_LINK, str(fields, 'mcpClientSaid') ?? client));
135
145
  const action = str(fields, 'mcpClientAction');
136
- if (action !== undefined)
146
+ if (action !== undefined) {
137
147
  lines.push(continuation(action));
148
+ }
149
+ }
150
+ // Per agent: connected, or the step still missing. The installer prints the same lines.
151
+ for (const [i, line] of agentLinesOf(fields['agents']).entries()) {
152
+ lines.push(0 === i ? row(StatusLabel.AGENTS, line) : continuation(line));
138
153
  }
139
154
  for (const [label, key] of [
140
155
  [StatusLabel.NEXT, 'nextAction'],
@@ -142,18 +157,58 @@ export function statusLines(fields) {
142
157
  [StatusLabel.UPDATE, 'updateAvailable'],
143
158
  ]) {
144
159
  const value = str(fields, key);
145
- if (value !== undefined)
160
+ if (value !== undefined) {
146
161
  lines.push(row(label, value));
162
+ }
163
+ }
164
+ const license = licenseText(fields['license']);
165
+ if (license !== undefined) {
166
+ lines.push(row(StatusLabel.LICENSE, license));
147
167
  }
148
168
  return lines;
149
169
  }
170
+ /** License states with no key set. `--json` carries them; the block stays silent. */
171
+ const NO_KEY_LICENSE = new Set(['missing', 'eval']);
172
+ /** The license row, only when a key is set: active, expired or rejected. */
173
+ function licenseText(value) {
174
+ if ('object' !== typeof value || null === value) {
175
+ return undefined;
176
+ }
177
+ const { status, detail } = value;
178
+ if ('string' !== typeof status || NO_KEY_LICENSE.has(status)) {
179
+ return undefined;
180
+ }
181
+ return 'string' === typeof detail ? `${status}: ${detail}` : status;
182
+ }
183
+ /** The account row: refused at the last sync, not signed in, or signed in. */
184
+ function accountText(refused, who) {
185
+ if (refused !== undefined) {
186
+ return `${NOT_OK} refused at the last sync: ${refused}`;
187
+ }
188
+ return who === undefined ? `${NOT_OK} not signed in` : `${OK} signed in as ${who}`;
189
+ }
190
+ /** The `agents` field as lines, read defensively: it is the status object, not a typed value. */
191
+ function agentLinesOf(value) {
192
+ if (!Array.isArray(value)) {
193
+ return [];
194
+ }
195
+ return value.flatMap((raw) => {
196
+ if ('object' !== typeof raw || null === raw) {
197
+ return [];
198
+ }
199
+ const { said } = raw;
200
+ return 'string' === typeof said ? [said] : [];
201
+ });
202
+ }
150
203
  /** A workspace root's apps and their links, read defensively off the status fields. */
151
204
  function appLinks(value) {
152
- if (!Array.isArray(value))
205
+ if (!Array.isArray(value)) {
153
206
  return [];
207
+ }
154
208
  return value.flatMap((raw) => {
155
- if ('object' !== typeof raw || null === raw)
209
+ if ('object' !== typeof raw || null === raw) {
156
210
  return [];
211
+ }
157
212
  const { app, project } = raw;
158
213
  return 'string' === typeof app
159
214
  ? [{ app, project: 'string' === typeof project ? project : null }]
@@ -32,4 +32,8 @@ export declare function splitBrainFields(port: number, projectId: string | undef
32
32
  * transport lives on stdout), so `--json` must not go through it.
33
33
  */
34
34
  export declare function reportStatus(fields: Record<string, unknown>, json: boolean): void;
35
- export declare function handleStatus(port: number, json?: boolean): Promise<void>;
35
+ /**
36
+ * `license` is what `reticle license` printed. The caller reads it, so this directory does not
37
+ * reach into the license feature.
38
+ */
39
+ export declare function handleStatus(port: number, json?: boolean, license?: Record<string, unknown>): Promise<void>;
@@ -5,10 +5,14 @@ import { hasAnyAppConnectedBefore, hasProjectConnectedBefore, } from '../../memo
5
5
  import { devServersForProject } from '@reticlehq/core';
6
6
  import { readDevServers } from '../daemon/dev-servers.js';
7
7
  import { attachStatusFields } from '../../surface/mcp/attach-memory.js';
8
+ import { connectedAgentClients } from '../../surface/mcp/peer/agents-connected.js';
9
+ import { agentStatuses } from '../setup/agent-next-steps.js';
10
+ import { readAgentRows } from './setup-mcp-cli.js';
8
11
  import { probeDaemon } from '../../surface/mcp/mcp-proxy.js';
9
12
  import { availableUpdate } from '../update/update-nudge.js';
10
13
  import { fetchStatus } from '../daemon/binding/daemon-status-probe.js';
11
- import { PortPresence, probePresence, presenceIsUsable, describePresence, } from '../daemon/binding/port-presence.js';
14
+ import { PortPresence, probePresence, presenceIsUsable, } from '../daemon/binding/port-presence.js';
15
+ import { describePortState } from '../daemon/port-state.js';
12
16
  import { summarizeStatus } from './launch/cli-launch.js';
13
17
  import { readProjectId } from './ports/resolve/cli-port.js';
14
18
  import { accountStatusFields } from './cloud-cli.js';
@@ -35,7 +39,7 @@ export function withNextAction(facts) {
35
39
  */
36
40
  export function splitBrainFields(port, projectId) {
37
41
  const home = reticleStateHome();
38
- const elsewhere = splitBrainNote(port, daemonsServingProjectElsewhere(projectId, port, home, isAlive, (other) => hasProjectConnectedBefore(home, other, projectId)));
42
+ const elsewhere = splitBrainNote(port, daemonsServingProjectElsewhere(projectId, port, home, isAlive, (other) => hasProjectConnectedBefore(home, other, projectId)), { projectId, home });
39
43
  const note = elsewhere ?? wrongDaemonNote(port, resolveDaemonForProject(projectId, home, isAlive));
40
44
  return note === undefined ? {} : { splitBrain: note };
41
45
  }
@@ -56,7 +60,21 @@ export function reportStatus(fields, json) {
56
60
  }
57
61
  process.stdout.write(`${statusLines(fields).join('\n')}\n`);
58
62
  }
59
- export async function handleStatus(port, json = false) {
63
+ /**
64
+ * Each agent on this machine: connected, or the step still missing. The same lines the installer
65
+ * prints after its wait. Absent when no agent is on this machine.
66
+ */
67
+ function agentStatusFields() {
68
+ const rows = readAgentRows(process.cwd());
69
+ return 0 === rows.length
70
+ ? {}
71
+ : { agents: agentStatuses(rows, connectedAgentClients(reticleStateHome())) };
72
+ }
73
+ /**
74
+ * `license` is what `reticle license` printed. The caller reads it, so this directory does not
75
+ * reach into the license feature.
76
+ */
77
+ export async function handleStatus(port, json = false, license) {
60
78
  // A broken session file must not cost the reader the rest of the status.
61
79
  const account = await accountStatusFields().catch(() => ({}));
62
80
  // At a workspace root that is no app of its own, each app and its link: "not linked" named none.
@@ -66,7 +84,7 @@ export async function handleStatus(port, json = false) {
66
84
  workspaceApps: await workspaceAppLinks(process.cwd(), localLinkOf).catch(() => []),
67
85
  });
68
86
  }
69
- const report = (fields) => reportStatus({ ...fields, ...account }, json);
87
+ const report = (fields) => reportStatus({ ...fields, ...account, ...(license === undefined ? {} : { license }) }, json);
70
88
  const pid = readPid(port);
71
89
  // Durable, so it survives the daemon idling out — which is the state `status` is most often run in.
72
90
  const projectId = readProjectId(process.cwd());
@@ -81,7 +99,7 @@ export async function handleStatus(port, json = false) {
81
99
  // The OTHER half of the install, and the half this command could not see. A host that registers
82
100
  // Reticle and never lists its tools looks exactly like an abandoned install from here — same idle
83
101
  // daemon, same zero sessions — and the user sees a tool that does nothing. See attach-memory.ts.
84
- const client = attachStatusFields(reticleStateHome(), port);
102
+ const client = { ...attachStatusFields(reticleStateHome(), port), ...agentStatusFields() };
85
103
  // What the dev servers themselves said. The reason this command could previously only guess at
86
104
  // whether the app was running is that it had no way to see one; now the ones carrying Reticle
87
105
  // announce, and the advice below stops contradicting the terminal the reader is looking at.
@@ -103,7 +121,7 @@ export async function handleStatus(port, json = false) {
103
121
  port,
104
122
  running: false,
105
123
  presence,
106
- ...(presence === PortPresence.FOREIGN ? { reason: describePresence(presence, port) } : {}),
124
+ ...(presence === PortPresence.FOREIGN ? { reason: describePortState(presence, port) } : {}),
107
125
  // `init` promises this command says why the app has not connected. Without it the answer was
108
126
  // `running: false` and nothing else, which reads as "Reticle is broken" for what is usually
109
127
  // just a daemon that has not been asked to do anything yet.
@@ -1,6 +1,11 @@
1
1
  import type { CloudConfig } from '../../memory/cloud/cloud-sync.js';
2
2
  import { type FreeDrive } from '../../features/harness/platform/platform-drives.js';
3
3
  export declare const MSG_SIGN_IN_FIRST = "Link this folder first: reticle connect. It signs you in if you are not, and it is free, no card.";
4
+ /**
5
+ * The local path that needs no account and no MCP tools. An agent whose client had no reticle_*
6
+ * tools ran `try`, was told to sign in, and stopped with no verdict.
7
+ */
8
+ export declare const MSG_LOCAL_CHECK: string;
4
9
  /** The whole drive, model turns and browser included, before the CLI stops waiting for it. */
5
10
  export declare const TRY_BUDGET_MS = 120000;
6
11
  /** Model turns in the one free drive. Bounds what it costs, not what it may find. */
@@ -43,6 +48,8 @@ export declare function summarizeTry(journeys: readonly TryJourney[]): string[];
43
48
  export declare function runTry(args: TryArgs, ports: TryPorts): Promise<number>;
44
49
  /** The journeys out of an explore report, or one journey graded from the drive when unplanned. */
45
50
  export declare function journeysOf(report: Record<string, unknown>, persona?: string): TryJourney[];
51
+ /** A daemon serving `port`: the one already there, or one started now. Undefined when ready. */
52
+ export declare function ensureTryDaemon(port: number): Promise<string | undefined>;
46
53
  /** What `try` borrows from the cloud commands, passed in so neither module imports the other. */
47
54
  export interface TryCloud {
48
55
  push: () => Promise<number>;
@@ -19,7 +19,8 @@ import { describeUnsynced, unsyncedRoots } from '../../memory/cloud/unsynced-roo
19
19
  import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
20
20
  import { defaultPairingTokenDir, readOrCreatePairingTokenSync, } from '../../portal/bridge/pairing-token.js';
21
21
  import { spawnDaemon } from '../daemon/daemon.js';
22
- import { PortPresence, describePresence, presenceIsUsable, probePresence, } from '../daemon/binding/port-presence.js';
22
+ import { PortPresence, presenceIsUsable, probePresence, } from '../daemon/binding/port-presence.js';
23
+ import { describePortState } from '../daemon/port-state.js';
23
24
  import { fetchStatus } from '../daemon/binding/daemon-status-probe.js';
24
25
  import { probeDaemon, waitForDaemonBind } from '../../surface/mcp/mcp-proxy.js';
25
26
  import { readProjectPort } from './ports/resolve/cli-port.js';
@@ -28,6 +29,12 @@ import { seeRunLine } from '../../memory/project/sync-status.js';
28
29
  import { DAEMON_INNER_COMMAND, PORT_FLAG } from './cli-parse.js';
29
30
  import { acquireLease, connectOverSse, endpointFor, exploreToEnd, refusalText, releaseLease, verdictOf, } from './adhoc-verdict.js';
30
31
  export const MSG_SIGN_IN_FIRST = 'Link this folder first: reticle connect. It signs you in if you are not, and it is free, no card.';
32
+ /**
33
+ * The local path that needs no account and no MCP tools. An agent whose client had no reticle_*
34
+ * tools ran `try`, was told to sign in, and stopped with no verdict.
35
+ */
36
+ export const MSG_LOCAL_CHECK = 'To check one thing on this machine with no account and no MCP tools: ' +
37
+ `reticle verify <url> --expect '{"kind":"text","contains":"..."}'. Exit 0 means it held.`;
31
38
  const PERSONA_FLAG = '--persona';
32
39
  /** The whole drive, model turns and browser included, before the CLI stops waiting for it. */
33
40
  export const TRY_BUDGET_MS = 120_000;
@@ -89,6 +96,7 @@ export async function runTry(args, ports) {
89
96
  const cloud = await ports.linked();
90
97
  if (null === cloud) {
91
98
  ports.fail(MSG_SIGN_IN_FIRST);
99
+ ports.fail(MSG_LOCAL_CHECK);
92
100
  return EXIT_FAIL;
93
101
  }
94
102
  const grant = await ports.requestDrive(cloud);
@@ -165,13 +173,13 @@ function tryPort(cwd) {
165
173
  return readProjectPort(cwd) ?? RETICLE_DEFAULT_PORT;
166
174
  }
167
175
  /** A daemon serving `port`: the one already there, or one started now. Undefined when ready. */
168
- async function ensureTryDaemon(port) {
176
+ export async function ensureTryDaemon(port) {
169
177
  const presence = await probePresence(port, { tcpOpen: probeDaemon, status: fetchStatus });
170
178
  if (presenceIsUsable(presence))
171
179
  return undefined;
172
180
  // A stranger on the port: a daemon spawned now could not bind, so say who holds it instead.
173
181
  if (PortPresence.FREE !== presence)
174
- return describePresence(presence, port);
182
+ return describePortState(presence, port);
175
183
  const script = process.argv[1];
176
184
  if (script === undefined)
177
185
  return 'Cannot locate the reticle daemon script.';
@@ -0,0 +1,48 @@
1
+ import { type OpenedPage } from '../../../features/compare/behaviour-compare.js';
2
+ import { type CompareUrls } from '../../../features/compare/behaviour-report.js';
3
+ import { type StateIo } from '../../../features/compare/outside/state-sources.js';
4
+ import { type ToolCaller } from '../daemon-link/daemon-client.js';
5
+ /** The pairing token the daemon asks for, or undefined when there is none. */
6
+ export declare function pairingToken(): string | undefined;
7
+ /** One leased tab as the compare driver. Every call goes through `reticle_run` on that tab. */
8
+ export declare function leasedPage(caller: ToolCaller, url: string, sessionId: string): OpenedPage;
9
+ export interface CompareCommandOptions extends CompareUrls {
10
+ json: boolean;
11
+ port: number;
12
+ token?: string;
13
+ /** The caller's project `.reticle`, where the leased tabs write their runs. */
14
+ root?: string;
15
+ /** Injected so a test can use its own transport. */
16
+ connect?: (endpoint: URL) => Promise<ToolCaller>;
17
+ sleep?: (ms: number) => Promise<void>;
18
+ now?: () => number;
19
+ fetchText?: (url: string) => Promise<string | undefined>;
20
+ /** `--report <file>`: also write the comparison as an HTML page there. */
21
+ report?: string;
22
+ /** Injected so a test can capture the report; the default writes the file. */
23
+ writeReport?: (path: string, html: string) => void;
24
+ /** The path of the declared state sources file (`--state`). */
25
+ state?: string;
26
+ }
27
+ export declare const MSG_REPORT_WRITTEN = "Report:";
28
+ export declare const MSG_REPORT_FAILED = "Report not written:";
29
+ /** State sources read on this machine: a shell, `docker exec`, `fetch` and the file system. */
30
+ export declare const hostStateIo: StateIo;
31
+ /** Compare the builds through the daemon on `port`. Returns the lines to print and the exit code. */
32
+ export declare function runCompareCommand(options: CompareCommandOptions): Promise<{
33
+ code: number;
34
+ lines: string[];
35
+ }>;
36
+ /**
37
+ * The command. It needs a daemon, as an agent does: `ensureDaemon` attaches to the one on the port,
38
+ * or starts one. Nothing here stops a daemon, so an agent's MCP link stays up.
39
+ */
40
+ export declare function handleCompare(parsed: CompareUrls & {
41
+ json: boolean;
42
+ port: number;
43
+ report?: string;
44
+ state?: string;
45
+ }, ensureDaemon: (port: number) => Promise<void>, out: {
46
+ line: (text: string) => void;
47
+ exit: (code: number) => void;
48
+ }): Promise<void>;