@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
@@ -19,6 +19,7 @@
19
19
  * not ours to do.
20
20
  */
21
21
  import { posix, win32 } from 'node:path';
22
+ import { isReticleRegistration, serverInvocation } from '@reticlehq/init';
22
23
  export const AgentConfidence = {
23
24
  /** Documented by the vendor. Safe to create before the agent exists. */
24
25
  OFFICIAL: 'official',
@@ -34,11 +35,16 @@ export const AgentAction = {
34
35
  SKIP: 'skip',
35
36
  };
36
37
  const NPX = 'npx';
37
- const SERVER_PACKAGE = '@reticlehq/server';
38
- const MCP_SUBCOMMAND = 'mcp';
38
+ /** In every entry we write: the npx package name, or the installed launcher's path. */
39
+ const RETICLE_SCOPE = '@reticlehq';
39
40
  const RETICLE_KEY = 'reticle';
40
- /** The stdio entry, in the shape most clients expect. */
41
- const STDIO = { command: NPX, args: [SERVER_PACKAGE, MCP_SUBCOMMAND] };
41
+ /** The stdio `{ command, args }` that starts the MCP server. One rule for init and setup. */
42
+ function stdioFor(launcher) {
43
+ const [command = NPX, ...args] = serverInvocation(launcher);
44
+ return { command, args };
45
+ }
46
+ /** The stdio entry, in the shape most clients expect. `planAgentConfigs` sets its command. */
47
+ const STDIO = stdioFor();
42
48
  /**
43
49
  * The `PlatformPaths` row to plan for on a host that reports `platform`.
44
50
  *
@@ -234,7 +240,15 @@ export const AGENT_CLIENTS = [
234
240
  * mentions the word in a comment is not mistaken for a registration.
235
241
  */
236
242
  function yamlHasReticle(text) {
237
- return text.includes(`name: ${RETICLE_KEY}`) && text.includes(SERVER_PACKAGE);
243
+ return text.includes(`name: ${RETICLE_KEY}`) && text.includes(RETICLE_SCOPE);
244
+ }
245
+ /** Every string in an entry's `command` and `args`. */
246
+ function entryStrings(entry) {
247
+ if ('object' !== typeof entry || null === entry) {
248
+ return [];
249
+ }
250
+ const { command, args } = entry;
251
+ return [command, args].flat().filter((v) => 'string' === typeof v);
238
252
  }
239
253
  const forPlatform = (p, os) => p[os];
240
254
  /**
@@ -276,6 +290,8 @@ export function planAgentConfigs(input) {
276
290
  const join = joinFor(platform);
277
291
  const file = join(home, forPlatform(c.paths, platform));
278
292
  const detected = exists(join(home, forPlatform(c.marker, platform)));
293
+ const stdio = stdioFor(input.launcher);
294
+ const entry = c.entry === undefined ? undefined : { ...c.entry, ...stdio };
279
295
  // A NEW yaml file has nobody's formatting to destroy. An existing one does: `mcpServers` there
280
296
  // is a list of named entries, and a naive rewrite loses comments, anchors and ordering.
281
297
  if ('yaml-manual' === c.format) {
@@ -299,6 +315,7 @@ export function planAgentConfigs(input) {
299
315
  name: c.name,
300
316
  file,
301
317
  action: AgentAction.CREATE_YAML,
318
+ entry: stdio,
302
319
  why: 'no config yet, so a valid one can be written outright',
303
320
  };
304
321
  }
@@ -319,7 +336,7 @@ export function planAgentConfigs(input) {
319
336
  file,
320
337
  action: AgentAction.CREATE,
321
338
  key: c.key,
322
- entry: c.entry,
339
+ entry,
323
340
  why: detected
324
341
  ? 'installed, with no config yet'
325
342
  : 'a documented path, so a later install finds it already wired',
@@ -339,7 +356,7 @@ export function planAgentConfigs(input) {
339
356
  file,
340
357
  action: AgentAction.MANUAL,
341
358
  key: c.key,
342
- entry: c.entry,
359
+ entry,
343
360
  why: "the existing config is not plain JSON (comments or trailing commas), and rewriting it would reformat somebody else's file",
344
361
  };
345
362
  }
@@ -347,18 +364,28 @@ export function planAgentConfigs(input) {
347
364
  const existing = 'object' === typeof bucket && null !== bucket
348
365
  ? bucket[RETICLE_KEY]
349
366
  : undefined;
350
- if (existing !== undefined) {
351
- const ours = JSON.stringify(existing) === JSON.stringify(c.entry);
367
+ if (existing !== undefined && JSON.stringify(existing) === JSON.stringify(entry)) {
368
+ return {
369
+ id: c.id,
370
+ name: c.name,
371
+ file,
372
+ action: AgentAction.ALREADY,
373
+ key: c.key,
374
+ entry,
375
+ why: 'already registered',
376
+ };
377
+ }
378
+ // An older entry of our own (a floating npx command, a launcher that moved) is replaced. Any
379
+ // other `reticle` entry is somebody's own choice.
380
+ if (existing !== undefined && !isReticleRegistration(entryStrings(existing))) {
352
381
  return {
353
382
  id: c.id,
354
383
  name: c.name,
355
384
  file,
356
- action: ours ? AgentAction.ALREADY : AgentAction.MANUAL,
385
+ action: AgentAction.MANUAL,
357
386
  key: c.key,
358
- entry: c.entry,
359
- why: ours
360
- ? 'already registered'
361
- : 'a different `reticle` entry is there, and it is not ours to replace',
387
+ entry,
388
+ why: 'a different `reticle` entry is there, and it is not ours to replace',
362
389
  };
363
390
  }
364
391
  return {
@@ -367,7 +394,7 @@ export function planAgentConfigs(input) {
367
394
  file,
368
395
  action: AgentAction.MERGE,
369
396
  key: c.key,
370
- entry: c.entry,
397
+ entry,
371
398
  why: 'adding our key beside the servers already there',
372
399
  };
373
400
  });
@@ -0,0 +1,77 @@
1
+ import { McpClient } from '@reticlehq/init';
2
+ import { AgentClient } from '@reticlehq/core/telemetry';
3
+ import type { SetupMcpResult } from './setup-mcp.js';
4
+ /** What registration did for one client. */
5
+ export declare const AgentReg: {
6
+ /** The Claude Code plugin carries Reticle. */
7
+ readonly PLUGIN: "plugin";
8
+ readonly ADDED: "added";
9
+ readonly ALREADY: "already";
10
+ readonly FAILED: "failed";
11
+ readonly MANUAL: "manual";
12
+ /** Found, and Reticle is not in its config. Read-only callers (`status`) only. */
13
+ readonly MISSING: "missing";
14
+ };
15
+ export type AgentReg = (typeof AgentReg)[keyof typeof AgentReg];
16
+ export interface AgentRow {
17
+ readonly id: McpClient;
18
+ readonly reg: AgentReg;
19
+ /** The config path for a hand edit. */
20
+ readonly path?: string;
21
+ /** The command to retry a failed CLI registration, with the launcher that run used. */
22
+ readonly retry?: string;
23
+ /** The plugin AND a user-scope `reticle` entry: the client has two servers. */
24
+ readonly duplicate?: boolean;
25
+ /** The entry is the floating npx form: the note that names the commands that replace it. */
26
+ readonly stale?: string;
27
+ }
28
+ /**
29
+ * The rows for one `setupMcp` run, in its order.
30
+ *
31
+ * @param launcher the installed bin that run registered (`SetupMcpIo.launcher`), so a retry line
32
+ * names the same command.
33
+ */
34
+ export declare function agentRows(result: SetupMcpResult, launcher?: string): AgentRow[];
35
+ /** The "Your agents:" block: one line per client, each with its own next step. */
36
+ export declare function agentLines(rows: readonly AgentRow[]): string[];
37
+ /** The clients worth waiting for: the ones that have Reticle registered. */
38
+ export declare function awaitedClients(rows: readonly AgentRow[]): AgentClient[];
39
+ /** One agent, as `reticle status` reports it. */
40
+ export interface AgentStatus {
41
+ readonly name: string;
42
+ readonly connected: boolean;
43
+ /** The step still missing. Absent when connected. */
44
+ readonly next?: string;
45
+ /** The line a person reads: "Connected: Cursor ✓", or the name and the step still missing. */
46
+ readonly said: string;
47
+ }
48
+ /** Per client: connected, or the exact step still missing. */
49
+ export declare function agentStatuses(rows: readonly AgentRow[], connected: ReadonlySet<string>): AgentStatus[];
50
+ /** The lines the installer prints after its wait. */
51
+ export declare function connectionLines(rows: readonly AgentRow[], connected: ReadonlySet<string>): string[];
52
+ /** The clock the wait runs on. Injected, so a test does not wait. */
53
+ export interface WaitClock {
54
+ now(): number;
55
+ sleep(ms: number): Promise<void>;
56
+ }
57
+ /**
58
+ * Poll `read` until every client in `want` has connected, or `budgetMs` has passed. Returns the
59
+ * last read. Bounded: it never waits longer than the budget.
60
+ */
61
+ export declare function waitForAgents(want: readonly string[], read: () => ReadonlySet<string>, clock: WaitClock, budgetMs: number, pollMs: number): Promise<ReadonlySet<string>>;
62
+ /** `$CLAUDE_CONFIG_DIR`, else home: where Claude Code keeps `.claude.json`. */
63
+ export declare function claudeStateDir(): string;
64
+ /** What `installedAgentRows` reads. It never writes. */
65
+ export interface AgentProbe {
66
+ exists(path: string): boolean;
67
+ readFile(path: string): string | null;
68
+ homeDir(): string;
69
+ }
70
+ /**
71
+ * The agents on this machine and whether Reticle is in each config, read only. For `reticle status`,
72
+ * which must not register anything and must not spawn a client CLI.
73
+ *
74
+ * @param claudeStateDir the directory that holds `.claude.json`: `$CLAUDE_CONFIG_DIR`, else home.
75
+ * @param launcher the installed bin a new registration would use, for the stale-entry fix.
76
+ */
77
+ export declare function installedAgentRows(io: AgentProbe, projectDir: string | undefined, pluginActive: boolean, claudeStateDir?: string, launcher?: string): AgentRow[];
@@ -0,0 +1,284 @@
1
+ /**
2
+ * One next step for each coding agent, and whether each one really connected.
3
+ *
4
+ * Registration writes a config. An agent reads that config only at a time the client decides, so
5
+ * "registered" is not "the agent has the tools". This file names, per client, the one step that
6
+ * loads the tools, and reads which agents did connect (`agents-connected.ts`) to say so.
7
+ *
8
+ * Only the Claude Code plugin gets "no restart". Its docs say `/reload-plugins` loads it. For every
9
+ * other client the step is the conservative one: their docs do not say a running session picks up a
10
+ * new server.
11
+ */
12
+ import { join } from 'node:path';
13
+ import { homedir } from 'node:os';
14
+ import { claudeAddCommand, claudeHasReticle, claudeRemoveUserCommand, claudeStaleEntryNote, claudeUserEntryIsFloating, clientSpec, codexNamesOurServer, ConfigFormat, detectMcpClients, McpClient, } from '@reticlehq/init';
15
+ import { MCP_SERVER_NAME } from '@reticlehq/core';
16
+ import { AgentClient } from '@reticlehq/core/telemetry';
17
+ /** What registration did for one client. */
18
+ export const AgentReg = {
19
+ /** The Claude Code plugin carries Reticle. */
20
+ PLUGIN: 'plugin',
21
+ ADDED: 'added',
22
+ ALREADY: 'already',
23
+ FAILED: 'failed',
24
+ MANUAL: 'manual',
25
+ /** Found, and Reticle is not in its config. Read-only callers (`status`) only. */
26
+ MISSING: 'missing',
27
+ };
28
+ /** The one table of client to next step. Change a step here, nowhere else. */
29
+ const AGENT_STEPS = {
30
+ [McpClient.CLAUDE_CODE]: {
31
+ name: 'Claude Code',
32
+ agent: AgentClient.CLAUDE_CODE,
33
+ step: 'restart Claude Code, then /mcp shows reticle',
34
+ },
35
+ [McpClient.CURSOR]: {
36
+ name: 'Cursor',
37
+ agent: AgentClient.CURSOR,
38
+ step: 'restart Cursor, then turn Reticle on in Settings › MCP',
39
+ },
40
+ [McpClient.CODEX]: {
41
+ name: 'Codex',
42
+ agent: AgentClient.CODEX,
43
+ step: 'restart Codex, then /mcp shows reticle',
44
+ },
45
+ [McpClient.GEMINI]: {
46
+ name: 'Gemini CLI',
47
+ agent: AgentClient.GEMINI_CLI,
48
+ step: 'restart Gemini CLI, then /mcp shows reticle',
49
+ },
50
+ [McpClient.WINDSURF]: {
51
+ name: 'Windsurf',
52
+ agent: AgentClient.WINDSURF,
53
+ step: 'restart Windsurf, then turn Reticle on in its MCP settings',
54
+ },
55
+ [McpClient.VSCODE]: {
56
+ name: 'VS Code',
57
+ agent: AgentClient.VSCODE,
58
+ step: 'run "Developer: Reload Window" in VS Code',
59
+ },
60
+ [McpClient.OPENCODE]: {
61
+ name: 'OpenCode',
62
+ agent: AgentClient.OPENCODE,
63
+ step: 'restart OpenCode',
64
+ },
65
+ [McpClient.ANTIGRAVITY]: {
66
+ name: 'Antigravity',
67
+ agent: AgentClient.ANTIGRAVITY,
68
+ step: 'restart Antigravity',
69
+ },
70
+ };
71
+ const NextStepCopy = {
72
+ HEADING: 'Your agents:',
73
+ PLUGIN_ACTIVE: 'plugin active: type /reload-plugins if it is open',
74
+ PLUGIN_NOT_CONNECTED: 'start Claude Code, or type /reload-plugins in an open session',
75
+ ADDED: 'added: ',
76
+ ALREADY: 'already set up',
77
+ NOT_ADDED: 'not added: ',
78
+ FAILED: 'registration failed: ',
79
+ FAILED_FILE: 'check the permissions of its config file, then run `reticle setup mcp`',
80
+ MANUAL_HEAD: 'add the reticle entry to ',
81
+ MANUAL_TAIL: ' by hand',
82
+ MISSING: 'not added: run `reticle setup mcp`',
83
+ CONNECTED_HEAD: 'Connected: ',
84
+ CONNECTED_TAIL: ' ✓',
85
+ NOT_CONNECTED: ' not connected yet: ',
86
+ DUPLICATE: ' ⚠ a user-scope reticle server is registered too, so Claude Code has two. Remove it: ',
87
+ STALE: ' ⚠ ',
88
+ };
89
+ const NAME_COLUMN = Math.max(...Object.values(AGENT_STEPS).map((s) => s.name.length)) + 2;
90
+ /**
91
+ * The rows for one `setupMcp` run, in its order.
92
+ *
93
+ * @param launcher the installed bin that run registered (`SetupMcpIo.launcher`), so a retry line
94
+ * names the same command.
95
+ */
96
+ export function agentRows(result, launcher) {
97
+ const known = (id) => id in AGENT_STEPS;
98
+ const rows = [];
99
+ for (const id of result.detected) {
100
+ if (!known(id)) {
101
+ continue;
102
+ }
103
+ if (result.pluginActive.includes(id)) {
104
+ rows.push(pluginRow(id, result.duplicates.includes(id)));
105
+ continue;
106
+ }
107
+ const manual = result.manual.find((m) => m.id === id);
108
+ if (manual !== undefined) {
109
+ rows.push({ id, reg: AgentReg.MANUAL, path: manual.configPath });
110
+ }
111
+ else if (result.failed.includes(id)) {
112
+ rows.push(McpClient.CLAUDE_CODE === id
113
+ ? { id, reg: AgentReg.FAILED, retry: claudeAddCommand(launcher).display }
114
+ : { id, reg: AgentReg.FAILED });
115
+ }
116
+ else if (result.alreadyThere.includes(id)) {
117
+ rows.push(alreadyRow(id, result.stale.includes(id), launcher));
118
+ }
119
+ else if (result.registered.includes(id)) {
120
+ rows.push({ id, reg: AgentReg.ADDED });
121
+ }
122
+ }
123
+ return rows;
124
+ }
125
+ function alreadyRow(id, stale, launcher) {
126
+ return stale
127
+ ? { id, reg: AgentReg.ALREADY, stale: claudeStaleEntryNote(launcher) }
128
+ : { id, reg: AgentReg.ALREADY };
129
+ }
130
+ function pluginRow(id, duplicate) {
131
+ return duplicate ? { id, reg: AgentReg.PLUGIN, duplicate } : { id, reg: AgentReg.PLUGIN };
132
+ }
133
+ function failedStep(row) {
134
+ return row.retry === undefined ? NextStepCopy.FAILED_FILE : `run \`${row.retry}\``;
135
+ }
136
+ /** What one row says before anything is known about the connection. */
137
+ function registrationText(row) {
138
+ const { step } = AGENT_STEPS[row.id];
139
+ switch (row.reg) {
140
+ case AgentReg.PLUGIN:
141
+ return NextStepCopy.PLUGIN_ACTIVE;
142
+ case AgentReg.ADDED:
143
+ return `${NextStepCopy.ADDED}${step}`;
144
+ case AgentReg.ALREADY:
145
+ return NextStepCopy.ALREADY;
146
+ case AgentReg.FAILED:
147
+ return `${NextStepCopy.FAILED}${failedStep(row)}`;
148
+ case AgentReg.MANUAL:
149
+ return `${NextStepCopy.NOT_ADDED}${NextStepCopy.MANUAL_HEAD}${row.path ?? ''}${NextStepCopy.MANUAL_TAIL}`;
150
+ case AgentReg.MISSING:
151
+ return NextStepCopy.MISSING;
152
+ }
153
+ }
154
+ /** The "Your agents:" block: one line per client, each with its own next step. */
155
+ export function agentLines(rows) {
156
+ if (0 === rows.length) {
157
+ return [];
158
+ }
159
+ return [
160
+ NextStepCopy.HEADING,
161
+ ...rows.flatMap((row) => {
162
+ const lines = [` ${AGENT_STEPS[row.id].name.padEnd(NAME_COLUMN)}${registrationText(row)}`];
163
+ if (true === row.duplicate) {
164
+ lines.push(`${NextStepCopy.DUPLICATE}${claudeRemoveUserCommand()}`);
165
+ }
166
+ if (row.stale !== undefined) {
167
+ lines.push(`${NextStepCopy.STALE}${row.stale}`);
168
+ }
169
+ return lines;
170
+ }),
171
+ ];
172
+ }
173
+ /** A row whose client has Reticle in its config, so a connection can be waited for. */
174
+ function isRegistered(row) {
175
+ return AgentReg.PLUGIN === row.reg || AgentReg.ADDED === row.reg || AgentReg.ALREADY === row.reg;
176
+ }
177
+ /** The clients worth waiting for: the ones that have Reticle registered. */
178
+ export function awaitedClients(rows) {
179
+ return rows.filter(isRegistered).map((row) => AGENT_STEPS[row.id].agent);
180
+ }
181
+ function missingStep(row) {
182
+ if (AgentReg.PLUGIN === row.reg) {
183
+ return NextStepCopy.PLUGIN_NOT_CONNECTED;
184
+ }
185
+ if (isRegistered(row)) {
186
+ return AGENT_STEPS[row.id].step;
187
+ }
188
+ return registrationText(row);
189
+ }
190
+ /** Per client: connected, or the exact step still missing. */
191
+ export function agentStatuses(rows, connected) {
192
+ return rows.map((row) => {
193
+ const { name, agent } = AGENT_STEPS[row.id];
194
+ if (isRegistered(row) && connected.has(agent)) {
195
+ return {
196
+ name,
197
+ connected: true,
198
+ said: `${NextStepCopy.CONNECTED_HEAD}${name}${NextStepCopy.CONNECTED_TAIL}`,
199
+ };
200
+ }
201
+ const next = missingStep(row);
202
+ const said = isRegistered(row)
203
+ ? `${name}${NextStepCopy.NOT_CONNECTED}${next}`
204
+ : `${name} ${next}`;
205
+ return { name, connected: false, next, said };
206
+ });
207
+ }
208
+ /** The lines the installer prints after its wait. */
209
+ export function connectionLines(rows, connected) {
210
+ return agentStatuses(rows, connected).map((status) => status.said);
211
+ }
212
+ /**
213
+ * Poll `read` until every client in `want` has connected, or `budgetMs` has passed. Returns the
214
+ * last read. Bounded: it never waits longer than the budget.
215
+ */
216
+ export async function waitForAgents(want, read, clock, budgetMs, pollMs) {
217
+ const start = clock.now();
218
+ let seen = read();
219
+ while (!want.every((client) => seen.has(client)) && clock.now() - start < budgetMs) {
220
+ await clock.sleep(pollMs);
221
+ seen = read();
222
+ }
223
+ return seen;
224
+ }
225
+ const CLAUDE_CONFIG_DIR_ENV = 'CLAUDE_CONFIG_DIR';
226
+ /** `$CLAUDE_CONFIG_DIR`, else home: where Claude Code keeps `.claude.json`. */
227
+ export function claudeStateDir() {
228
+ return process.env[CLAUDE_CONFIG_DIR_ENV] ?? homedir();
229
+ }
230
+ const CLAUDE_STATE_FILE = '.claude.json';
231
+ /**
232
+ * Does this client's config name a `reticle` server, in any shape?
233
+ *
234
+ * Presence, not "the entry we would write now". An entry that starts an installed launcher, or an
235
+ * older npx entry, still starts Reticle. `setup mcp` repairs a stale entry; `status` only reports
236
+ * whether one is there. A file that does not parse reads as absent.
237
+ */
238
+ function configNamesReticle(spec, existing) {
239
+ if (ConfigFormat.TOML === spec.format) {
240
+ return codexNamesOurServer(existing, spec.serversKey);
241
+ }
242
+ if (null === existing) {
243
+ return false;
244
+ }
245
+ try {
246
+ const parsed = JSON.parse(existing);
247
+ const servers = 'object' === typeof parsed && null !== parsed
248
+ ? parsed[spec.serversKey]
249
+ : undefined;
250
+ return 'object' === typeof servers && null !== servers && MCP_SERVER_NAME in servers;
251
+ }
252
+ catch {
253
+ return false;
254
+ }
255
+ }
256
+ /**
257
+ * The agents on this machine and whether Reticle is in each config, read only. For `reticle status`,
258
+ * which must not register anything and must not spawn a client CLI.
259
+ *
260
+ * @param claudeStateDir the directory that holds `.claude.json`: `$CLAUDE_CONFIG_DIR`, else home.
261
+ * @param launcher the installed bin a new registration would use, for the stale-entry fix.
262
+ */
263
+ export function installedAgentRows(io, projectDir, pluginActive, claudeStateDir = io.homeDir(), launcher) {
264
+ const rows = [];
265
+ if (pluginActive) {
266
+ // A user-scope entry next to the plugin is a second server.
267
+ rows.push(pluginRow(McpClient.CLAUDE_CODE, claudeHasReticle(io, undefined, claudeStateDir)));
268
+ }
269
+ else if (claudeHasReticle(io, projectDir, claudeStateDir)) {
270
+ rows.push(alreadyRow(McpClient.CLAUDE_CODE, claudeUserEntryIsFloating(io, claudeStateDir), launcher));
271
+ }
272
+ else if (io.exists(join(claudeStateDir, CLAUDE_STATE_FILE))) {
273
+ rows.push({ id: McpClient.CLAUDE_CODE, reg: AgentReg.MISSING });
274
+ }
275
+ for (const client of detectMcpClients(io)) {
276
+ rows.push({
277
+ id: client.id,
278
+ reg: configNamesReticle(clientSpec(client.id), client.existing)
279
+ ? AgentReg.ALREADY
280
+ : AgentReg.MISSING,
281
+ });
282
+ }
283
+ return rows;
284
+ }
@@ -13,8 +13,11 @@ import { AgentAction, AGENT_CLIENTS, joinFor, parentOf, } from './agent-configs.
13
13
  /** Two spaces, because that is what every one of these files already uses. */
14
14
  const INDENT = 2;
15
15
  const RETICLE_KEY = 'reticle';
16
- /** A fresh Continue config. YAML is only ever created, never edited. */
17
- const CONTINUE_YAML = 'mcpServers:\n - name: reticle\n type: stdio\n command: npx\n args: ["@reticlehq/server", "mcp"]\n';
16
+ /**
17
+ * A fresh Continue config. YAML is only ever created, never edited. The args are a JSON array,
18
+ * which is valid YAML flow syntax and keeps a Windows path escaped.
19
+ */
20
+ const continueYaml = (entry) => `mcpServers:\n - name: ${RETICLE_KEY}\n type: stdio\n command: ${String(entry['command'])}\n args: ${JSON.stringify(entry['args'])}\n`;
18
21
  /**
19
22
  * Write what the plan says to write, and nothing else.
20
23
  *
@@ -32,8 +35,8 @@ export function applyAgentPlan(plan, io) {
32
35
  }
33
36
  try {
34
37
  io.mkdirp(parentOf(step.file));
35
- if (AgentAction.CREATE_YAML === step.action) {
36
- io.writeFile(step.file, CONTINUE_YAML);
38
+ if (AgentAction.CREATE_YAML === step.action && undefined !== step.entry) {
39
+ io.writeFile(step.file, continueYaml(step.entry));
37
40
  return { ...base, action: 'created' };
38
41
  }
39
42
  const key = step.key;
@@ -99,10 +102,12 @@ export function applyAgentSkills(io, where) {
99
102
  const join = joinFor(where.platform);
100
103
  for (const client of AGENT_CLIENTS) {
101
104
  const dir = client.skillDir;
102
- if (undefined === dir)
105
+ if (undefined === dir) {
103
106
  continue;
104
- if (!io.exists(join(where.home, client.marker[where.platform])))
107
+ }
108
+ if (!io.exists(join(where.home, client.marker[where.platform]))) {
105
109
  continue;
110
+ }
106
111
  try {
107
112
  const target = join(where.home, dir);
108
113
  io.mkdirp(target);
@@ -13,6 +13,7 @@ declare const HandedOverSchema: z.ZodObject<{
13
13
  pid: z.ZodNumber;
14
14
  url: z.ZodString;
15
15
  appDir: z.ZodString;
16
+ bridgePort: z.ZodOptional<z.ZodNumber>;
16
17
  }, z.core.$strip>;
17
18
  export type HandedOver = z.infer<typeof HandedOverSchema>;
18
19
  /**
@@ -32,6 +33,14 @@ export declare function handedOverUrl(dir: string, appDir: string, deps: {
32
33
  alive: (pid: number) => boolean;
33
34
  answers: (url: string) => Promise<boolean>;
34
35
  }): Promise<string | undefined>;
36
+ /**
37
+ * True when the live server `init` handed over for `appDir` was started for a daemon port other than
38
+ * `bridgePort`. Attaching to it leaves the page dialling the old port, even when no daemon on that
39
+ * port is left to retire. A record with no port gives false, as before.
40
+ */
41
+ export declare function handedOverToOtherPort(dir: string, appDir: string, bridgePort: number, deps: {
42
+ alive: (pid: number) => boolean;
43
+ }): boolean;
35
44
  /**
36
45
  * Stop the server `init` handed over for `appDir`, and forget it. True when one was stopped.
37
46
  *
@@ -34,6 +34,11 @@ const HandedOverSchema = z.object({
34
34
  pid: z.number().int().positive(),
35
35
  url: z.string().min(1),
36
36
  appDir: z.string().min(1),
37
+ /**
38
+ * The daemon port the server was started for. Absent in a record from an older build. Reticle's
39
+ * static server adds a snippet that dials this port, so it cannot follow a port move.
40
+ */
41
+ bridgePort: z.number().int().positive().optional(),
37
42
  });
38
43
  /**
39
44
  * Written when `init` leaves a server running, so the next `init` can attach to it.
@@ -70,6 +75,18 @@ export async function handedOverUrl(dir, appDir, deps) {
70
75
  return undefined;
71
76
  return (await deps.answers(record.url)) ? record.url : undefined;
72
77
  }
78
+ /**
79
+ * True when the live server `init` handed over for `appDir` was started for a daemon port other than
80
+ * `bridgePort`. Attaching to it leaves the page dialling the old port, even when no daemon on that
81
+ * port is left to retire. A record with no port gives false, as before.
82
+ */
83
+ export function handedOverToOtherPort(dir, appDir, bridgePort, deps) {
84
+ const record = readRecord(join(dir, recordName(appDir)));
85
+ if (undefined === record || record.appDir !== appDir || !deps.alive(record.pid)) {
86
+ return false;
87
+ }
88
+ return undefined !== record.bridgePort && record.bridgePort !== bridgePort;
89
+ }
73
90
  /**
74
91
  * Stop the server `init` handed over for `appDir`, and forget it. True when one was stopped.
75
92
  *
@@ -8,8 +8,11 @@
8
8
  * starts `npm run dev`, and the rest of setup (wait, open, prove the connect) runs unchanged.
9
9
  *
10
10
  * It is run as its own process (`node static-page-server.js --dir <app>`), not inside init, because it
11
- * has to outlive init exactly like any handed-over dev server. It imports nothing but Node, so the
12
- * built file runs on its own.
11
+ * has to outlive init exactly like any handed-over dev server. It imports only Node and
12
+ * `@reticlehq/init`, so the built file runs on its own.
13
+ *
14
+ * It adds the connect snippet to each HTML page it serves, so init does not edit the file the user
15
+ * hands over (#1544). The file on disk stays byte-identical.
13
16
  *
14
17
  * Loopback only, on both families: a page served to the LAN would publish the pairing token the
15
18
  * snippet carries.
@@ -21,9 +24,16 @@ export interface StaticPageServer {
21
24
  readonly url: string;
22
25
  close(): Promise<void>;
23
26
  }
27
+ /**
28
+ * The connect literal for the page in `root`: the bridge port, and the project id its `.reticle.json`
29
+ * names. The same literal init wrote into the page before #1544.
30
+ */
31
+ export declare function staticPageConnect(root: string, bridgePort: number): string;
24
32
  export declare function startStaticPageServer(opts: {
25
33
  root: string;
26
34
  port: number;
35
+ /** The connect literal to add to each HTML page. Absent: pages are served as written. */
36
+ connect?: string | undefined;
27
37
  }): Promise<StaticPageServer>;
28
38
  /**
29
39
  * The command setup runs for a page with no dev server of its own, or undefined when this is not
@@ -32,4 +42,6 @@ export declare function startStaticPageServer(opts: {
32
42
  export declare function staticPageDevCommand(opts: {
33
43
  appDir: string;
34
44
  isStaticPage: boolean;
45
+ /** The daemon port the added snippet dials. Absent: the page is served as written. */
46
+ bridgePort?: number | undefined;
35
47
  }): string | undefined;