@reticlehq/server 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (513) hide show
  1. package/SKILL.md +93 -111
  2. package/dist/bridge/auth-failure-reason.d.ts +6 -2
  3. package/dist/bridge/auth-failure-reason.js +15 -8
  4. package/dist/bridge/bridge.d.ts +18 -14
  5. package/dist/bridge/bridge.js +248 -165
  6. package/dist/bridge/bridge.test-harness.d.ts +2 -0
  7. package/dist/bridge/bridge.test-harness.js +8 -1
  8. package/dist/bridge/pairing-token.d.ts +5 -0
  9. package/dist/bridge/pairing-token.js +28 -0
  10. package/dist/bridge/protocol-skew.d.ts +37 -0
  11. package/dist/bridge/protocol-skew.js +45 -0
  12. package/dist/capsule/capsule-store.d.ts +8 -7
  13. package/dist/capsule/capsule-store.js +1 -1
  14. package/dist/capsule/causal-summary.d.ts +2 -2
  15. package/dist/capsule/causal-summary.js +7 -2
  16. package/dist/chromium-launch-options.d.ts +28 -0
  17. package/dist/chromium-launch-options.js +29 -0
  18. package/dist/cli/cli-doctor.js +39 -1
  19. package/dist/cli/cli-flow-commands.d.ts +3 -1
  20. package/dist/cli/cli-flow-commands.js +34 -4
  21. package/dist/cli/cli-kill.d.ts +2 -1
  22. package/dist/cli/cli-launch.d.ts +11 -1
  23. package/dist/cli/cli-launch.js +59 -10
  24. package/dist/cli/cli-parse.d.ts +17 -1
  25. package/dist/cli/cli-parse.js +238 -12
  26. package/dist/cli/cli-update-commands.js +20 -1
  27. package/dist/cli/cli-verify.d.ts +2 -1
  28. package/dist/cli/cli-verify.js +5 -4
  29. package/dist/cli/cloud-cli.js +428 -253
  30. package/dist/cli/cloud-keystore.d.ts +37 -0
  31. package/dist/cli/cloud-keystore.js +97 -0
  32. package/dist/cli/cloud-kit.d.ts +37 -0
  33. package/dist/cli/cloud-kit.js +121 -0
  34. package/dist/cli/cloud-login.d.ts +17 -0
  35. package/dist/cli/cloud-login.js +183 -0
  36. package/dist/cli/cloud-session.d.ts +48 -0
  37. package/dist/cli/cloud-session.js +53 -0
  38. package/dist/cli/config-discovery.d.ts +2 -1
  39. package/dist/cli/config-discovery.js +1 -0
  40. package/dist/cli/daemon-start-options.d.ts +32 -0
  41. package/dist/cli/daemon-start-options.js +38 -0
  42. package/dist/cli/device-flow.d.ts +76 -0
  43. package/dist/cli/device-flow.js +56 -0
  44. package/dist/cli/doctor-rows.d.ts +12 -1
  45. package/dist/cli/doctor-rows.js +12 -1
  46. package/dist/cli/drive-attach.d.ts +13 -0
  47. package/dist/cli/drive-attach.js +18 -0
  48. package/dist/cli/drive-command.js +7 -3
  49. package/dist/cli/gate-exit.d.ts +21 -0
  50. package/dist/cli/gate-exit.js +21 -0
  51. package/dist/cli/gate-hook-message.d.ts +33 -0
  52. package/dist/cli/gate-hook-message.js +46 -0
  53. package/dist/cli/mcp-command.d.ts +25 -0
  54. package/dist/cli/mcp-command.js +174 -0
  55. package/dist/cli/project-name.d.ts +30 -0
  56. package/dist/cli/project-name.js +44 -0
  57. package/dist/cli/sibling-ports.d.ts +37 -0
  58. package/dist/cli/sibling-ports.js +56 -0
  59. package/dist/cli/status-next-action.d.ts +14 -0
  60. package/dist/cli/status-next-action.js +4 -4
  61. package/dist/cli.d.ts +1 -0
  62. package/dist/cli.js +167 -186
  63. package/dist/cloud/cloud-config.d.ts +24 -2
  64. package/dist/cloud/cloud-config.js +64 -5
  65. package/dist/cloud/cloud-sync.d.ts +16 -5
  66. package/dist/cloud/cloud-sync.js +64 -1
  67. package/dist/cloud/sync-cycle.d.ts +110 -0
  68. package/dist/cloud/sync-cycle.js +270 -0
  69. package/dist/cloud/sync-daemon.d.ts +69 -0
  70. package/dist/cloud/sync-daemon.js +260 -0
  71. package/dist/cloud/sync-disk.d.ts +9 -0
  72. package/dist/cloud/sync-disk.js +191 -0
  73. package/dist/cloud/sync-hash.d.ts +2 -0
  74. package/dist/cloud/sync-hash.js +35 -0
  75. package/dist/crawl/crawl-tools.js +5 -3
  76. package/dist/crawl/crawl.d.ts +12 -13
  77. package/dist/crawl/crawl.js +25 -3
  78. package/dist/daemon/daemon-resolve.d.ts +122 -0
  79. package/dist/daemon/daemon-resolve.js +187 -0
  80. package/dist/daemon/dev-servers.d.ts +15 -0
  81. package/dist/daemon/dev-servers.js +68 -0
  82. package/dist/daemon/free-port.d.ts +29 -0
  83. package/dist/daemon/free-port.js +55 -0
  84. package/dist/daemon/heartbeat.d.ts +0 -4
  85. package/dist/daemon/heartbeat.js +2 -2
  86. package/dist/daemon/wake-decision.d.ts +32 -0
  87. package/dist/daemon/wake-decision.js +38 -0
  88. package/dist/dev/stale-issue-guard.d.ts +0 -2
  89. package/dist/dev/stale-issue-guard.js +1 -1
  90. package/dist/domain/domain-tools.js +2 -2
  91. package/dist/events/contradictions.d.ts +59 -0
  92. package/dist/events/contradictions.js +253 -27
  93. package/dist/events/declared.d.ts +17 -0
  94. package/dist/events/declared.js +43 -1
  95. package/dist/events/echo-mismatch.js +65 -1
  96. package/dist/events/event-filters.d.ts +8 -0
  97. package/dist/events/event-filters.js +19 -2
  98. package/dist/events/observed-in-window.d.ts +12 -0
  99. package/dist/events/observed-in-window.js +17 -0
  100. package/dist/events/predicate-asks.d.ts +13 -0
  101. package/dist/events/predicate-asks.js +22 -0
  102. package/dist/events/predicate-eval.js +117 -27
  103. package/dist/events/predicate-parse.d.ts +0 -6
  104. package/dist/events/predicate-parse.js +43 -3
  105. package/dist/events/predicate-precheck.d.ts +8 -0
  106. package/dist/events/predicate-precheck.js +41 -0
  107. package/dist/events/predicate-route.d.ts +14 -0
  108. package/dist/events/predicate-route.js +36 -8
  109. package/dist/events/predicate-schema.d.ts +44 -0
  110. package/dist/events/predicate-schema.js +126 -23
  111. package/dist/events/predicate.d.ts +20 -0
  112. package/dist/events/predicate.js +77 -6
  113. package/dist/events/split-text-miss.d.ts +30 -0
  114. package/dist/events/split-text-miss.js +44 -0
  115. package/dist/flows/coverage.d.ts +0 -8
  116. package/dist/flows/coverage.js +1 -1
  117. package/dist/flows/decision.d.ts +5 -1
  118. package/dist/flows/decision.js +33 -7
  119. package/dist/flows/flake.d.ts +6 -8
  120. package/dist/flows/flake.js +1 -1
  121. package/dist/flows/flow-intent.d.ts +52 -0
  122. package/dist/flows/flow-intent.js +123 -0
  123. package/dist/flows/flow-memory-consult.d.ts +55 -0
  124. package/dist/flows/flow-memory-consult.js +38 -0
  125. package/dist/flows/flow-replay-run.d.ts +18 -7
  126. package/dist/flows/flow-replay-run.js +263 -23
  127. package/dist/flows/flow-replay.js +11 -2
  128. package/dist/flows/flow-step-runners.d.ts +8 -0
  129. package/dist/flows/flow-step-runners.js +8 -2
  130. package/dist/flows/flow-store-for-session.d.ts +31 -0
  131. package/dist/flows/flow-store-for-session.js +33 -0
  132. package/dist/flows/flow-success.js +15 -3
  133. package/dist/flows/flow-tools.js +87 -33
  134. package/dist/flows/flows.d.ts +14 -1
  135. package/dist/flows/flows.js +502 -24
  136. package/dist/flows/heal-run.js +5 -2
  137. package/dist/flows/predicate-to-expect.d.ts +17 -12
  138. package/dist/flows/predicate-to-expect.js +36 -15
  139. package/dist/flows/recordings.d.ts +13 -1
  140. package/dist/flows/recordings.js +17 -2
  141. package/dist/flows/replay.d.ts +22 -2
  142. package/dist/flows/replay.js +28 -2
  143. package/dist/flows/server-verify.js +16 -2
  144. package/dist/flows/verify-change-tools.js +9 -3
  145. package/dist/honesty/blind-spots.d.ts +51 -15
  146. package/dist/honesty/blind-spots.js +64 -4
  147. package/dist/honesty/feature-capture.d.ts +150 -0
  148. package/dist/honesty/feature-capture.js +233 -0
  149. package/dist/honesty/honesty.d.ts +24 -0
  150. package/dist/honesty/honesty.js +25 -1
  151. package/dist/honesty/instrumentation-gaps.d.ts +39 -6
  152. package/dist/honesty/instrumentation-gaps.js +88 -5
  153. package/dist/honesty/tool-hit-rate.d.ts +86 -0
  154. package/dist/honesty/tool-hit-rate.js +90 -0
  155. package/dist/honesty/undeclared-change.d.ts +51 -0
  156. package/dist/honesty/undeclared-change.js +56 -0
  157. package/dist/honesty/verified.d.ts +16 -0
  158. package/dist/honesty/verified.js +84 -5
  159. package/dist/http-server.d.ts +0 -1
  160. package/dist/http-server.js +13 -1
  161. package/dist/hunt/hunt-report.d.ts +0 -2
  162. package/dist/hunt/hunt-report.js +1 -1
  163. package/dist/impact/impact-recorder.d.ts +31 -8
  164. package/dist/impact/impact-recorder.js +104 -21
  165. package/dist/impact/impact-store.d.ts +13 -4
  166. package/dist/impact/impact-store.js +44 -3
  167. package/dist/index.d.ts +4 -1
  168. package/dist/index.js +113 -7
  169. package/dist/init/agent-rules.d.ts +30 -6
  170. package/dist/init/agent-rules.js +54 -13
  171. package/dist/init/astro-patch.d.ts +16 -0
  172. package/dist/init/astro-patch.js +28 -0
  173. package/dist/init/capabilities.d.ts +4 -3
  174. package/dist/init/capabilities.js +23 -3
  175. package/dist/init/closing-hint.d.ts +36 -0
  176. package/dist/init/closing-hint.js +120 -0
  177. package/dist/init/confirm.d.ts +27 -28
  178. package/dist/init/confirm.js +51 -11
  179. package/dist/init/cra.d.ts +34 -5
  180. package/dist/init/cra.js +96 -25
  181. package/dist/init/csp-check.js +17 -2
  182. package/dist/init/csp-doctor.d.ts +8 -1
  183. package/dist/init/csp-doctor.js +8 -3
  184. package/dist/init/dev-script.d.ts +50 -0
  185. package/dist/init/dev-script.js +66 -0
  186. package/dist/init/format-generated.d.ts +18 -0
  187. package/dist/init/format-generated.js +39 -0
  188. package/dist/init/install-hint.d.ts +9 -0
  189. package/dist/init/install-hint.js +29 -0
  190. package/dist/init/mcp-clients.d.ts +7 -0
  191. package/dist/init/mcp-clients.js +7 -0
  192. package/dist/init/mcp.d.ts +17 -6
  193. package/dist/init/mcp.js +27 -11
  194. package/dist/init/node-io.js +11 -1
  195. package/dist/init/plan-framework.d.ts +0 -5
  196. package/dist/init/plan-framework.js +147 -37
  197. package/dist/init/plan.d.ts +30 -37
  198. package/dist/init/plan.js +50 -60
  199. package/dist/init/preflight.d.ts +28 -0
  200. package/dist/init/preflight.js +38 -0
  201. package/dist/init/refresh-rules.d.ts +39 -0
  202. package/dist/init/refresh-rules.js +51 -0
  203. package/dist/init/run.d.ts +32 -35
  204. package/dist/init/run.js +151 -202
  205. package/dist/init/slash-command.d.ts +1 -1
  206. package/dist/init/snippets.js +90 -31
  207. package/dist/init/vite-config.d.ts +1 -1
  208. package/dist/init/vite-config.js +39 -25
  209. package/dist/init/workspace-apps.d.ts +17 -10
  210. package/dist/init/workspace-apps.js +110 -0
  211. package/dist/input/network-mock-tools.js +3 -6
  212. package/dist/input/real-input.d.ts +2 -0
  213. package/dist/input/real-input.js +28 -7
  214. package/dist/input/scroll-find.d.ts +7 -4
  215. package/dist/input/scroll-find.js +63 -25
  216. package/dist/input/scroll-tools.js +4 -6
  217. package/dist/input/viewport-tools.js +5 -4
  218. package/dist/intent/inline-intent.d.ts +37 -0
  219. package/dist/intent/inline-intent.js +193 -0
  220. package/dist/intent/intent-shard-store.d.ts +72 -0
  221. package/dist/intent/intent-shard-store.js +203 -0
  222. package/dist/intent/intent-shard.d.ts +411 -0
  223. package/dist/intent/intent-shard.js +176 -0
  224. package/dist/intent/intent-store.d.ts +49 -0
  225. package/dist/intent/intent-store.js +133 -0
  226. package/dist/intent/intent-subject.d.ts +45 -0
  227. package/dist/intent/intent-subject.js +177 -0
  228. package/dist/intent/intent-tools.d.ts +2 -0
  229. package/dist/intent/intent-tools.js +143 -0
  230. package/dist/intent/open-intents.d.ts +42 -0
  231. package/dist/intent/open-intents.js +40 -0
  232. package/dist/journal/envelope.d.ts +26 -26
  233. package/dist/journal/journal-recorder.d.ts +23 -0
  234. package/dist/journal/journal-recorder.js +35 -0
  235. package/dist/license/license-env.d.ts +29 -0
  236. package/dist/license/license-env.js +148 -0
  237. package/dist/loopback-agent.d.ts +31 -0
  238. package/dist/loopback-agent.js +57 -0
  239. package/dist/mcp/attach-memory.d.ts +83 -0
  240. package/dist/mcp/attach-memory.js +185 -0
  241. package/dist/mcp/client-identity.d.ts +31 -0
  242. package/dist/mcp/client-identity.js +51 -0
  243. package/dist/mcp/mcp-post-transport.d.ts +26 -0
  244. package/dist/mcp/mcp-post-transport.js +109 -0
  245. package/dist/mcp/mcp-proxy.d.ts +2 -8
  246. package/dist/mcp/mcp-proxy.js +64 -62
  247. package/dist/mcp/mcp.d.ts +2 -0
  248. package/dist/mcp/mcp.js +52 -24
  249. package/dist/mcp/proxy-backoff.d.ts +11 -0
  250. package/dist/mcp/proxy-backoff.js +13 -0
  251. package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
  252. package/dist/mcp/proxy-daemon-probe.js +7 -1
  253. package/dist/mcp/proxy-handshake.d.ts +23 -0
  254. package/dist/mcp/proxy-handshake.js +31 -0
  255. package/dist/mcp/server-instructions.js +45 -3
  256. package/dist/mcp/tool-catalog-cache.d.ts +16 -0
  257. package/dist/mcp/tool-catalog-cache.js +22 -0
  258. package/dist/memory/memory-tools.d.ts +2 -0
  259. package/dist/memory/memory-tools.js +82 -0
  260. package/dist/memory/project-memory.d.ts +34 -0
  261. package/dist/memory/project-memory.js +96 -0
  262. package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
  263. package/dist/oracles/flow-instrument-gaps.js +4 -5
  264. package/dist/oracles/propose-consequences.js +12 -3
  265. package/dist/oracles/self-instrument.d.ts +9 -9
  266. package/dist/oracles/self-instrument.js +19 -13
  267. package/dist/pool/browser-pool.d.ts +75 -5
  268. package/dist/pool/browser-pool.js +144 -5
  269. package/dist/pool/playwright-launcher.js +12 -1
  270. package/dist/project/fs-port.d.ts +3 -0
  271. package/dist/project/fs-port.js +3 -2
  272. package/dist/project/memory-fs.js +6 -1
  273. package/dist/project/project-tools.js +6 -35
  274. package/dist/project/reticle-dir.d.ts +17 -2
  275. package/dist/project/reticle-dir.js +22 -4
  276. package/dist/runs/context-tools.d.ts +2 -0
  277. package/dist/runs/context-tools.js +89 -0
  278. package/dist/runs/run-context.d.ts +40 -0
  279. package/dist/runs/run-context.js +158 -0
  280. package/dist/runs/run-diff.d.ts +2 -1
  281. package/dist/runs/run-store.d.ts +10 -0
  282. package/dist/runs/run-store.js +10 -0
  283. package/dist/runs/verification-sync.d.ts +0 -11
  284. package/dist/runs/verification-sync.js +24 -3
  285. package/dist/runs/verify-server.d.ts +8 -1
  286. package/dist/runs/verify-server.js +14 -2
  287. package/dist/session/command-timeout.d.ts +5 -2
  288. package/dist/session/command-timeout.js +5 -4
  289. package/dist/session/dev-server-probe.d.ts +0 -8
  290. package/dist/session/dev-server-probe.js +1 -1
  291. package/dist/session/last-act.d.ts +7 -1
  292. package/dist/session/last-act.js +2 -2
  293. package/dist/session/lease-visibility.d.ts +67 -0
  294. package/dist/session/lease-visibility.js +76 -0
  295. package/dist/session/live-control-tools.js +1 -42
  296. package/dist/session/no-session-diagnosis.d.ts +33 -0
  297. package/dist/session/no-session-diagnosis.js +82 -24
  298. package/dist/session/no-session-next-action.d.ts +12 -0
  299. package/dist/session/no-session-next-action.js +77 -6
  300. package/dist/session/no-session-watch.d.ts +18 -6
  301. package/dist/session/no-session-watch.js +125 -75
  302. package/dist/session/output-budget.js +4 -1
  303. package/dist/session/pending-commands.d.ts +11 -1
  304. package/dist/session/pending-commands.js +12 -2
  305. package/dist/session/resolve-within.d.ts +34 -0
  306. package/dist/session/resolve-within.js +53 -0
  307. package/dist/session/session-health.d.ts +9 -0
  308. package/dist/session/session-health.js +23 -0
  309. package/dist/session/session-info.d.ts +18 -0
  310. package/dist/session/session-info.js +11 -0
  311. package/dist/session/session-manager.d.ts +14 -0
  312. package/dist/session/session-manager.js +111 -4
  313. package/dist/session/session-mirror.d.ts +16 -0
  314. package/dist/session/session-mirror.js +22 -0
  315. package/dist/session/session-recommendation.d.ts +19 -5
  316. package/dist/session/session-recommendation.js +25 -9
  317. package/dist/session/session-successor.d.ts +37 -0
  318. package/dist/session/session-successor.js +113 -0
  319. package/dist/session/session-tools.js +2 -2
  320. package/dist/session/session.d.ts +53 -3
  321. package/dist/session/session.js +162 -9
  322. package/dist/session/wall-clock.d.ts +12 -0
  323. package/dist/session/wall-clock.js +14 -0
  324. package/dist/setup/agent-configs.d.ts +96 -0
  325. package/dist/setup/agent-configs.js +333 -0
  326. package/dist/setup/agent-io.d.ts +9 -0
  327. package/dist/setup/agent-io.js +16 -0
  328. package/dist/setup/agent-writer.d.ts +51 -0
  329. package/dist/setup/agent-writer.js +115 -0
  330. package/dist/setup/approval-migration.d.ts +47 -0
  331. package/dist/setup/approval-migration.js +68 -0
  332. package/dist/setup/auto-approve.d.ts +85 -0
  333. package/dist/setup/auto-approve.js +150 -0
  334. package/dist/setup/bridge-port.d.ts +15 -0
  335. package/dist/setup/bridge-port.js +24 -0
  336. package/dist/setup/desktop-shape.d.ts +57 -0
  337. package/dist/setup/desktop-shape.js +63 -0
  338. package/dist/setup/dev-server-wait.d.ts +60 -0
  339. package/dist/setup/dev-server-wait.js +65 -0
  340. package/dist/setup/drive-agent.d.ts +71 -0
  341. package/dist/setup/drive-agent.js +171 -0
  342. package/dist/setup/drive-plan.d.ts +68 -0
  343. package/dist/setup/drive-plan.js +130 -0
  344. package/dist/setup/ensure-daemon.d.ts +29 -0
  345. package/dist/setup/ensure-daemon.js +58 -0
  346. package/dist/setup/init-runtime.d.ts +47 -0
  347. package/dist/setup/init-runtime.js +160 -0
  348. package/dist/setup/interrupt.d.ts +25 -0
  349. package/dist/setup/interrupt.js +40 -0
  350. package/dist/setup/license-key.d.ts +39 -0
  351. package/dist/setup/license-key.js +72 -0
  352. package/dist/setup/listeners.d.ts +37 -0
  353. package/dist/setup/listeners.js +85 -0
  354. package/dist/setup/node-effects.d.ts +60 -0
  355. package/dist/setup/node-effects.js +210 -0
  356. package/dist/setup/page-probe.d.ts +39 -0
  357. package/dist/setup/page-probe.js +49 -0
  358. package/dist/setup/relaunch.d.ts +36 -0
  359. package/dist/setup/relaunch.js +57 -0
  360. package/dist/setup/remaining-steps.d.ts +19 -0
  361. package/dist/setup/remaining-steps.js +31 -0
  362. package/dist/setup/run-setup.d.ts +99 -0
  363. package/dist/setup/run-setup.js +187 -0
  364. package/dist/setup/session-pick.d.ts +47 -0
  365. package/dist/setup/session-pick.js +51 -0
  366. package/dist/setup/setup-command.d.ts +45 -0
  367. package/dist/setup/setup-command.js +199 -0
  368. package/dist/setup/setup-options.d.ts +74 -0
  369. package/dist/setup/setup-options.js +67 -0
  370. package/dist/setup/transcripts.d.ts +16 -0
  371. package/dist/setup/transcripts.js +43 -0
  372. package/dist/status-payload.d.ts +14 -1
  373. package/dist/status-payload.js +23 -1
  374. package/dist/telemetry/automation-hint.d.ts +2 -1
  375. package/dist/telemetry/daemon-telemetry.d.ts +8 -1
  376. package/dist/telemetry/daemon-telemetry.js +52 -5
  377. package/dist/telemetry/error-class.js +1 -1
  378. package/dist/telemetry/feedback-context.d.ts +9 -1
  379. package/dist/telemetry/feedback-context.js +60 -29
  380. package/dist/telemetry/feedback-local.d.ts +15 -0
  381. package/dist/telemetry/feedback-local.js +56 -0
  382. package/dist/telemetry/feedback-outbox.d.ts +2 -1
  383. package/dist/telemetry/feedback.d.ts +11 -0
  384. package/dist/telemetry/feedback.js +19 -6
  385. package/dist/telemetry/init-telemetry.d.ts +2 -0
  386. package/dist/telemetry/init-telemetry.js +2 -0
  387. package/dist/telemetry/install-source.d.ts +14 -0
  388. package/dist/telemetry/install-source.js +30 -0
  389. package/dist/telemetry/license-activation.d.ts +7 -1
  390. package/dist/telemetry/license-activation.js +9 -5
  391. package/dist/telemetry/mcp-connection.js +7 -0
  392. package/dist/telemetry/project-profile.d.ts +12 -9
  393. package/dist/telemetry/project-profile.js +12 -7
  394. package/dist/telemetry/proxy-telemetry.d.ts +3 -0
  395. package/dist/telemetry/proxy-telemetry.js +21 -0
  396. package/dist/telemetry/run-telemetry.d.ts +0 -2
  397. package/dist/telemetry/run-telemetry.js +1 -1
  398. package/dist/telemetry/session-metrics.d.ts +12 -0
  399. package/dist/telemetry/session-metrics.js +35 -1
  400. package/dist/telemetry/telemetry.js +17 -2
  401. package/dist/telemetry/tool-refused.d.ts +3 -1
  402. package/dist/telemetry/tool-refused.js +34 -2
  403. package/dist/telemetry/verification-of.js +2 -2
  404. package/dist/tools/act-capsule.d.ts +10 -0
  405. package/dist/tools/act-capsule.js +8 -2
  406. package/dist/tools/act-danger.d.ts +2 -1
  407. package/dist/tools/act-danger.js +11 -3
  408. package/dist/tools/act-observation.d.ts +41 -0
  409. package/dist/tools/act-observation.js +36 -0
  410. package/dist/tools/act-preflight.d.ts +20 -0
  411. package/dist/tools/act-preflight.js +98 -0
  412. package/dist/tools/act-sequence-retry.d.ts +45 -0
  413. package/dist/tools/act-sequence-retry.js +58 -0
  414. package/dist/tools/act-sequence-tool.d.ts +13 -0
  415. package/dist/tools/act-sequence-tool.js +135 -0
  416. package/dist/tools/act-target.d.ts +14 -0
  417. package/dist/tools/act-target.js +47 -0
  418. package/dist/tools/act-tools.d.ts +21 -1
  419. package/dist/tools/act-tools.js +196 -204
  420. package/dist/tools/assert-source.d.ts +22 -0
  421. package/dist/tools/assert-source.js +53 -0
  422. package/dist/tools/assert-verdict.d.ts +20 -3
  423. package/dist/tools/assert-verdict.js +58 -20
  424. package/dist/tools/browser-tools.js +6 -22
  425. package/dist/tools/complete-snapshot.d.ts +48 -0
  426. package/dist/tools/complete-snapshot.js +75 -0
  427. package/dist/tools/coverage-tools.d.ts +10 -1
  428. package/dist/tools/coverage-tools.js +123 -69
  429. package/dist/tools/dynamic-tools.js +53 -13
  430. package/dist/tools/error-recovery.d.ts +25 -14
  431. package/dist/tools/error-recovery.js +78 -9
  432. package/dist/tools/feedback-tools.d.ts +1 -1
  433. package/dist/tools/feedback-tools.js +2 -2
  434. package/dist/tools/invoke-tool.js +121 -11
  435. package/dist/tools/lease-hint.d.ts +10 -0
  436. package/dist/tools/lease-hint.js +53 -4
  437. package/dist/tools/lease-tools.d.ts +35 -5
  438. package/dist/tools/lease-tools.js +191 -13
  439. package/dist/tools/merged-name-redirect.d.ts +13 -0
  440. package/dist/tools/merged-name-redirect.js +22 -0
  441. package/dist/tools/navigate-arrival.d.ts +0 -2
  442. package/dist/tools/navigate-arrival.js +1 -1
  443. package/dist/tools/numeric-bounds.d.ts +100 -0
  444. package/dist/tools/numeric-bounds.js +125 -0
  445. package/dist/tools/observe-tools.js +109 -65
  446. package/dist/tools/read-tools.js +31 -8
  447. package/dist/tools/real-input-attempt.d.ts +32 -0
  448. package/dist/tools/real-input-attempt.js +212 -2
  449. package/dist/tools/reconcile-tools.js +22 -8
  450. package/dist/tools/resolve-target.d.ts +0 -7
  451. package/dist/tools/sdk-marker-probe.d.ts +29 -0
  452. package/dist/tools/sdk-marker-probe.js +57 -0
  453. package/dist/tools/snapshot-delta.d.ts +1 -1
  454. package/dist/tools/tool-kit.d.ts +24 -0
  455. package/dist/tools/tool-kit.js +21 -0
  456. package/dist/tools/tool-names.d.ts +5 -0
  457. package/dist/tools/tool-names.js +5 -0
  458. package/dist/tools/tool-surface.d.ts +85 -6
  459. package/dist/tools/tool-surface.js +122 -2
  460. package/dist/tools/tools-helpers.d.ts +19 -0
  461. package/dist/tools/tools-helpers.js +46 -0
  462. package/dist/tools/tools.d.ts +2 -0
  463. package/dist/tools/tools.js +78 -12
  464. package/dist/tools/unadvertised-help.js +4 -4
  465. package/dist/tools/verify-next-baton.d.ts +53 -0
  466. package/dist/tools/verify-next-baton.js +52 -0
  467. package/dist/update/reticle-deps.d.ts +9 -0
  468. package/dist/update/reticle-deps.js +27 -0
  469. package/dist/update/sdk-sync.d.ts +1 -2
  470. package/dist/update/sdk-sync.js +1 -21
  471. package/dist/update/update-nudge.d.ts +25 -10
  472. package/dist/update/update-nudge.js +32 -3
  473. package/dist/update/updater.d.ts +1 -1
  474. package/dist/version/peer-announce.js +4 -2
  475. package/dist/version/sdk-fix.d.ts +47 -0
  476. package/dist/version/sdk-fix.js +127 -0
  477. package/dist/version/version-nudge.d.ts +14 -0
  478. package/dist/version/version-nudge.js +21 -0
  479. package/dist/version/version-skew.d.ts +38 -3
  480. package/dist/version/version-skew.js +83 -7
  481. package/dist/visual/visual-store.d.ts +6 -6
  482. package/dist/visual/visual-store.js +18 -16
  483. package/dist/visual/visual-tools.js +57 -12
  484. package/docs/README.md +2 -1
  485. package/docs/cli/cloud.mdx +1 -1
  486. package/docs/cli/doctor.mdx +2 -0
  487. package/docs/cli/serve.mdx +4 -2
  488. package/docs/cli/verify.mdx +4 -5
  489. package/docs/cli.mdx +7 -3
  490. package/docs/desktop.mdx +1 -1
  491. package/docs/docs.json +2 -2
  492. package/docs/gates.md +1 -1
  493. package/docs/getting-started.md +19 -3
  494. package/docs/index.mdx +9 -6
  495. package/docs/install-agentic.mdx +38 -12
  496. package/docs/install-manual.mdx +1 -1
  497. package/docs/packages/browser.mdx +2 -2
  498. package/docs/packages/server.mdx +1 -1
  499. package/docs/packages.mdx +8 -6
  500. package/docs/platform-integration.md +17 -0
  501. package/docs/predicates.mdx +8 -0
  502. package/docs/reticle-manual.md +106 -0
  503. package/docs/skill-file.mdx +3 -3
  504. package/docs/telemetry-contract.md +108 -4
  505. package/docs/tools-act-sequence.mdx +16 -0
  506. package/docs/tools-tools-and-run.mdx +2 -4
  507. package/docs/troubleshooting.mdx +9 -0
  508. package/docs/usage.md +4 -3
  509. package/package.json +4 -3
  510. package/dist/init/cursor.d.ts +0 -24
  511. package/dist/init/cursor.js +0 -80
  512. package/dist/session/session-readiness.d.ts +0 -34
  513. package/dist/session/session-readiness.js +0 -36
@@ -3,15 +3,17 @@
3
3
  * Split out of `plan.ts` — that file is the plan's SHAPE (statuses, ordering, the agent/MCP steps),
4
4
  * this one is the per-framework detail, and they grow for different reasons.
5
5
  */
6
+ import { bridgeWsUrl } from '@reticlehq/core';
6
7
  import { patchViteConfig, VitePatchKind } from './vite-config.js';
7
8
  import { patchNextConfig, patchRootLayout, patchPagesApp } from './next-patch.js';
8
- import { patchAstroConfig, patchAstroLayout } from './astro-patch.js';
9
- import { CRA_DEV_MODULE_IMPORT, CRA_DEV_MODULE_PATH, CRA_ENV_PATH, CRA_TOKEN_PER_MACHINE_NOTICE, TOKEN_VAR, craDevModuleFile, craEnvPatch, craImportPatch, } from './cra.js';
9
+ import { ASTRO_ENV_DTS_PATH, patchAstroConfig, patchAstroEnvDts, patchAstroLayout, } from './astro-patch.js';
10
+ import { CRA_DEV_MODULE_IMPORT, CRA_ENV_PATH, CRA_TOKEN_PER_MACHINE_NOTICE, TOKEN_VAR, craDevModuleFile, craDevModulePath, craEnvPatch, craImportPatch, } from './cra.js';
10
11
  import { PatchKind } from './patch-kind.js';
11
12
  import { viteManual, NEXT_LAYOUT_MANUAL, NEXT_LAYOUT_PATH, viteDevModuleFile, VITE_DEV_MODULE_PATH, nextReticleDevFile, NEXT_RETICLE_DEV_PATH, nextConfigManual, svelteKitHooksFile, SVELTEKIT_HOOKS_PATH, UNVERIFIED_FRAMEWORK_NOTE, astroManual, nuxtManual, NUXT_PLUGIN_PATH, } from './snippets.js';
12
- import { RETICLE_CONFIG_FILE, StepStatus } from './plan.js';
13
+ import { StepStatus } from './plan.js';
13
14
  import { RETICLE_DEFAULT_PORT } from '@reticlehq/core';
14
- import { CSP_STEP_TITLE, cspPlanProblem } from './csp-check.js';
15
+ import { CSP_STEP_TITLE } from './csp-check.js';
16
+ import { diagnoseWebCsp } from './csp-doctor.js';
15
17
  /** What adding `reticle()` to a Vite config buys, which differs by framework. */
16
18
  export const VITE_PLUGIN_DETAIL = {
17
19
  /** A plain Vite app gets both halves from the plugin. */
@@ -40,20 +42,13 @@ const CAPABILITIES_TITLE = 'Capabilities + store';
40
42
  */
41
43
  const CAPABILITIES_TODO_TITLE = 'AGENT: finish the capabilities file';
42
44
  function capabilitiesTodo(path, stores) {
43
- const store = stores.length > 0
44
- ? `This app depends on a state library init cannot wire on its own (it needs an argument only ` +
45
- `reading the code can supply). Uncomment the suggested line in that file and complete it: ` +
46
- `${stores.join('; ')}.`
47
- : `No state library was detected. If the app holds state somewhere init cannot see, register ` +
48
- `it — see node_modules/@reticlehq/server/docs/usage.md.`;
49
- return (`${path} was written but registers nothing, so \`hasCapabilities\` stays false and reticle_state ` +
50
- `has nothing to read.\n` +
45
+ return (`This app's state lives in a library nothing in the running app points at, so it is the one ` +
46
+ `thing Reticle cannot find for itself — reticle_state will not see it until you say where it ` +
47
+ `is.\n` +
51
48
  `Do this now, before driving anything:\n` +
52
- ` 1. ${store}\n` +
53
- ` 2. Open the app's main flow and add \`testids\` for the elements it touches (or add ` +
54
- `data-testid attributes where there are none).\n` +
55
- ` 3. Prove it: drive one flow and check reticle_state returns your keys. An empty state read ` +
56
- `means this file is still not doing anything, whatever else went green.`);
49
+ ` 1. In ${path}, uncomment the suggested line and complete it: ${stores.join('; ')}.\n` +
50
+ ` 2. Prove it: drive one flow and check reticle_state returns your key. An empty state read ` +
51
+ `means the line is still not doing anything, whatever else went green.`);
57
52
  }
58
53
  /**
59
54
  * The dev module carrying `registerCapabilities` / `registerStore`.
@@ -62,6 +57,28 @@ function capabilitiesTodo(path, stores) {
62
57
  * `__reticle_renders` — the state-truth read was unavailable on every app out of the box. Written
63
58
  * only when absent, because it is the one generated file a user is expected to EDIT.
64
59
  */
60
+ /**
61
+ * Is there state left that ONLY the app can hand over?
62
+ *
63
+ * This used to ask a much bigger question — "does the generated file register anything at all?" —
64
+ * and fired on almost every install, because almost every install generated a file whose testids
65
+ * and stores were both empty. The answer was homework: go read the source, uncomment a line, add
66
+ * data-testid attributes, then drive to prove it. Several turns, on every onboarding.
67
+ *
68
+ * Two of those three are no longer anyone's homework. Testids are read from the live DOM, and a
69
+ * store passed through a React context provider (Redux, TanStack Query) is discovered and
70
+ * registered on the first commit. What is left is the genuinely unreachable case: a module-scope
71
+ * store, or one needing an argument only the source supplies — Zustand, Jotai atoms, an XState
72
+ * actor. Nothing in the running app points at those, so the notice still has to fire, and it now
73
+ * fires ONLY there.
74
+ *
75
+ * `wired` are stores init resolved and wrote a live `registerStore` call for. Hints are not
76
+ * registrations: they land in the file as a commented line, and counting one as a registration
77
+ * silences the notice whose whole purpose is to say "act on the hint".
78
+ */
79
+ function needsManualStore(hints, wired) {
80
+ return hints.length > 0 && 0 === wired.length;
81
+ }
65
82
  function capabilitiesStep(input) {
66
83
  if (true === input.viteDevModuleExists) {
67
84
  return [
@@ -76,11 +93,26 @@ function capabilitiesStep(input) {
76
93
  const testids = input.testids ?? [];
77
94
  const stores = input.storeHints ?? [];
78
95
  const wired = input.foundStores ?? [];
79
- const found = testids.length > 0
80
- ? `${String(testids.length)} data-testid values`
81
- : 'no data-testid values yet';
82
- // A store we found and wired IS a registration, so the "registers nothing" notice must not fire.
83
- const nothingToRegister = 0 === testids.length && 0 === stores.length && 0 === wired.length;
96
+ // Testids no longer need counting here. They are read from the live DOM at announce time, so a
97
+ // number printed at install time would be a stale claim about a codebase that is about to change —
98
+ // which is exactly what "no data-testid values yet" used to be on an app whose testids arrive with
99
+ // a lazy route.
100
+ const found = 'testids read from the live DOM';
101
+ // A store we found and WIRED is a registration, so the notice must not fire. A store HINT is not:
102
+ // `stores` holds suggestions, written into the file as a commented line of the form
103
+ // `// import your store, then: registerStore(...)`. Counting a suggestion as a registration let
104
+ // the hint silence the notice whose entire job is to say "act on the hint".
105
+ //
106
+ // Measured against a real product UI (rowy — 70+ deps, jotai, a whole src/atoms tree): init
107
+ // detected jotai, offered one commented line, emitted NO notice, and wrote
108
+ // `registerCapabilities({ testids: [], signals: [], stores: [] })`. So `hasCapabilities` stayed
109
+ // false, `reticle_state` was empty forever, and the install gate reported "connected: 1,
110
+ // manual ⚠: none". Every check green, state observability zero.
111
+ //
112
+ // jotai is still exactly that case. A Redux or TanStack app is not, any more: its store rides a
113
+ // context provider and the React adapter registers it on the first commit, so `storeHints` no
114
+ // longer names either one and this notice no longer fires for them.
115
+ const nothingToRegister = needsManualStore(stores, wired);
84
116
  return [
85
117
  {
86
118
  title: CAPABILITIES_TITLE,
@@ -135,7 +167,7 @@ function viteConfigSteps(input, detail) {
135
167
  },
136
168
  ];
137
169
  }
138
- const patch = patchViteConfig(cfg.source, port);
170
+ const patch = patchViteConfig(cfg.source, port, true === input.captureBodies);
139
171
  if (patch.kind === VitePatchKind.ALREADY) {
140
172
  return [
141
173
  {
@@ -197,16 +229,44 @@ function patchStep(title, path, patch, applyDetail, manualDetail) {
197
229
  * skipped, so a Next user's app booted, connected to nothing, and said nothing about why. Both are
198
230
  * now patched by the same conservative rules the Vite config gets.
199
231
  */
232
+ /** The env var withReticle sets from the discovered daemon, and the component must read. */
233
+ const NEXT_DAEMON_URL_ENV = 'NEXT_PUBLIC_RETICLE_URL';
234
+ /**
235
+ * The two-line edit that unfreezes an existing install's port.
236
+ *
237
+ * Stated as the edit rather than as a problem, because the reader is an agent that can apply it in
238
+ * one write and is otherwise going to ask what to do.
239
+ */
240
+ const NEXT_DEV_FILE_STALE_DETAIL = 'predates daemon discovery, so it dials the port init saw when it ran. In this file add ' +
241
+ '`const url = process.env.NEXT_PUBLIC_RETICLE_URL;` and spread `...(url ? { url } : {})` into ' +
242
+ 'reticle.connect(), after any url already there. Nothing else needs to change.';
200
243
  export function nextSteps(input) {
201
244
  const configFile = input.nextConfigFile ?? 'next.config.mjs';
202
245
  const devPath = input.nextReticleDevPath ?? NEXT_RETICLE_DEV_PATH;
246
+ // An install that predates daemon discovery has a component that never reads the discovered URL,
247
+ // so it keeps dialling whatever port `init` saw on the day it ran. Re-running `init` used to call
248
+ // that "file exists" and move on, which is why the defect survives an upgrade. Named as work.
249
+ //
250
+ // Never overwritten: this file is the one an app owner edits — registered stores, capabilities,
251
+ // their own signals. Rewriting it to fix two lines would take the rest with it. Undefined source
252
+ // means it was not read, and an unread file stays ALREADY rather than becoming invented work.
253
+ const devStale = true === input.nextReticleDevExists &&
254
+ 'string' === typeof input.nextReticleDevSource &&
255
+ !input.nextReticleDevSource.includes(NEXT_DAEMON_URL_ENV);
203
256
  const devFile = input.nextReticleDevExists
204
- ? {
205
- title: 'ReticleDev component',
206
- target: devPath,
207
- status: StepStatus.ALREADY,
208
- detail: 'file exists',
209
- }
257
+ ? devStale
258
+ ? {
259
+ title: 'ReticleDev component',
260
+ target: devPath,
261
+ status: StepStatus.MANUAL,
262
+ detail: NEXT_DEV_FILE_STALE_DETAIL,
263
+ }
264
+ : {
265
+ title: 'ReticleDev component',
266
+ target: devPath,
267
+ status: StepStatus.ALREADY,
268
+ detail: 'file exists',
269
+ }
210
270
  : {
211
271
  title: 'ReticleDev component',
212
272
  target: devPath,
@@ -233,8 +293,22 @@ export function nextSteps(input) {
233
293
  : isPagesRouter
234
294
  ? patchPagesApp(layout.source, input.nextReticleDevImport)
235
295
  : patchRootLayout(layout.source);
296
+ // The same question the Vite path asks. Skipped when the module already exists: its contents are
297
+ // the user's, and re-nagging about a file we did not write is noise.
298
+ const nextTodo = true !== input.nextReticleDevExists &&
299
+ needsManualStore(input.storeHints ?? [], input.nextFoundStores ?? [])
300
+ ? [
301
+ {
302
+ title: CAPABILITIES_TODO_TITLE,
303
+ target: devPath,
304
+ status: StepStatus.NOTICE,
305
+ detail: capabilitiesTodo(devPath, input.storeHints ?? []),
306
+ },
307
+ ]
308
+ : [];
236
309
  return [
237
310
  devFile,
311
+ ...nextTodo,
238
312
  patchStep('Next config (withReticle)', configFile, configPatch, 'wrap the export in withReticle (source mapping, dev-only)', nextConfigManual(configFile)),
239
313
  patchStep('Mount ReticleDev', layout?.path ?? NEXT_LAYOUT_PATH, layoutPatch, 'mount <ReticleDev /> in the root layout (dev-only)', NEXT_LAYOUT_MANUAL),
240
314
  ];
@@ -255,21 +329,27 @@ export function nextSteps(input) {
255
329
  */
256
330
  export function craSteps(input) {
257
331
  const entry = input.craEntry ?? null;
332
+ // Match the project language the same way Next does (#675): a JS CRA app cannot resolve `.ts`.
333
+ const modulePath = craDevModulePath(input.detection.typescript);
258
334
  const steps = [
259
335
  {
260
336
  title: 'Reticle connect module',
261
- target: CRA_DEV_MODULE_PATH,
337
+ target: modulePath,
262
338
  status: StepStatus.APPLY,
263
339
  detail: 'create the dev-only connect (CRA cannot inject through public/index.html)',
264
340
  write: {
265
- path: CRA_DEV_MODULE_PATH,
266
- content: craDevModuleFile(input.options.port, input.options.projectId),
341
+ path: modulePath,
342
+ content: craDevModuleFile(input.options.port, input.options.projectId, {
343
+ typescript: input.detection.typescript,
344
+ }),
267
345
  },
268
346
  dependsOnInstall: true,
269
347
  },
270
348
  ];
271
349
  const token = input.pairingToken ?? '';
272
- const env = craEnvPatch(input.craEnv ?? null, token);
350
+ // The daemon that is live NOW, not the one baked into the module at first install. CRA has no
351
+ // build hook, so this is refreshed by re-running `init` rather than by starting the dev server.
352
+ const env = craEnvPatch(input.craEnv ?? null, token, input.options.port === undefined ? undefined : bridgeWsUrl(input.options.port));
273
353
  if (env !== null) {
274
354
  steps.push({
275
355
  title: 'Pairing token',
@@ -426,9 +506,14 @@ export function astroSteps(input) {
426
506
  },
427
507
  ];
428
508
  }
509
+ const envPatch = patchAstroEnvDts(input.astroEnvDts ?? null);
429
510
  return [
430
511
  patchStep('Astro config (token + build target)', config.path, configPatch, 'inline the pairing token and raise build.target to es2022', manualWithLayout),
431
512
  patchStep('Connect snippet (Astro)', layout.path, layoutPatch, 'add the dev-only connect <script> before </body>', manualWithLayout),
513
+ // Declares the Vite define names so `astro check` (create-astro's default build) can see them
514
+ // (#677). Independent of the two halves above: even an ALREADY config/layout still needs this
515
+ // when the env file was never written.
516
+ patchStep('Astro env types (Vite defines)', ASTRO_ENV_DTS_PATH, envPatch, 'declare __RETICLE_TOKEN__ / __RETICLE_ROOT__ for astro check', manualWithLayout),
432
517
  ];
433
518
  }
434
519
  /**
@@ -441,15 +526,40 @@ export function astroSteps(input) {
441
526
  * warning and a fix.
442
527
  */
443
528
  export function cspStep(input) {
444
- const problem = cspPlanProblem([input.nextConfigSource, input.nextLayout?.source], input.options.port ?? RETICLE_DEFAULT_PORT);
445
- if (problem === undefined)
529
+ // Reads the SAME list `reticle doctor` reads. It used to read a hand-written pair —
530
+ // `[nextConfigSource, nextLayout?.source]` — while csp-doctor.ts already carried the full set
531
+ // including `index.html`, which is where every Vite and Electron app declares its policy. So the
532
+ // command you run BEFORE anything works checked less than the one you run after it has failed.
533
+ //
534
+ // Measured on MarkText, a production Electron editor: its renderer sets `default-src 'self'` with
535
+ // no `connect-src`, the browser blocked the bridge WebSocket, and `init` printed a clean plan. The
536
+ // daemon cannot see a dial that never left the page, so nothing anywhere said why — and the check
537
+ // that would have said it was sitting one import away.
538
+ // The pre-read Next sources are folded in ON TOP of the shared list, not replaced by it: init
539
+ // resolves `nextConfigFile` across more spellings than CSP_FILES names (`.mts`, for one), and a
540
+ // layout is found by search rather than by a fixed path. Two sources of the same truth is the
541
+ // problem being fixed here — one of them being a SUPERSET is not.
542
+ const extra = {
543
+ ...(input.nextConfigFile !== null && input.nextConfigFile !== undefined
544
+ ? { [input.nextConfigFile]: input.nextConfigSource ?? undefined }
545
+ : {}),
546
+ ...(input.nextLayout ? { [input.nextLayout.path]: input.nextLayout.source } : {}),
547
+ };
548
+ const read = (file) => extra[file] ?? input.cspSources?.[file];
549
+ const findings = diagnoseWebCsp(read, input.options.port ?? RETICLE_DEFAULT_PORT, [
550
+ ...Object.keys(extra),
551
+ ]);
552
+ const first = findings[0];
553
+ if (first === undefined)
446
554
  return [];
447
555
  return [
448
556
  {
449
557
  title: CSP_STEP_TITLE,
450
- target: input.nextConfigFile ?? RETICLE_CONFIG_FILE,
558
+ target: first.file,
451
559
  status: StepStatus.NOTICE,
452
- detail: problem,
560
+ // `problem` already ends with the text to paste; `fix` is the same sentence for callers that
561
+ // want it on its own (doctor renders them separately). Printing both said it twice.
562
+ detail: first.problem,
453
563
  },
454
564
  ];
455
565
  }
@@ -5,17 +5,7 @@
5
5
  */
6
6
  import { Framework, UiLibrary, type Detection } from './detect.js';
7
7
  import type { FoundStore } from './capabilities.js';
8
- import { type McpClient } from './mcp-clients.js';
9
- /**
10
- * Pin the SDK to the CLI's own version.
11
- *
12
- * `pnpm add -D @reticlehq/react` installed **2.2.1** in one project while npm and yarn took 2.3.0 in
13
- * the next — a stale registry metadata cache, invisible to the user and to us. A version-skewed SDK
14
- * talking to a newer daemon is the `-32000` failure path: the app connects, the protocol disagrees,
15
- * and nothing on either side names a version. Asking for the CLI's exact version makes the cache
16
- * irrelevant, and a skewed pair impossible to install by accident.
17
- */
18
- export declare function pinnedPackages(packages: readonly string[], version: string | undefined): readonly string[];
8
+ import { McpClient } from './mcp-clients.js';
19
9
  /**
20
10
  * The dev-dependencies `reticle init` installs — kit (or sensor) first, build plugin next.
21
11
  *
@@ -95,18 +85,28 @@ export interface Plan {
95
85
  }
96
86
  export interface PlanInput {
97
87
  detection: Detection;
88
+ /**
89
+ * Write `captureNetworkBodies: true` into the app's config. Off unless the caller asked (#705).
90
+ *
91
+ * Optional so every existing caller and test keeps the safe default without naming it — the one
92
+ * direction a default about somebody else's data should be wrong in.
93
+ */
94
+ captureBodies?: boolean | undefined;
95
+ /**
96
+ * The CSP-bearing files this project actually has, keyed by path — read once in `gatherPlanInput`.
97
+ *
98
+ * Pre-read rather than given a reader, because `PlanInput` is the pure input to a pure planner and
99
+ * handing it an io would let any later step reach the disk from inside `buildPlan`.
100
+ */
101
+ cspSources?: Readonly<Record<string, string | undefined>> | undefined;
98
102
  /** Whether the `claude` CLI is installed (so we can register the MCP server globally). */
99
103
  claudeCli: boolean;
100
104
  /** Whether an `reticle` MCP server is already registered with Claude (any scope) — idempotency. */
101
105
  mcpExists: boolean;
102
- /** Whether Cursor is installed for this user (its global config dir exists). */
103
- cursorPresent: boolean;
106
+ /** `process.platform`. Injected so this module stays pure. Windows is the only branch. */
107
+ platform?: string;
104
108
  /** Whether THIS project has a .cursor/ directory — the signal that Cursor works on this repo. */
105
109
  cursorProjectPresent?: boolean | undefined;
106
- /** Current ~/.cursor/mcp.json content, or null if absent. */
107
- cursorConfig: string | null;
108
- /** Absolute path of ~/.cursor/mcp.json (the write target). */
109
- cursorConfigPath: string;
110
110
  /**
111
111
  * Every OTHER MCP client detected on this machine, with its config path and current content.
112
112
  *
@@ -139,6 +139,11 @@ export interface PlanInput {
139
139
  path: string;
140
140
  source: string;
141
141
  } | null | undefined;
142
+ /**
143
+ * Existing `src/env.d.ts` content, when present — where the Vite-define ambient declarations go
144
+ * so `astro check` can see `__RETICLE_TOKEN__` / `__RETICLE_ROOT__` (#677).
145
+ */
146
+ astroEnvDts?: string | null | undefined;
142
147
  /** Discovered Next config filename (e.g. 'next.config.mjs'), or null. */
143
148
  nextConfigFile: string | null;
144
149
  /** Source of that Next config, so the export can be wrapped in withReticle. */
@@ -154,6 +159,14 @@ export interface PlanInput {
154
159
  nextReticleDevImport?: string | undefined;
155
160
  /** Whether the ReticleDev component file already exists. */
156
161
  nextReticleDevExists: boolean;
162
+ /**
163
+ * The existing ReticleDev component's source, when there is one.
164
+ *
165
+ * Read so an install predating daemon discovery can be told apart from a current one. Undefined
166
+ * means NOT READ, and an unread file is reported as already-wired rather than as stale: inventing
167
+ * work from missing information is how a plan grows steps that can never be completed.
168
+ */
169
+ nextReticleDevSource?: string | null | undefined;
157
170
  /** `data-testid` values scanned from the app's source, for the generated capabilities block. */
158
171
  testids?: readonly string[] | undefined;
159
172
  /** Ready-to-uncomment `registerStore` lines for the state libraries the app actually depends on. */
@@ -226,24 +239,4 @@ export interface PlanInput {
226
239
  sdkVersion?: string;
227
240
  };
228
241
  }
229
- /**
230
- * Every coding agent `reticle init` knows how to wire itself into, and the three surfaces it wires:
231
- * the global MCP registration, the project rule file that makes the agent USE Reticle, and the
232
- * `/reticle` command.
233
- *
234
- * One list, because those three surfaces used to enumerate Claude and Cursor separately in three
235
- * places — so supporting a fourth agent meant finding all three and getting each right. Adding one
236
- * is now an entry here plus its builders; each builder answers null when that agent is not present
237
- * for this user or this project, which is also how "no agent detected" falls through to the
238
- * cross-agent AGENTS.md.
239
- *
240
- * Deliberately functions rather than data: registering with Claude runs its CLI while Cursor merges
241
- * a JSON file, and pretending those are the same shape would cost more than it saves.
242
- */
243
- declare const AgentId: {
244
- readonly CLAUDE: "claude";
245
- readonly CURSOR: "cursor";
246
- };
247
- export type AgentId = (typeof AgentId)[keyof typeof AgentId];
248
242
  export declare function buildPlan(input: PlanInput): Plan;
249
- export {};
package/dist/init/plan.js CHANGED
@@ -4,15 +4,16 @@
4
4
  * runner performs the `write` side-effects; this module decides *what* should happen.
5
5
  */
6
6
  import { Framework, PackageManager, UiLibrary, installCommand, installCommandParts, } from './detect.js';
7
- import { claudeAddCommand, mcpManual } from './mcp.js';
8
- import { mergeCursorConfig, CursorMergeStatus, cursorServerEntry } from './cursor.js';
9
- import { mergeClientConfig, ClientMergeStatus, clientSnippet, clientSpec, } from './mcp-clients.js';
7
+ import { installFailureHint } from './install-hint.js';
8
+ import { claudeAddCommand, mcpManual, mcpWindowsNote } from './mcp.js';
9
+ import { NodePlatform } from '../platform.js';
10
+ import { mergeClientConfig, ClientMergeStatus, clientSnippet, clientSpec, McpClient, } from './mcp-clients.js';
10
11
  import { CLAUDE_COMMAND_PATH, CURSOR_COMMAND_PATH, SLASH_COMMAND_BODY, SLASH_COMMAND_SIGNATURE, } from './slash-command.js';
11
12
  import { mergeMarkedInstruction, reticleMdFile, cursorRuleFile, AgentRuleStatus, CLAUDE_MD_PATH, AGENTS_MD_PATH, RETICLE_MD_PATH, CURSOR_RULE_PATH, } from './agent-rules.js';
12
13
  import { viteSteps, nextSteps, craSteps, svelteKitSteps, nuxtSteps, astroSteps, cspStep, VITE_PLUGIN_DETAIL, } from './plan-framework.js';
13
14
  import { join } from 'node:path';
14
15
  import { htmlManual, reticleConfigContent, unverifiedUiLibraryNote } from './snippets.js';
15
- import { declaredInstallSource } from '../telemetry/install-source.js';
16
+ import { configWithInstallSource, declaredInstallSource } from '../telemetry/install-source.js';
16
17
  import { devServerPortWarning, isLikelyDevServerPort } from '../cli/cli-port.js';
17
18
  // An app dev installs exactly the audience-scoped browser-side dependencies — never the retired
18
19
  // `@reticlehq/core` umbrella (which dragged the Node MCP server + ws into every app). The kit is the
@@ -32,7 +33,7 @@ const RETICLE_NEXT_PLUGIN = '@reticlehq/next';
32
33
  * and nothing on either side names a version. Asking for the CLI's exact version makes the cache
33
34
  * irrelevant, and a skewed pair impossible to install by accident.
34
35
  */
35
- export function pinnedPackages(packages, version) {
36
+ function pinnedPackages(packages, version) {
36
37
  if (version === undefined || 0 === version.length)
37
38
  return packages;
38
39
  return packages.map((p) => `${p}@${version}`);
@@ -121,7 +122,6 @@ function agentFile(input, relPath) {
121
122
  return root === undefined || 0 === root.length ? relPath : join(root, relPath);
122
123
  }
123
124
  const CLAUDE_MCP_TITLE = 'MCP server (Claude, global)';
124
- const CURSOR_MCP_TITLE = 'MCP server (Cursor, global)';
125
125
  function claudeMcpStep(input) {
126
126
  if (!input.claudeCli)
127
127
  return null;
@@ -142,34 +142,6 @@ function claudeMcpStep(input) {
142
142
  exec: { command: cmd.command, args: cmd.args, fallback: cmd.display },
143
143
  };
144
144
  }
145
- function cursorMcpStep(input) {
146
- if (!input.cursorPresent)
147
- return null;
148
- const r = mergeCursorConfig(input.cursorConfig);
149
- if (r.status === CursorMergeStatus.ALREADY) {
150
- return {
151
- title: CURSOR_MCP_TITLE,
152
- target: input.cursorConfigPath,
153
- status: StepStatus.ALREADY,
154
- detail: 'reticle already in Cursor global config',
155
- };
156
- }
157
- if (r.status === CursorMergeStatus.MANUAL) {
158
- return {
159
- title: CURSOR_MCP_TITLE,
160
- target: input.cursorConfigPath,
161
- status: StepStatus.MANUAL,
162
- detail: `couldn't parse ${input.cursorConfigPath} — add this server by hand:\n "reticle": ${JSON.stringify(cursorServerEntry())}`,
163
- };
164
- }
165
- return {
166
- title: CURSOR_MCP_TITLE,
167
- target: input.cursorConfigPath,
168
- status: StepStatus.APPLY,
169
- detail: 'register reticle in Cursor global config',
170
- write: { path: input.cursorConfigPath, content: r.content },
171
- };
172
- }
173
145
  /**
174
146
  * One step per OTHER detected client.
175
147
  *
@@ -232,19 +204,33 @@ function mcpSteps(input) {
232
204
  // client. A machine with Cursor AND Windsurf gets both — registering only the first one found is
233
205
  // how a user ends up with Reticle in the editor they were not using.
234
206
  const steps = [...stepsForAgents(input, (a) => a.mcpStep), ...otherClientSteps(input)];
235
- if (steps.length > 0)
236
- return steps;
237
- // No supported agent detected — print the one-time global instructions. Reached when the `claude`
238
- // CLI is absent AND ~/.cursor does not exist, which includes Cursor installed with a fresh profile
239
- // that has not written its config directory yet, so the manual text covers both agents.
240
- return [
241
- {
242
- title: 'MCP server (global)',
243
- target: MCP_TARGET,
244
- status: StepStatus.MANUAL,
245
- detail: mcpManual(),
246
- },
247
- ];
207
+ if (0 === steps.length) {
208
+ // No agent detected. mcpManual already carries the Windows cmd fallback — do not append it again.
209
+ return [
210
+ {
211
+ title: 'MCP server (global)',
212
+ target: MCP_TARGET,
213
+ status: StepStatus.MANUAL,
214
+ detail: mcpManual(),
215
+ },
216
+ ];
217
+ }
218
+ const windowsNote = windowsMcpNoteStep(input);
219
+ if (windowsNote !== null)
220
+ steps.push(windowsNote);
221
+ return steps;
222
+ }
223
+ const WINDOWS_MCP_TITLE = 'Windows MCP spawn';
224
+ /** Windows only. The reported install never reached mcpManual because `claude mcp add` succeeded. */
225
+ function windowsMcpNoteStep(input) {
226
+ if (input.platform !== NodePlatform.WINDOWS)
227
+ return null;
228
+ return {
229
+ title: WINDOWS_MCP_TITLE,
230
+ target: MCP_TARGET,
231
+ status: StepStatus.NOTICE,
232
+ detail: mcpWindowsNote(),
233
+ };
248
234
  }
249
235
  const SLASH_COMMAND_TITLE = 'The /reticle command';
250
236
  /**
@@ -289,7 +275,8 @@ function claudeCommandStep(input) {
289
275
  return commandStepFor(agentFile(input, CLAUDE_COMMAND_PATH), input.claudeCli, input.claudeCommandContent);
290
276
  }
291
277
  function cursorCommandStep(input) {
292
- const present = true === input.cursorProjectPresent || (input.cursorPresent && !input.claudeCli);
278
+ const cursorGlobal = (input.detectedClients ?? []).some((c) => c.id === McpClient.CURSOR);
279
+ const present = true === input.cursorProjectPresent || (cursorGlobal && !input.claudeCli);
293
280
  return commandStepFor(agentFile(input, CURSOR_COMMAND_PATH), present, input.cursorCommandContent);
294
281
  }
295
282
  const AGENT_RULE_TITLE = 'Agent verification rule';
@@ -324,7 +311,8 @@ function claudeRuleStep(input) {
324
311
  * committed into their repo. (Global MCP registration is different: it is global, and stays.)
325
312
  */
326
313
  function cursorRuleStep(input) {
327
- if (!input.cursorPresent)
314
+ const cursorGlobal = (input.detectedClients ?? []).some((c) => c.id === McpClient.CURSOR);
315
+ if (!cursorGlobal && true !== input.cursorProjectPresent)
328
316
  return null;
329
317
  if (input.cursorProjectPresent !== true && input.claudeCli)
330
318
  return null;
@@ -374,14 +362,13 @@ const AGENT_INTEGRATIONS = [
374
362
  },
375
363
  {
376
364
  id: AgentId.CURSOR,
377
- mcpStep: cursorMcpStep,
378
365
  ruleStep: cursorRuleStep,
379
366
  commandStep: cursorCommandStep,
380
367
  },
381
368
  ];
382
369
  /** The steps one surface contributes across every known agent, in registry order. */
383
370
  function stepsForAgents(input, surface) {
384
- return AGENT_INTEGRATIONS.map((a) => surface(a)(input)).filter((s) => s !== null);
371
+ return AGENT_INTEGRATIONS.map((a) => surface(a)?.(input) ?? null).filter((s) => s !== null);
385
372
  }
386
373
  /** The `/reticle` command file for every agent that has a command surface and is present here. */
387
374
  function slashCommandSteps(input) {
@@ -488,15 +475,6 @@ function unpinnedRetryNote(version, pm) {
488
475
  `installed instead. That may not match the daemon — if the agent reports protocol errors, check ` +
489
476
  `\`versionSkew\` in reticle_sessions.${remedy}`);
490
477
  }
491
- function installFailureHint(pm) {
492
- if (pm !== PackageManager.PNPM)
493
- return 'If the version was refused, install the SDK yourself.';
494
- return ('If pnpm reported ERR_PNPM_NO_MATURE_MATCHING_VERSION, its minimumReleaseAge setting is holding ' +
495
- 'this release back. Either wait out the window, or allow these packages explicitly:\n' +
496
- ' pnpm config set minimumReleaseAgeExclude "@reticlehq/*"\n' +
497
- 'Do NOT drop the version pin — unpinned, pnpm installs an older SDK against a newer daemon, and ' +
498
- 'that mismatch surfaces as a -32000 with nothing naming a version.');
499
- }
500
478
  function installStep(input) {
501
479
  const pm = input.detection.packageManager;
502
480
  const packages = pinnedPackages(frameworkPackages(input.detection.framework, input.detection.uiLibrary), input.options.sdkVersion);
@@ -614,6 +592,18 @@ function reticleConfigStep(input, content) {
614
592
  detail: problem,
615
593
  };
616
594
  }
595
+ // The one thing a re-run can still learn: which channel the user actually arrived through.
596
+ // See configWithInstallSource — it only ever ADDS a field that is absent.
597
+ const backfilled = configWithInstallSource(input.reticleConfigSource, declaredInstallSource());
598
+ if (backfilled !== undefined) {
599
+ return {
600
+ title: RETICLE_CONFIG_TITLE,
601
+ target: RETICLE_CONFIG_FILE,
602
+ status: StepStatus.APPLY,
603
+ detail: 'record which install route this project came through',
604
+ write: { path: RETICLE_CONFIG_FILE, content: backfilled },
605
+ };
606
+ }
617
607
  return {
618
608
  title: RETICLE_CONFIG_TITLE,
619
609
  target: RETICLE_CONFIG_FILE,
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The two conditions that make every later phase fail, checked before anything is written.
3
+ *
4
+ * Both lived in setup/reticle.mjs and neither survived the port into `init`. What they buy is the
5
+ * distance between a failure and its cause: without them, an unwritable checkout arrives as EACCES
6
+ * in a stack trace at phase four, and a missing package manager arrives as `spawn pnpm ENOENT`
7
+ * inside "the dev server exited" — which sends the reader into their own dev script hunting a bug
8
+ * that is not there.
9
+ */
10
+ /** The parts of the environment preflight reads, so the rules are testable without a filesystem. */
11
+ export interface PreflightIo {
12
+ /** Absolute path of the directory init is running in. */
13
+ cwd(): string;
14
+ /** Can this process write into the project root. */
15
+ canWrite(): boolean;
16
+ /** Runs a command quietly for a yes/no check; true on exit code 0. */
17
+ probe(command: string, args: readonly string[]): boolean;
18
+ }
19
+ /**
20
+ * The refusal to print, or undefined when this machine can run the install.
21
+ *
22
+ * `packageManager` is the one init RESOLVED, never a raw lockfile check. An inherited
23
+ * `pnpm-lock.yaml` at a monorepo root does not mean the app in `frontend/` uses pnpm — that app's own
24
+ * installed tree outranks an ancestor lockfile, and detect.ts already works this out. Re-deriving it
25
+ * here from `exists('pnpm-lock.yaml')` refused an npm app sitting under a pnpm monorepo on a machine
26
+ * with no pnpm, which the install gate proves must succeed.
27
+ */
28
+ export declare function preflightRefusal(io: PreflightIo, packageManager: string): string | undefined;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The two conditions that make every later phase fail, checked before anything is written.
3
+ *
4
+ * Both lived in setup/reticle.mjs and neither survived the port into `init`. What they buy is the
5
+ * distance between a failure and its cause: without them, an unwritable checkout arrives as EACCES
6
+ * in a stack trace at phase four, and a missing package manager arrives as `spawn pnpm ENOENT`
7
+ * inside "the dev server exited" — which sends the reader into their own dev script hunting a bug
8
+ * that is not there.
9
+ */
10
+ /**
11
+ * npm ships with node, so refusing for its absence would refuse on a machine that is fine.
12
+ */
13
+ const ALWAYS_PRESENT = 'npm';
14
+ /**
15
+ * The refusal to print, or undefined when this machine can run the install.
16
+ *
17
+ * `packageManager` is the one init RESOLVED, never a raw lockfile check. An inherited
18
+ * `pnpm-lock.yaml` at a monorepo root does not mean the app in `frontend/` uses pnpm — that app's own
19
+ * installed tree outranks an ancestor lockfile, and detect.ts already works this out. Re-deriving it
20
+ * here from `exists('pnpm-lock.yaml')` refused an npm app sitting under a pnpm monorepo on a machine
21
+ * with no pnpm, which the install gate proves must succeed.
22
+ */
23
+ export function preflightRefusal(io, packageManager) {
24
+ // First: on a read-only checkout nothing else matters, and one access check is cheaper and
25
+ // quieter than spawning a subprocess to discover the same thing.
26
+ if (!io.canWrite()) {
27
+ return (`${io.cwd()} is not writable, and init has to write into it (.reticle.json, the build config, ` +
28
+ 'a capabilities file). Fix the permissions, or run init from a checkout you own.');
29
+ }
30
+ // What the project resolves to says nothing about what the machine HAS, and a project committed to
31
+ // pnpm on an npm-only box is an ordinary Monday.
32
+ if (ALWAYS_PRESENT !== packageManager && !io.probe(packageManager, ['--version'])) {
33
+ return (`this project uses ${packageManager} (its lockfile says so) and ${packageManager} is not ` +
34
+ `installed on this machine. Install it (npm i -g ${packageManager}, or corepack enable), or ` +
35
+ 'pass --url with the address the app already serves.');
36
+ }
37
+ return undefined;
38
+ }