@reticlehq/server 3.9.0 → 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 (350) hide show
  1. package/SKILL.md +13 -12
  2. package/dist/command/cli/adhoc-suite.js +2 -0
  3. package/dist/command/cli/adhoc-verdict.d.ts +2 -43
  4. package/dist/command/cli/adhoc-verdict.js +50 -187
  5. package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
  6. package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
  7. package/dist/command/cli/cli-doctor.js +1 -1
  8. package/dist/command/cli/cli-flow-commands.js +2 -9
  9. package/dist/command/cli/cli-kill.js +1 -1
  10. package/dist/command/cli/cli-parse-compare.d.ts +22 -0
  11. package/dist/command/cli/cli-parse-compare.js +75 -0
  12. package/dist/command/cli/cli-parse-grade.d.ts +36 -0
  13. package/dist/command/cli/cli-parse-grade.js +75 -0
  14. package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
  15. package/dist/command/cli/cli-parse-grammar.js +18 -20
  16. package/dist/command/cli/cli-parse-verify.d.ts +10 -0
  17. package/dist/command/cli/cli-parse-verify.js +63 -14
  18. package/dist/command/cli/cli-parse.d.ts +17 -15
  19. package/dist/command/cli/cli-parse.js +44 -27
  20. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  21. package/dist/command/cli/cli-update-commands.js +29 -20
  22. package/dist/command/cli/cli-usage.js +58 -29
  23. package/dist/command/cli/cli-verify.d.ts +11 -2
  24. package/dist/command/cli/cli-verify.js +27 -8
  25. package/dist/command/cli/cloud-cli.js +2 -119
  26. package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
  27. package/dist/command/cli/daemon-link/daemon-client.js +205 -0
  28. package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
  29. package/dist/command/cli/doctor-repairs.js +1 -1
  30. package/dist/command/cli/ensure-daemon.d.ts +26 -0
  31. package/dist/command/cli/ensure-daemon.js +57 -0
  32. package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
  33. package/dist/command/cli/finished-run/grade-command.js +180 -0
  34. package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
  35. package/dist/command/cli/lifecycle/daemon-lifecycle.js +1 -1
  36. package/dist/command/cli/ports/port-holder.d.ts +9 -0
  37. package/dist/command/cli/ports/port-holder.js +27 -3
  38. package/dist/command/cli/status/status-lines.d.ts +1 -0
  39. package/dist/command/cli/status/status-lines.js +22 -0
  40. package/dist/command/cli/status-fields.d.ts +5 -1
  41. package/dist/command/cli/status-fields.js +7 -3
  42. package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
  43. package/dist/command/cli/two-builds/compare-command.js +314 -0
  44. package/dist/command/cli/verify-against.d.ts +61 -0
  45. package/dist/command/cli/verify-against.js +187 -0
  46. package/dist/command/cli/verify-no-session.d.ts +2 -0
  47. package/dist/command/cli/verify-no-session.js +13 -0
  48. package/dist/command/cli/verify-results.d.ts +35 -2
  49. package/dist/command/cli/verify-results.js +76 -10
  50. package/dist/command/cli.js +46 -41
  51. package/dist/command/daemon/daemon-resolve.d.ts +8 -1
  52. package/dist/command/daemon/daemon-resolve.js +27 -1
  53. package/dist/command/daemon/daemon.d.ts +12 -1
  54. package/dist/command/daemon/daemon.js +35 -4
  55. package/dist/command/daemon/lifetime/death-cause.js +21 -2
  56. package/dist/command/daemon/lifetime/heartbeat.js +7 -2
  57. package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
  58. package/dist/command/daemon/lifetime/startup-failure.js +62 -0
  59. package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
  60. package/dist/command/setup/bringup/dev-server-files.js +17 -0
  61. package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
  62. package/dist/command/setup/bringup/static-page-server.js +43 -9
  63. package/dist/command/setup/init/init-runtime.js +6 -0
  64. package/dist/command/setup/node-effects.d.ts +3 -2
  65. package/dist/command/setup/node-effects.js +9 -3
  66. package/dist/command/setup/remaining-steps.d.ts +8 -0
  67. package/dist/command/setup/remaining-steps.js +10 -0
  68. package/dist/command/setup/run-setup.d.ts +2 -0
  69. package/dist/command/setup/run-setup.js +9 -1
  70. package/dist/command/setup/setup-command.js +6 -3
  71. package/dist/command/update/updater.js +6 -0
  72. package/dist/command/version/version-skew.js +1 -1
  73. package/dist/features/compare/action-plan.d.ts +260 -0
  74. package/dist/features/compare/action-plan.js +543 -0
  75. package/dist/features/compare/behaviour-compare.d.ts +24 -0
  76. package/dist/features/compare/behaviour-compare.js +85 -0
  77. package/dist/features/compare/behaviour-diff.d.ts +97 -0
  78. package/dist/features/compare/behaviour-diff.js +202 -0
  79. package/dist/features/compare/behaviour-report.d.ts +40 -0
  80. package/dist/features/compare/behaviour-report.js +128 -0
  81. package/dist/features/compare/build-readings.d.ts +106 -0
  82. package/dist/features/compare/build-readings.js +250 -0
  83. package/dist/features/compare/compare-diff.d.ts +62 -0
  84. package/dist/features/compare/compare-diff.js +177 -0
  85. package/dist/features/compare/compare-report-html.d.ts +6 -0
  86. package/dist/features/compare/compare-report-html.js +102 -0
  87. package/dist/features/compare/compare-report.d.ts +15 -0
  88. package/dist/features/compare/compare-report.js +73 -0
  89. package/dist/features/compare/compare-run.d.ts +60 -0
  90. package/dist/features/compare/compare-run.js +123 -0
  91. package/dist/features/compare/outside/effect-lines.d.ts +26 -0
  92. package/dist/features/compare/outside/effect-lines.js +103 -0
  93. package/dist/features/compare/outside/state-sources.d.ts +76 -0
  94. package/dist/features/compare/outside/state-sources.js +164 -0
  95. package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
  96. package/dist/features/compare/outside/value-dictionary.js +227 -0
  97. package/dist/features/compare/visible-content.d.ts +20 -0
  98. package/dist/features/compare/visible-content.js +125 -0
  99. package/dist/features/crawl/crawl-empty.js +2 -1
  100. package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
  101. package/dist/features/crawl/crawl-exhaustive.js +138 -0
  102. package/dist/features/crawl/crawl-tools.d.ts +9 -2
  103. package/dist/features/crawl/crawl-tools.js +28 -12
  104. package/dist/features/crawl/crawl.d.ts +8 -9
  105. package/dist/features/crawl/crawl.js +61 -65
  106. package/dist/features/exhaust/app-coverage.d.ts +5 -1
  107. package/dist/features/exhaust/app-coverage.js +3 -1
  108. package/dist/features/exhaust/code-coverage.js +8 -4
  109. package/dist/features/exhaust/edge-cases.d.ts +133 -0
  110. package/dist/features/exhaust/edge-cases.js +310 -0
  111. package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
  112. package/dist/features/exhaust/edges/edge-drive.js +364 -0
  113. package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
  114. package/dist/features/exhaust/edges/edge-run.js +169 -0
  115. package/dist/features/exhaust/explorer.d.ts +87 -14
  116. package/dist/features/exhaust/explorer.js +159 -25
  117. package/dist/features/exhaust/failure-branches.d.ts +5 -0
  118. package/dist/features/exhaust/failure-branches.js +29 -11
  119. package/dist/features/exhaust/invariants.d.ts +112 -0
  120. package/dist/features/exhaust/invariants.js +188 -0
  121. package/dist/features/exhaust/ledger.d.ts +68 -0
  122. package/dist/features/exhaust/ledger.js +121 -13
  123. package/dist/features/exhaust/session-fold.d.ts +10 -0
  124. package/dist/features/exhaust/session-fold.js +46 -3
  125. package/dist/features/exhaust/session-port.d.ts +3 -1
  126. package/dist/features/exhaust/session-port.js +97 -28
  127. package/dist/features/grade/grade-answer.d.ts +99 -0
  128. package/dist/features/grade/grade-answer.js +112 -0
  129. package/dist/features/grade/grade-noise.d.ts +27 -0
  130. package/dist/features/grade/grade-noise.js +55 -0
  131. package/dist/features/grade/grade-renumber.d.ts +12 -0
  132. package/dist/features/grade/grade-renumber.js +86 -0
  133. package/dist/features/grade/grade-state.d.ts +50 -0
  134. package/dist/features/grade/grade-state.js +93 -0
  135. package/dist/features/grade/grade-suggest.d.ts +33 -0
  136. package/dist/features/grade/grade-suggest.js +98 -0
  137. package/dist/features/visual/visual-tools.js +66 -19
  138. package/dist/index.js +7 -4
  139. package/dist/judgement/capsule/causal-summary.js +9 -2
  140. package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
  141. package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
  142. package/dist/judgement/runs/reticle-runner.js +16 -2
  143. package/dist/judgement/runs/runner-port.d.ts +2 -0
  144. package/dist/judgement/runs/runner-port.js +23 -5
  145. package/dist/language/flows/affected-tools.d.ts +1 -1
  146. package/dist/language/flows/affected-tools.js +49 -30
  147. package/dist/language/flows/change/git-changed.d.ts +2 -1
  148. package/dist/language/flows/change/git-changed.js +19 -2
  149. package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
  150. package/dist/language/flows/fields/flow-secret-field.js +77 -21
  151. package/dist/language/flows/flow-anchor.d.ts +60 -2
  152. package/dist/language/flows/flow-anchor.js +125 -20
  153. package/dist/language/flows/flow-classify.d.ts +20 -0
  154. package/dist/language/flows/flow-classify.js +90 -12
  155. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  156. package/dist/language/flows/flow-cross-step.js +25 -1
  157. package/dist/language/flows/flow-journey.d.ts +38 -4
  158. package/dist/language/flows/flow-journey.js +138 -8
  159. package/dist/language/flows/flow-replay-run.d.ts +0 -16
  160. package/dist/language/flows/flow-replay-run.js +76 -14
  161. package/dist/language/flows/flow-replay-types.d.ts +4 -2
  162. package/dist/language/flows/flow-replay.d.ts +19 -1
  163. package/dist/language/flows/flow-replay.js +169 -52
  164. package/dist/language/flows/flow-replayable.js +7 -1
  165. package/dist/language/flows/flow-start-path.d.ts +34 -5
  166. package/dist/language/flows/flow-start-path.js +202 -15
  167. package/dist/language/flows/flow-step-runners.d.ts +14 -13
  168. package/dist/language/flows/flow-step-runners.js +184 -109
  169. package/dist/language/flows/flow-store-for-session.d.ts +26 -25
  170. package/dist/language/flows/flow-store-for-session.js +44 -0
  171. package/dist/language/flows/flow-tools.js +46 -33
  172. package/dist/language/flows/flows.js +176 -76
  173. package/dist/language/flows/recording/tape/recordings.d.ts +19 -3
  174. package/dist/language/flows/recording/tape/recordings.js +71 -5
  175. package/dist/language/flows/replay.d.ts +19 -5
  176. package/dist/language/flows/replay.js +99 -7
  177. package/dist/language/flows/steps/page-steps.d.ts +68 -0
  178. package/dist/language/flows/steps/page-steps.js +198 -0
  179. package/dist/language/flows/suite/sequential-run.d.ts +68 -0
  180. package/dist/language/flows/suite/sequential-run.js +96 -0
  181. package/dist/language/flows/verify-change-tools.js +26 -15
  182. package/dist/memory/cloud/background-sync.d.ts +13 -0
  183. package/dist/memory/cloud/background-sync.js +24 -3
  184. package/dist/memory/cloud/sync-daemon.js +26 -27
  185. package/dist/memory/journal/attach-journal.js +2 -1
  186. package/dist/memory/journal/drive-flow.d.ts +7 -0
  187. package/dist/memory/journal/drive-flow.js +44 -13
  188. package/dist/memory/journal/journal-recorder.d.ts +4 -2
  189. package/dist/memory/journal/session-journal.d.ts +7 -0
  190. package/dist/memory/journal/session-journal.js +58 -10
  191. package/dist/memory/project/root-claims.d.ts +9 -0
  192. package/dist/memory/project/root-claims.js +9 -4
  193. package/dist/portal/input/download-capture.d.ts +7 -0
  194. package/dist/portal/input/download-capture.js +92 -0
  195. package/dist/portal/input/network-detail.d.ts +6 -0
  196. package/dist/portal/input/network-detail.js +12 -1
  197. package/dist/portal/input/network-mock-tools.js +49 -13
  198. package/dist/portal/input/network-mock.d.ts +8 -0
  199. package/dist/portal/input/network-mock.js +28 -9
  200. package/dist/portal/input/page-capture.d.ts +24 -0
  201. package/dist/portal/input/page-capture.js +33 -0
  202. package/dist/portal/input/real-input.d.ts +22 -20
  203. package/dist/portal/input/real-input.js +41 -31
  204. package/dist/portal/input/viewport-tools.d.ts +8 -0
  205. package/dist/portal/input/viewport-tools.js +75 -18
  206. package/dist/portal/pool/browser-pool.d.ts +11 -29
  207. package/dist/portal/pool/browser-pool.js +35 -17
  208. package/dist/portal/pool/context-permissions.d.ts +17 -3
  209. package/dist/portal/pool/context-permissions.js +36 -5
  210. package/dist/portal/pool/determinism.d.ts +52 -0
  211. package/dist/portal/pool/determinism.js +259 -0
  212. package/dist/portal/pool/lease-emulation.d.ts +34 -1
  213. package/dist/portal/pool/lease-emulation.js +18 -0
  214. package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
  215. package/dist/portal/pool/lease-marker-stamp.js +15 -1
  216. package/dist/portal/pool/lease-page-error.d.ts +44 -17
  217. package/dist/portal/pool/lease-page-error.js +147 -5
  218. package/dist/portal/pool/page-error-journal.d.ts +7 -1
  219. package/dist/portal/pool/page-error-journal.js +27 -0
  220. package/dist/portal/pool/playwright-launcher.js +51 -8
  221. package/dist/portal/pool/pool-contract.d.ts +27 -1
  222. package/dist/portal/pool/pool-lease.d.ts +36 -1
  223. package/dist/portal/pool/zero-install.d.ts +8 -0
  224. package/dist/portal/pool/zero-install.js +23 -1
  225. package/dist/portal/session/dev-server/dev-command.d.ts +7 -6
  226. package/dist/portal/session/dev-server/dev-command.js +61 -15
  227. package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
  228. package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
  229. package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
  230. package/dist/portal/session/dev-server/project-ports.js +62 -0
  231. package/dist/portal/session/facts/departed-network.d.ts +66 -0
  232. package/dist/portal/session/facts/departed-network.js +142 -0
  233. package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
  234. package/dist/portal/session/no-session-diagnosis.js +67 -25
  235. package/dist/portal/session/no-session-next-action.d.ts +2 -0
  236. package/dist/portal/session/no-session-next-action.js +12 -3
  237. package/dist/portal/session/no-session-watch.d.ts +6 -0
  238. package/dist/portal/session/no-session-watch.js +38 -3
  239. package/dist/portal/session/serving-directory.d.ts +10 -0
  240. package/dist/portal/session/serving-directory.js +39 -8
  241. package/dist/portal/session/session-manager.d.ts +10 -0
  242. package/dist/portal/session/session-manager.js +174 -63
  243. package/dist/start-wiring.d.ts +2 -1
  244. package/dist/start-wiring.js +2 -1
  245. package/dist/surface/mcp/mcp.js +3 -2
  246. package/dist/surface/mcp/shared-params.d.ts +2 -0
  247. package/dist/surface/mcp/shared-params.js +31 -0
  248. package/dist/surface/tools/act/act-observation.d.ts +40 -2
  249. package/dist/surface/tools/act/act-observation.js +118 -12
  250. package/dist/surface/tools/act/act-preflight.js +1 -1
  251. package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
  252. package/dist/surface/tools/act/act-sequence-retry.js +61 -5
  253. package/dist/surface/tools/act/after-match.d.ts +4 -1
  254. package/dist/surface/tools/act/after-match.js +8 -1
  255. package/dist/surface/tools/act/already-true.js +1 -1
  256. package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
  257. package/dist/surface/tools/act/navigation/reload-result.js +25 -2
  258. package/dist/surface/tools/act/resolve-target.d.ts +15 -1
  259. package/dist/surface/tools/act/resolve-target.js +24 -1
  260. package/dist/surface/tools/act/sequence-grade.d.ts +12 -0
  261. package/dist/surface/tools/act/sequence-grade.js +37 -26
  262. package/dist/surface/tools/act/settle-in-flight.js +27 -15
  263. package/dist/surface/tools/act-command.d.ts +23 -0
  264. package/dist/surface/tools/act-command.js +50 -0
  265. package/dist/surface/tools/act-sequence-tool.js +78 -50
  266. package/dist/surface/tools/act-tools.d.ts +1 -13
  267. package/dist/surface/tools/act-tools.js +74 -86
  268. package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
  269. package/dist/surface/tools/agent/build-staleness.js +1 -1
  270. package/dist/surface/tools/assert/assert-verdict.js +16 -37
  271. package/dist/surface/tools/browser-tools.js +12 -6
  272. package/dist/surface/tools/compare-tools.d.ts +11 -0
  273. package/dist/surface/tools/compare-tools.js +94 -0
  274. package/dist/surface/tools/coverage-tools.js +1 -1
  275. package/dist/surface/tools/dynamic-tools.js +9 -2
  276. package/dist/surface/tools/error-recovery.d.ts +12 -1
  277. package/dist/surface/tools/error-recovery.js +91 -21
  278. package/dist/surface/tools/explore-tools.js +1 -1
  279. package/dist/surface/tools/invoke-tool.js +3 -2
  280. package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
  281. package/dist/surface/tools/lease-coverage-tools.js +128 -0
  282. package/dist/surface/tools/lease-hint.d.ts +35 -1
  283. package/dist/surface/tools/lease-hint.js +42 -0
  284. package/dist/surface/tools/lease-readiness.d.ts +26 -0
  285. package/dist/surface/tools/lease-readiness.js +79 -0
  286. package/dist/surface/tools/lease-seed.d.ts +14 -1
  287. package/dist/surface/tools/lease-seed.js +35 -3
  288. package/dist/surface/tools/lease-tools.d.ts +3 -41
  289. package/dist/surface/tools/lease-tools.js +62 -110
  290. package/dist/surface/tools/lease-url-identity.d.ts +46 -0
  291. package/dist/surface/tools/lease-url-identity.js +97 -0
  292. package/dist/surface/tools/merge-tools.js +99 -2
  293. package/dist/surface/tools/merged-name-redirect.js +5 -1
  294. package/dist/surface/tools/observe-tools.js +15 -9
  295. package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
  296. package/dist/surface/tools/read/console-pre-attach.js +23 -0
  297. package/dist/surface/tools/read-tools.js +33 -30
  298. package/dist/surface/tools/real-input-attempt.d.ts +0 -8
  299. package/dist/surface/tools/real-input-attempt.js +143 -28
  300. package/dist/surface/tools/session-ports.d.ts +14 -0
  301. package/dist/surface/tools/session-ports.js +53 -0
  302. package/dist/surface/tools/tool-kit.d.ts +6 -0
  303. package/dist/surface/tools/tool-kit.js +2 -3
  304. package/dist/surface/tools/tool-surface.js +0 -1
  305. package/dist/surface/tools/tools.js +28 -5
  306. package/dist/surface/tools/type-spelling.d.ts +13 -0
  307. package/dist/surface/tools/type-spelling.js +36 -0
  308. package/dist/telemetry/agent-client.d.ts +6 -0
  309. package/dist/telemetry/agent-client.js +10 -0
  310. package/dist/telemetry/argument-shape.js +1 -0
  311. package/dist/telemetry/tool-refused.d.ts +6 -3
  312. package/dist/telemetry/tool-refused.js +8 -3
  313. package/docs/actions.mdx +3 -3
  314. package/docs/agent-cheatsheet.md +1 -1
  315. package/docs/capabilities.mdx +61 -1
  316. package/docs/cli/affected.mdx +9 -7
  317. package/docs/cli/cloud.mdx +3 -3
  318. package/docs/cli/compare.mdx +94 -0
  319. package/docs/cli/doctor.mdx +1 -1
  320. package/docs/cli/grade.mdx +97 -0
  321. package/docs/cli/license.mdx +9 -7
  322. package/docs/cli/restart.mdx +7 -5
  323. package/docs/cli/rollback.mdx +5 -5
  324. package/docs/cli/stop.mdx +3 -3
  325. package/docs/cli/update.mdx +2 -2
  326. package/docs/cli/verify.mdx +23 -1
  327. package/docs/cli.mdx +33 -23
  328. package/docs/deploy-checks.md +1 -1
  329. package/docs/desktop.mdx +1 -1
  330. package/docs/enterprise.md +2 -2
  331. package/docs/environment.mdx +1 -1
  332. package/docs/flows.md +11 -1
  333. package/docs/frameworks.mdx +9 -9
  334. package/docs/getting-started.md +1 -1
  335. package/docs/install-manual.mdx +1 -1
  336. package/docs/license-activation.mdx +3 -3
  337. package/docs/packages/tauri.mdx +1 -1
  338. package/docs/packages.mdx +1 -1
  339. package/docs/predicates.mdx +1 -1
  340. package/docs/quickstart.mdx +68 -49
  341. package/docs/skill-setup.md +1 -1
  342. package/docs/skill.md +14 -13
  343. package/docs/telemetry.md +2 -2
  344. package/docs/tools/navigate.mdx +1 -1
  345. package/docs/tools/verify.mdx +4 -1
  346. package/docs/troubleshooting.mdx +1 -1
  347. package/docs/usage.md +17 -14
  348. package/package.json +13 -13
  349. package/dist/features/exhaust/exhaust-run.d.ts +0 -33
  350. package/dist/features/exhaust/exhaust-run.js +0 -82
@@ -14,6 +14,7 @@
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',
@@ -24,6 +25,7 @@ export const StatusLabel = {
24
25
  NEXT: 'next',
25
26
  SPLIT_BRAIN: 'split brain',
26
27
  UPDATE: 'update',
28
+ LICENSE: 'license',
27
29
  };
28
30
  const LABELS = Object.values(StatusLabel);
29
31
  /** The heading, so a reader can tell which command produced the block. */
@@ -80,6 +82,9 @@ export function statusLines(fields) {
80
82
  lines.push(row(StatusLabel.DAEMON, running
81
83
  ? `${OK} running${at}${pid === undefined ? '' : ` (pid ${String(pid)})`}`
82
84
  : `${NOT_OK} not running${at}`));
85
+ if (running && port !== undefined) {
86
+ lines.push(continuation(mcpConnectionHint(port)));
87
+ }
83
88
  // What was actually ON the port, when the pid file said nothing useful. "A stranger holds this"
84
89
  // and "nothing is here" were the same output once, and the true sentence was said by nothing a
85
90
  // person sees — so the word belongs in the prose, not only in the event.
@@ -156,8 +161,25 @@ export function statusLines(fields) {
156
161
  lines.push(row(label, value));
157
162
  }
158
163
  }
164
+ const license = licenseText(fields['license']);
165
+ if (license !== undefined) {
166
+ lines.push(row(StatusLabel.LICENSE, license));
167
+ }
159
168
  return lines;
160
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
+ }
161
183
  /** The account row: refused at the last sync, not signed in, or signed in. */
162
184
  function accountText(refused, who) {
163
185
  if (refused !== undefined) {
@@ -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>;
@@ -39,7 +39,7 @@ export function withNextAction(facts) {
39
39
  */
40
40
  export function splitBrainFields(port, projectId) {
41
41
  const home = reticleStateHome();
42
- 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 });
43
43
  const note = elsewhere ?? wrongDaemonNote(port, resolveDaemonForProject(projectId, home, isAlive));
44
44
  return note === undefined ? {} : { splitBrain: note };
45
45
  }
@@ -70,7 +70,11 @@ function agentStatusFields() {
70
70
  ? {}
71
71
  : { agents: agentStatuses(rows, connectedAgentClients(reticleStateHome())) };
72
72
  }
73
- export async function handleStatus(port, json = false) {
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) {
74
78
  // A broken session file must not cost the reader the rest of the status.
75
79
  const account = await accountStatusFields().catch(() => ({}));
76
80
  // At a workspace root that is no app of its own, each app and its link: "not linked" named none.
@@ -80,7 +84,7 @@ export async function handleStatus(port, json = false) {
80
84
  workspaceApps: await workspaceAppLinks(process.cwd(), localLinkOf).catch(() => []),
81
85
  });
82
86
  }
83
- const report = (fields) => reportStatus({ ...fields, ...account }, json);
87
+ const report = (fields) => reportStatus({ ...fields, ...account, ...(license === undefined ? {} : { license }) }, json);
84
88
  const pid = readPid(port);
85
89
  // Durable, so it survives the daemon idling out — which is the state `status` is most often run in.
86
90
  const projectId = readProjectId(process.cwd());
@@ -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>;
@@ -0,0 +1,314 @@
1
+ /**
2
+ * `reticle compare <reference-url> <candidate-url> [--base <url>] [--json]`.
3
+ *
4
+ * Drives two running builds of one app the same way and reports each difference in what a person
5
+ * sees, for example main against a pull request preview. The app needs nothing installed: each run
6
+ * is a tab the daemon leases, and a page with no Reticle SDK gets the daemon's own reader. The rules
7
+ * are in `@/features/compare/behaviour-compare.ts`; this file connects them to the daemon over its
8
+ * MCP transport, with the same tool calls an agent makes.
9
+ */
10
+ import { ActionType, isLocalhostSubdomain, isLoopbackHostname, ReticleTool, SnapshotMode, } from '@reticlehq/core';
11
+ import { mkdirSync, writeFileSync } from 'node:fs';
12
+ import { dirname } from 'node:path';
13
+ import { runCompare } from '../../../features/compare/behaviour-compare.js';
14
+ import { compareReportHtml } from '../../../features/compare/compare-report-html.js';
15
+ import { invalidComparison } from '../../../features/compare/behaviour-diff.js';
16
+ import { compareExitCode, compareReportJson, compareReportLines, } from '../../../features/compare/behaviour-report.js';
17
+ import { DriverLostError } from '../../../features/compare/build-readings.js';
18
+ import { StateDeclarationSchema, readStateSources, } from '../../../features/compare/outside/state-sources.js';
19
+ import { consoleLines, networkLines } from '../../../features/compare/outside/effect-lines.js';
20
+ import { execFile } from 'node:child_process';
21
+ import { readFile } from 'node:fs/promises';
22
+ import { promisify } from 'node:util';
23
+ import { callerArtifactRoot } from '../../../memory/project/link-directory.js';
24
+ import { defaultPairingTokenDir, readOrCreatePairingTokenSync, } from '../../../portal/bridge/pairing-token.js';
25
+ import { acquireLease, connectOverSse, endpointFor, payloadOf, refusalText, releaseLease, } from '../daemon-link/daemon-client.js';
26
+ /** How long a navigation may take before the start page counts as not loaded. */
27
+ const NAVIGATE_WAIT_MS = 15_000;
28
+ /** Room for one tool call past its own wait. */
29
+ const CALL_MS = 60_000;
30
+ /** The most network calls and console lines read for one sequence. */
31
+ const EFFECTS_LIMIT = 50;
32
+ /** How long fetching one page or script file may take. */
33
+ const FETCH_MS = 10_000;
34
+ /**
35
+ * Refusals that mean the driver lost its tab, not that the build did something. A run that sees
36
+ * one proves nothing about the build.
37
+ */
38
+ const DRIVER_LOST = /no browser session connected|no connected session|multiple sessions connected|session disconnected|names no session|no such session|session ended/i;
39
+ const MSG_NO_DAEMON = 'could not reach the daemon on port';
40
+ const MSG_LEASE_FAILED = 'could not open a browser on';
41
+ const MSG_STATE_UNREADABLE = 'could not read the state sources in';
42
+ /** How long one state source read may take. */
43
+ const STATE_READ_MS = 60_000;
44
+ /** The most output one state command may give. */
45
+ const STATE_OUTPUT_BYTES = 64 * 1024 * 1024;
46
+ const SHELL = 'sh';
47
+ const SHELL_COMMAND_FLAG = '-c';
48
+ const DOCKER = 'docker';
49
+ const DOCKER_EXEC = 'exec';
50
+ const UTF8 = 'utf8';
51
+ const asText = (value) => 'string' === typeof value ? value : undefined;
52
+ /** The pairing token the daemon asks for, or undefined when there is none. */
53
+ export function pairingToken() {
54
+ const token = readOrCreatePairingTokenSync(defaultPairingTokenDir());
55
+ return token === undefined || 0 === token.length ? undefined : token;
56
+ }
57
+ /**
58
+ * A build on loopback or a `*.localhost` name is a disposable copy, so compare presses its guarded
59
+ * controls too ("Place order", "Delete"): they are the actions most worth comparing. On any other
60
+ * host the act guard stays on, so a compare can never delete real data.
61
+ */
62
+ function isDisposableBuild(url) {
63
+ try {
64
+ const { hostname } = new URL(url);
65
+ return isLoopbackHostname(hostname) || isLocalhostSubdomain(hostname);
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ /** The act tool's args: a press names its key as `text`, a fill or a select its `value`. */
72
+ function actArgs(action, value, guarded) {
73
+ if (value === undefined) {
74
+ return guarded;
75
+ }
76
+ return ActionType.PRESS === action ? { text: value, ...guarded } : { value, ...guarded };
77
+ }
78
+ /** One leased tab as the compare driver. Every call goes through `reticle_run` on that tab. */
79
+ export function leasedPage(caller, url, sessionId) {
80
+ let id = sessionId;
81
+ const guarded = isDisposableBuild(url) ? { confirmDangerous: true } : {};
82
+ const run = async (tool, args, timeoutMs = CALL_MS) => {
83
+ let result;
84
+ try {
85
+ result = await caller.call(ReticleTool.RUN, { tool, args: { ...args, sessionId: id } }, timeoutMs);
86
+ }
87
+ catch (error) {
88
+ // Name the call, so a run that lost its driver says where.
89
+ throw new DriverLostError(`${tool}: ${error instanceof Error ? error.message : String(error)}`);
90
+ }
91
+ const payload = payloadOf(result);
92
+ const refusal = refusalText(result) ?? asText(payload['error']);
93
+ if (refusal !== undefined && DRIVER_LOST.test(refusal)) {
94
+ throw new DriverLostError(`${tool}: ${refusal}`);
95
+ }
96
+ return refusal === undefined ? { payload } : { payload, refusal };
97
+ };
98
+ const navigate = async (to) => {
99
+ const { payload, refusal } = await run(ReticleTool.NAVIGATE, { url: to, timeout_ms: NAVIGATE_WAIT_MS }, NAVIGATE_WAIT_MS * 2);
100
+ id = asText(payload['sessionId']) ?? id;
101
+ return refusal === undefined && true === payload['ok'] && false !== payload['confirmed'];
102
+ };
103
+ /** Faults stay on the tab until cleared, and each fresh sequence must see the real server. */
104
+ let mocked = false;
105
+ const mockRequests = async (args) => {
106
+ const { payload, refusal } = await run(ReticleTool.NETWORK_MOCK, args);
107
+ return refusal === undefined && true === payload['applied'];
108
+ };
109
+ return {
110
+ async open() {
111
+ if (mocked) {
112
+ if (!(await mockRequests({ clear: true }))) {
113
+ return false;
114
+ }
115
+ mocked = false;
116
+ }
117
+ return navigate(url);
118
+ },
119
+ mock(rules) {
120
+ mocked = true;
121
+ return mockRequests({ mocks: rules });
122
+ },
123
+ goto(query) {
124
+ return navigate(new URL(query, url).href);
125
+ },
126
+ async read() {
127
+ const { payload } = await run(ReticleTool.SNAPSHOT, { mode: SnapshotMode.FULL, ids: true });
128
+ return asText(payload['tree']) ?? '';
129
+ },
130
+ async act(at, action, value) {
131
+ const { payload, refusal } = await run(ReticleTool.ACT, {
132
+ ...('string' === typeof at ? { ref: at } : { target: at }),
133
+ action,
134
+ args: actArgs(action, value, guarded),
135
+ });
136
+ const ok = refusal === undefined && false !== payload['dispatched'];
137
+ const since = payload['since'];
138
+ return 'number' === typeof since ? { ok, since } : { ok };
139
+ },
140
+ async effects(since) {
141
+ // A refused read is passed on as `{ error }`, so it becomes a visible line, not an empty list.
142
+ const read = async (tool, args) => {
143
+ const { payload, refusal } = await run(tool, { since, ...args, limit: EFFECTS_LIMIT });
144
+ return refusal === undefined ? payload : { error: refusal };
145
+ };
146
+ return [
147
+ ...networkLines(await read(ReticleTool.NETWORK, { bodies: true })),
148
+ ...consoleLines(await read(ReticleTool.CONSOLE, {})),
149
+ ];
150
+ },
151
+ async close() {
152
+ await releaseLease(caller, id);
153
+ },
154
+ };
155
+ }
156
+ export const MSG_REPORT_WRITTEN = 'Report:';
157
+ export const MSG_REPORT_FAILED = 'Report not written:';
158
+ function writeReportFile(path, html) {
159
+ mkdirSync(dirname(path), { recursive: true });
160
+ writeFileSync(path, html);
161
+ }
162
+ const execFileText = promisify(execFile);
163
+ /** State sources read on this machine: a shell, `docker exec`, `fetch` and the file system. */
164
+ export const hostStateIo = {
165
+ async run(command, container) {
166
+ const [file, args] = container === undefined
167
+ ? [SHELL, [SHELL_COMMAND_FLAG, command]]
168
+ : [DOCKER, [DOCKER_EXEC, container, SHELL, SHELL_COMMAND_FLAG, command]];
169
+ const { stdout } = await execFileText(file, args, {
170
+ encoding: UTF8,
171
+ timeout: STATE_READ_MS,
172
+ maxBuffer: STATE_OUTPUT_BYTES,
173
+ });
174
+ return stdout;
175
+ },
176
+ async fetchJson(url) {
177
+ const response = await fetch(url, { signal: AbortSignal.timeout(STATE_READ_MS) });
178
+ if (!response.ok) {
179
+ throw new Error(`HTTP ${String(response.status)}`);
180
+ }
181
+ return response.json();
182
+ },
183
+ readFile: (path) => readFile(path, UTF8),
184
+ };
185
+ /** The sources in the `--state` file, or why they could not be read. */
186
+ async function loadStateSources(path) {
187
+ try {
188
+ const parsed = StateDeclarationSchema.safeParse(JSON.parse(await readFile(path, UTF8)));
189
+ return parsed.success ? parsed.data.sources : { error: parsed.error.message };
190
+ }
191
+ catch (error) {
192
+ return { error: error instanceof Error ? error.message : String(error) };
193
+ }
194
+ }
195
+ /** Fetch a page or script file as a browser would. Undefined when it could not be fetched. */
196
+ async function fetchText(url) {
197
+ try {
198
+ const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_MS) });
199
+ return response.ok ? await response.text() : undefined;
200
+ }
201
+ catch {
202
+ return undefined;
203
+ }
204
+ }
205
+ /** The exit code, and the text or the one JSON line to print. */
206
+ function render(json, urls, result, timings, sink) {
207
+ const report = compareReportJson(urls, result, timings);
208
+ // A report that could not be written says so: a line in text mode, a field in the one JSON object.
209
+ let reportError;
210
+ if (sink !== undefined) {
211
+ try {
212
+ sink.write(sink.path, compareReportHtml(report));
213
+ }
214
+ catch (error) {
215
+ reportError = error instanceof Error ? error.message : String(error);
216
+ }
217
+ }
218
+ if (json) {
219
+ return {
220
+ code: compareExitCode(result),
221
+ lines: [JSON.stringify(reportError === undefined ? report : { ...report, reportError })],
222
+ };
223
+ }
224
+ const lines = compareReportLines(urls, result, timings);
225
+ if (sink !== undefined) {
226
+ lines.push(reportError === undefined
227
+ ? `${MSG_REPORT_WRITTEN} ${sink.path}`
228
+ : `${MSG_REPORT_FAILED} ${sink.path}: ${reportError}`);
229
+ }
230
+ return { code: compareExitCode(result), lines };
231
+ }
232
+ /** Compare the builds through the daemon on `port`. Returns the lines to print and the exit code. */
233
+ export async function runCompareCommand(options) {
234
+ const urls = {
235
+ reference: options.reference,
236
+ candidate: options.candidate,
237
+ ...(options.base === undefined ? {} : { base: options.base }),
238
+ };
239
+ const sink = options.report === undefined
240
+ ? undefined
241
+ : { path: options.report, write: options.writeReport ?? writeReportFile };
242
+ let readState;
243
+ if (options.state !== undefined) {
244
+ const loaded = await loadStateSources(options.state);
245
+ if ('error' in loaded) {
246
+ const reason = `${MSG_STATE_UNREADABLE} ${options.state}: ${loaded.error}`;
247
+ return render(options.json, urls, invalidComparison(reason, 0), undefined, sink);
248
+ }
249
+ readState = () => readStateSources(loaded, hostStateIo);
250
+ }
251
+ const connect = options.connect ?? connectOverSse;
252
+ let caller;
253
+ try {
254
+ caller = await connect(endpointFor(options.port, options.token));
255
+ }
256
+ catch (error) {
257
+ const why = error instanceof Error ? error.message : String(error);
258
+ const reason = `${MSG_NO_DAEMON} ${String(options.port)}: ${why}`;
259
+ return render(options.json, urls, invalidComparison(reason, 0), undefined, sink);
260
+ }
261
+ const open = async (url) => {
262
+ const lease = await acquireLease(caller, url, false, options.root);
263
+ if ('failed' in lease) {
264
+ throw new Error([`${MSG_LEASE_FAILED} ${url}`, ...lease.failed].join(' '));
265
+ }
266
+ return leasedPage(caller, url, lease.leased);
267
+ };
268
+ try {
269
+ const { result, timings } = await runCompare({
270
+ ...urls,
271
+ open,
272
+ sleep: options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
273
+ now: options.now ?? Date.now,
274
+ fetchText: options.fetchText ?? fetchText,
275
+ ...(readState === undefined ? {} : { readState }),
276
+ });
277
+ return render(options.json, urls, result, timings, sink);
278
+ }
279
+ catch (error) {
280
+ const reason = error instanceof Error ? error.message : String(error);
281
+ return render(options.json, urls, invalidComparison(reason, 0), undefined, sink);
282
+ }
283
+ finally {
284
+ await caller.close().catch(() => undefined);
285
+ }
286
+ }
287
+ /**
288
+ * The command. It needs a daemon, as an agent does: `ensureDaemon` attaches to the one on the port,
289
+ * or starts one. Nothing here stops a daemon, so an agent's MCP link stays up.
290
+ */
291
+ export async function handleCompare(parsed, ensureDaemon, out) {
292
+ const fail = (reason) => {
293
+ const sink = parsed.report === undefined ? undefined : { path: parsed.report, write: writeReportFile };
294
+ const result = render(parsed.json, parsed, invalidComparison(reason, 0), undefined, sink);
295
+ result.lines.forEach(out.line);
296
+ out.exit(result.code);
297
+ };
298
+ try {
299
+ await ensureDaemon(parsed.port);
300
+ }
301
+ catch (error) {
302
+ fail(error instanceof Error ? error.message : String(error));
303
+ return;
304
+ }
305
+ const token = pairingToken();
306
+ const root = callerArtifactRoot(process.cwd());
307
+ const result = await runCompareCommand({
308
+ ...parsed,
309
+ ...(token === undefined ? {} : { token }),
310
+ ...(root === undefined ? {} : { root }),
311
+ });
312
+ result.lines.forEach(out.line);
313
+ out.exit(result.code);
314
+ }
@@ -0,0 +1,61 @@
1
+ import { type CompareDriver } from '../../features/compare/compare-run.js';
2
+ import { type FileSystemPort } from '../../memory/project/fs/fs-port.js';
3
+ import { type ToolCaller } from './daemon-link/daemon-client.js';
4
+ /** How long to wait after each action before the page is read, so a short timer can fire. */
5
+ export declare const AGAINST_WAIT_MS = 300;
6
+ /** The explorer's action budget on the reference. */
7
+ export declare const AGAINST_MAX_ACTIONS = 150;
8
+ /** The tab one run drives. */
9
+ export interface LeasedTab {
10
+ url: string;
11
+ sessionId: string;
12
+ /** Release the lease when the run ends. */
13
+ closeLease: boolean;
14
+ confirmDangerous?: boolean;
15
+ }
16
+ /** One leased tab, as the compare driver. Every call goes through `reticle_run` on that tab. */
17
+ export declare function daemonDriver(caller: ToolCaller, tab: LeasedTab): CompareDriver;
18
+ /** The saved flows a run replays, with `--select` applied, and how many steps each has. */
19
+ export declare function flowsToReplay(fs: FileSystemPort, reticleRoot: string, select: readonly string[] | undefined, now: () => number): Promise<{
20
+ name: string;
21
+ steps: number;
22
+ }[]>;
23
+ export interface VerifyAgainstOptions {
24
+ port: number;
25
+ candidate: string;
26
+ reference: string;
27
+ flows: readonly {
28
+ name: string;
29
+ steps: number;
30
+ }[];
31
+ token?: string;
32
+ /** The caller's project `.reticle`, where the leased tabs write their runs. */
33
+ root?: string;
34
+ confirmDangerous?: boolean;
35
+ resultsJson?: string;
36
+ sleep: (ms: number) => Promise<void>;
37
+ /** Injected so a test can use its own transport. */
38
+ connect?: (endpoint: URL) => Promise<ToolCaller>;
39
+ write?: (path: string, text: string) => Promise<void>;
40
+ }
41
+ /** Compare the two builds through the daemon on `port`. Returns the lines to print and the exit code. */
42
+ export declare function runVerifyAgainst(options: VerifyAgainstOptions): Promise<{
43
+ code: number;
44
+ lines: string[];
45
+ }>;
46
+ /**
47
+ * The command. It needs a daemon, as an agent does: `ensureDaemon` attaches to the one on the port,
48
+ * or starts one. Nothing here stops a daemon, so an agent's MCP link stays up.
49
+ */
50
+ export declare function handleVerifyAgainst(parsed: {
51
+ url: string;
52
+ against: string;
53
+ port: number;
54
+ select?: string[];
55
+ resultsJson?: string;
56
+ confirmDangerous?: boolean;
57
+ }, ensureDaemon: (port: number) => Promise<void>, out: {
58
+ line: (text: string) => void;
59
+ fail: (text: string) => void;
60
+ exit: (code: number) => void;
61
+ }): Promise<void>;