@reticlehq/server 2.7.0 → 2.9.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 (357) hide show
  1. package/README.md +14 -5
  2. package/SKILL.md +130 -778
  3. package/dist/bridge/bridge.d.ts +23 -0
  4. package/dist/bridge/bridge.js +80 -2
  5. package/dist/bridge/bridge.test-harness.d.ts +5 -0
  6. package/dist/bridge/bridge.test-harness.js +6 -4
  7. package/dist/capsule/causal-summary.d.ts +36 -1
  8. package/dist/capsule/causal-summary.js +33 -7
  9. package/dist/capsule/divergence.js +7 -1
  10. package/dist/cli/chromium-hint.d.ts +33 -5
  11. package/dist/cli/chromium-hint.js +82 -12
  12. package/dist/cli/cli-doctor.js +65 -34
  13. package/dist/cli/cli-flow-commands.js +8 -8
  14. package/dist/cli/cli-kill.d.ts +58 -0
  15. package/dist/cli/cli-kill.js +162 -0
  16. package/dist/cli/cli-parse.d.ts +16 -1
  17. package/dist/cli/cli-parse.js +32 -9
  18. package/dist/cli/cli-port.d.ts +32 -0
  19. package/dist/cli/cli-port.js +82 -35
  20. package/dist/cli/cli-verify.d.ts +21 -0
  21. package/dist/cli/cli-verify.js +47 -3
  22. package/dist/cli/config-discovery.d.ts +35 -0
  23. package/dist/cli/config-discovery.js +163 -0
  24. package/dist/cli/doctor-daemon-line.js +4 -1
  25. package/dist/cli/doctor-project-line.d.ts +37 -0
  26. package/dist/cli/doctor-project-line.js +35 -0
  27. package/dist/cli/doctor-rows.d.ts +51 -0
  28. package/dist/cli/doctor-rows.js +54 -0
  29. package/dist/cli/doctor-sessions-line.d.ts +12 -0
  30. package/dist/cli/doctor-sessions-line.js +69 -0
  31. package/dist/cli/drive-attach.d.ts +99 -0
  32. package/dist/cli/drive-attach.js +203 -0
  33. package/dist/cli/drive-command.d.ts +13 -0
  34. package/dist/cli/drive-command.js +103 -0
  35. package/dist/cli/open-note.d.ts +20 -0
  36. package/dist/cli/open-note.js +37 -0
  37. package/dist/cli/port-holder.d.ts +10 -0
  38. package/dist/cli/port-holder.js +26 -2
  39. package/dist/cli/status-next-action.d.ts +37 -0
  40. package/dist/cli/status-next-action.js +61 -0
  41. package/dist/cli.js +119 -39
  42. package/dist/crawl/crawl-tools.js +12 -2
  43. package/dist/crawl/crawl.d.ts +13 -0
  44. package/dist/crawl/crawl.js +50 -2
  45. package/dist/events/contradictions.d.ts +46 -0
  46. package/dist/events/contradictions.js +35 -22
  47. package/dist/events/declared.d.ts +45 -0
  48. package/dist/events/declared.js +73 -0
  49. package/dist/events/echo-mismatch.d.ts +8 -2
  50. package/dist/events/echo-mismatch.js +33 -5
  51. package/dist/events/event-filters.d.ts +1 -1
  52. package/dist/events/event-filters.js +7 -4
  53. package/dist/events/predicate-eval.d.ts +17 -72
  54. package/dist/events/predicate-eval.js +117 -236
  55. package/dist/events/predicate-parse.js +31 -3
  56. package/dist/events/predicate-route.d.ts +32 -0
  57. package/dist/events/predicate-route.js +102 -0
  58. package/dist/events/predicate-schema.d.ts +99 -0
  59. package/dist/events/predicate-schema.js +309 -0
  60. package/dist/events/predicate.d.ts +8 -0
  61. package/dist/events/predicate.js +296 -22
  62. package/dist/flows/annotate-tools.js +3 -0
  63. package/dist/flows/annotate.js +18 -4
  64. package/dist/flows/coverage.d.ts +38 -5
  65. package/dist/flows/coverage.js +30 -4
  66. package/dist/flows/decision.d.ts +15 -0
  67. package/dist/flows/decision.js +1 -1
  68. package/dist/flows/flow-classify.js +1 -1
  69. package/dist/flows/flow-replay-run.js +8 -1
  70. package/dist/flows/flow-tools.js +21 -5
  71. package/dist/flows/heal-run.js +1 -1
  72. package/dist/flows/replay.js +3 -0
  73. package/dist/honesty/accepted-write.d.ts +3 -0
  74. package/dist/honesty/accepted-write.js +8 -3
  75. package/dist/honesty/already-true.js +15 -0
  76. package/dist/honesty/blind-spots.js +10 -2
  77. package/dist/honesty/honesty.d.ts +11 -0
  78. package/dist/honesty/honesty.js +1 -0
  79. package/dist/honesty/uncaptured-bodies.d.ts +4 -2
  80. package/dist/honesty/uncaptured-bodies.js +9 -2
  81. package/dist/honesty/unread-outcome.d.ts +8 -0
  82. package/dist/honesty/unread-outcome.js +36 -9
  83. package/dist/honesty/unsettled.d.ts +49 -0
  84. package/dist/honesty/unsettled.js +82 -0
  85. package/dist/honesty/verified.d.ts +36 -3
  86. package/dist/honesty/verified.js +54 -11
  87. package/dist/http-server.d.ts +19 -0
  88. package/dist/http-server.js +202 -4
  89. package/dist/impact/impact-recorder.d.ts +23 -0
  90. package/dist/impact/impact-recorder.js +76 -0
  91. package/dist/impact/impact-store.d.ts +47 -0
  92. package/dist/impact/impact-store.js +171 -0
  93. package/dist/index.d.ts +7 -0
  94. package/dist/index.js +47 -10
  95. package/dist/init/agent-rules.d.ts +36 -0
  96. package/dist/init/agent-rules.js +132 -22
  97. package/dist/init/astro-patch.d.ts +2 -1
  98. package/dist/init/astro-patch.js +38 -6
  99. package/dist/init/capabilities.d.ts +22 -0
  100. package/dist/init/capabilities.js +76 -0
  101. package/dist/init/confirm.d.ts +114 -0
  102. package/dist/init/confirm.js +165 -0
  103. package/dist/init/connect-steps.d.ts +2 -0
  104. package/dist/init/connect-steps.js +50 -0
  105. package/dist/init/cra.js +3 -2
  106. package/dist/init/csp-check.d.ts +38 -0
  107. package/dist/init/csp-check.js +92 -0
  108. package/dist/init/csp-doctor.d.ts +25 -0
  109. package/dist/init/csp-doctor.js +49 -0
  110. package/dist/init/cursor.js +6 -9
  111. package/dist/init/detect.d.ts +8 -0
  112. package/dist/init/detect.js +33 -3
  113. package/dist/init/mcp-clients.d.ts +1 -0
  114. package/dist/init/mcp-clients.js +51 -7
  115. package/dist/init/mcp.d.ts +15 -0
  116. package/dist/init/mcp.js +19 -0
  117. package/dist/init/non-js-project.js +29 -5
  118. package/dist/init/plan-framework.d.ts +10 -0
  119. package/dist/init/plan-framework.js +78 -16
  120. package/dist/init/plan.d.ts +47 -6
  121. package/dist/init/plan.js +228 -69
  122. package/dist/init/run.d.ts +24 -2
  123. package/dist/init/run.js +157 -45
  124. package/dist/init/slash-command.d.ts +1 -1
  125. package/dist/init/slash-command.js +54 -6
  126. package/dist/init/snippets.d.ts +45 -5
  127. package/dist/init/snippets.js +194 -42
  128. package/dist/init/vite-config.js +53 -5
  129. package/dist/input/network-mock-tools.d.ts +19 -0
  130. package/dist/input/network-mock-tools.js +37 -5
  131. package/dist/input/scroll-find.d.ts +6 -0
  132. package/dist/input/scroll-find.js +17 -2
  133. package/dist/input/scroll-tools.js +4 -0
  134. package/dist/journal/attach-journal.d.ts +9 -1
  135. package/dist/journal/attach-journal.js +13 -2
  136. package/dist/journal/journal-query.d.ts +13 -0
  137. package/dist/journal/journal-query.js +28 -3
  138. package/dist/journal/workspace-gitignore.d.ts +10 -0
  139. package/dist/journal/workspace-gitignore.js +59 -0
  140. package/dist/license/license.js +1 -1
  141. package/dist/mcp/mcp-proxy.d.ts +35 -30
  142. package/dist/mcp/mcp-proxy.js +306 -104
  143. package/dist/mcp/mcp.d.ts +10 -1
  144. package/dist/mcp/mcp.js +70 -34
  145. package/dist/mcp/proxy-handshake.d.ts +82 -1
  146. package/dist/mcp/proxy-handshake.js +109 -2
  147. package/dist/mcp/proxy-lifecycle.d.ts +11 -2
  148. package/dist/mcp/proxy-lifecycle.js +12 -3
  149. package/dist/mcp/proxy-log.d.ts +63 -0
  150. package/dist/mcp/proxy-log.js +132 -0
  151. package/dist/mcp/server-instructions.d.ts +17 -0
  152. package/dist/mcp/server-instructions.js +56 -0
  153. package/dist/mcp/shared-params.d.ts +27 -0
  154. package/dist/mcp/shared-params.js +36 -0
  155. package/dist/pool/browser-pool.d.ts +22 -2
  156. package/dist/pool/browser-pool.js +44 -4
  157. package/dist/project/learned-routes.d.ts +24 -0
  158. package/dist/project/learned-routes.js +63 -0
  159. package/dist/project/project-store.d.ts +6 -0
  160. package/dist/project/project-store.js +25 -1
  161. package/dist/project/reticle-dir.d.ts +2 -0
  162. package/dist/project/reticle-dir.js +1 -0
  163. package/dist/session/connection-memory.d.ts +59 -0
  164. package/dist/session/connection-memory.js +108 -0
  165. package/dist/session/dev-command.d.ts +26 -0
  166. package/dist/session/dev-command.js +89 -0
  167. package/dist/session/dev-server-probe.d.ts +68 -0
  168. package/dist/session/dev-server-probe.js +102 -7
  169. package/dist/session/last-act.d.ts +26 -0
  170. package/dist/session/last-act.js +35 -1
  171. package/dist/session/live-control-tools.js +42 -5
  172. package/dist/session/no-session-diagnosis.d.ts +67 -2
  173. package/dist/session/no-session-diagnosis.js +236 -27
  174. package/dist/session/no-session-next-action.d.ts +46 -0
  175. package/dist/session/no-session-next-action.js +85 -0
  176. package/dist/session/no-session-watch.d.ts +40 -1
  177. package/dist/session/no-session-watch.js +174 -8
  178. package/dist/session/pending-commands.d.ts +12 -0
  179. package/dist/session/pending-commands.js +13 -1
  180. package/dist/session/ref-provenance.d.ts +54 -0
  181. package/dist/session/ref-provenance.js +61 -0
  182. package/dist/session/session-lease.js +1 -1
  183. package/dist/session/session-manager.d.ts +4 -0
  184. package/dist/session/session-manager.js +35 -5
  185. package/dist/session/session.d.ts +10 -1
  186. package/dist/session/session.js +146 -5
  187. package/dist/telemetry/app-instrumented.d.ts +8 -0
  188. package/dist/telemetry/app-instrumented.js +10 -0
  189. package/dist/telemetry/automation-hint.d.ts +17 -0
  190. package/dist/telemetry/automation-hint.js +71 -0
  191. package/dist/telemetry/bug-found.d.ts +15 -17
  192. package/dist/telemetry/bug-found.js +52 -21
  193. package/dist/telemetry/cli-telemetry.js +7 -1
  194. package/dist/telemetry/daemon-telemetry.js +24 -0
  195. package/dist/telemetry/feedback.js +1 -1
  196. package/dist/telemetry/init-telemetry.js +9 -1
  197. package/dist/telemetry/install-source.d.ts +56 -0
  198. package/dist/telemetry/install-source.js +74 -0
  199. package/dist/telemetry/instrumentation-stall.d.ts +50 -0
  200. package/dist/telemetry/instrumentation-stall.js +90 -0
  201. package/dist/telemetry/run-telemetry.js +4 -1
  202. package/dist/telemetry/session-metrics.d.ts +8 -0
  203. package/dist/telemetry/session-metrics.js +15 -0
  204. package/dist/telemetry/telemetry.d.ts +7 -1
  205. package/dist/telemetry/telemetry.js +26 -2
  206. package/dist/telemetry/tool-refused.d.ts +19 -0
  207. package/dist/telemetry/tool-refused.js +55 -0
  208. package/dist/telemetry/verification-of.js +46 -7
  209. package/dist/temp-dir.d.ts +27 -0
  210. package/dist/temp-dir.js +46 -0
  211. package/dist/tools/act-tools.js +209 -28
  212. package/dist/tools/assert-grade.d.ts +1 -1
  213. package/dist/tools/assert-grade.js +27 -5
  214. package/dist/tools/assert-verdict.js +49 -7
  215. package/dist/tools/browser-tools.js +10 -0
  216. package/dist/tools/contract-tools.js +4 -0
  217. package/dist/tools/dynamic-tools.js +16 -7
  218. package/dist/tools/error-recovery.d.ts +10 -0
  219. package/dist/tools/error-recovery.js +73 -9
  220. package/dist/tools/feedback-invite.js +1 -1
  221. package/dist/tools/invoke-tool.js +159 -26
  222. package/dist/tools/lease-hint.d.ts +30 -8
  223. package/dist/tools/lease-hint.js +65 -14
  224. package/dist/tools/lease-tools.d.ts +40 -1
  225. package/dist/tools/lease-tools.js +181 -83
  226. package/dist/tools/navigate-result.js +1 -1
  227. package/dist/tools/observe-tools.js +10 -4
  228. package/dist/tools/observed-nothing.js +1 -1
  229. package/dist/tools/react-grace.d.ts +52 -0
  230. package/dist/tools/react-grace.js +90 -0
  231. package/dist/tools/read-tools.js +67 -5
  232. package/dist/tools/resolve-target.d.ts +33 -0
  233. package/dist/tools/resolve-target.js +53 -0
  234. package/dist/tools/settle-in-flight.d.ts +94 -0
  235. package/dist/tools/settle-in-flight.js +146 -0
  236. package/dist/tools/snapshot-delta.d.ts +10 -0
  237. package/dist/tools/snapshot-delta.js +194 -9
  238. package/dist/tools/tool-kit.d.ts +8 -0
  239. package/dist/tools/tool-surface.d.ts +60 -0
  240. package/dist/tools/tool-surface.js +86 -1
  241. package/dist/tools/tools.js +61 -8
  242. package/dist/tools/unadvertised-help.js +9 -6
  243. package/docs/README.md +55 -11
  244. package/docs/actions.mdx +120 -0
  245. package/docs/agent-cheatsheet.md +95 -29
  246. package/docs/architecture.md +52 -35
  247. package/docs/benchmarks.md +127 -75
  248. package/docs/best-practices.mdx +216 -0
  249. package/docs/capabilities.mdx +534 -0
  250. package/docs/cli/affected.mdx +53 -0
  251. package/docs/cli/capsules.mdx +70 -0
  252. package/docs/cli/cloud.mdx +153 -0
  253. package/docs/cli/doctor.mdx +109 -0
  254. package/docs/cli/drive.mdx +74 -0
  255. package/docs/cli/feedback.mdx +67 -0
  256. package/docs/cli/gate.mdx +64 -0
  257. package/docs/cli/help.mdx +94 -0
  258. package/docs/cli/hunt.mdx +73 -0
  259. package/docs/cli/identify.mdx +76 -0
  260. package/docs/cli/init.mdx +121 -0
  261. package/docs/cli/kill.mdx +91 -0
  262. package/docs/cli/license.mdx +48 -0
  263. package/docs/cli/mcp.mdx +61 -0
  264. package/docs/cli/open.mdx +74 -0
  265. package/docs/cli/restart.mdx +60 -0
  266. package/docs/cli/rollback.mdx +35 -0
  267. package/docs/cli/serve.mdx +69 -0
  268. package/docs/cli/status.mdx +88 -0
  269. package/docs/cli/stop.mdx +64 -0
  270. package/docs/cli/telemetry.mdx +57 -0
  271. package/docs/cli/update.mdx +52 -0
  272. package/docs/cli/verify.mdx +76 -0
  273. package/docs/cli/version.mdx +39 -0
  274. package/docs/cli/watch.mdx +62 -0
  275. package/docs/cli.mdx +241 -0
  276. package/docs/debugging.md +16 -10
  277. package/docs/deploy-checks.md +45 -12
  278. package/docs/desktop.mdx +384 -0
  279. package/docs/docs.json +364 -0
  280. package/docs/enterprise.md +22 -16
  281. package/docs/faq.mdx +102 -0
  282. package/docs/fixtures.md +13 -7
  283. package/docs/flows.md +29 -23
  284. package/docs/for-agents.md +71 -0
  285. package/docs/frameworks.mdx +238 -0
  286. package/docs/gate-plan.md +48 -42
  287. package/docs/gates.md +28 -22
  288. package/docs/getting-started.md +129 -77
  289. package/docs/human-control.md +24 -18
  290. package/docs/index.mdx +143 -0
  291. package/docs/install-agentic.mdx +224 -0
  292. package/docs/install-manual.mdx +196 -0
  293. package/docs/instrumentation.mdx +238 -0
  294. package/docs/integration-patterns.md +41 -35
  295. package/docs/local-registry.md +19 -13
  296. package/docs/multi-agent-testing.md +19 -13
  297. package/docs/packages/babel-plugin.mdx +79 -0
  298. package/docs/packages/browser.mdx +111 -0
  299. package/docs/packages/core.mdx +116 -0
  300. package/docs/packages/electron.mdx +85 -0
  301. package/docs/packages/eslint-plugin.mdx +86 -0
  302. package/docs/packages/next.mdx +89 -0
  303. package/docs/packages/react.mdx +91 -0
  304. package/docs/packages/server.mdx +98 -0
  305. package/docs/packages/tauri.mdx +63 -0
  306. package/docs/packages/test.mdx +119 -0
  307. package/docs/packages/vite-plugin.mdx +94 -0
  308. package/docs/packages.mdx +218 -0
  309. package/docs/platform-integration.md +35 -26
  310. package/docs/predicates.mdx +248 -0
  311. package/docs/quickstart.mdx +257 -0
  312. package/docs/recipes.mdx +282 -0
  313. package/docs/skill-file.mdx +107 -0
  314. package/docs/state-management.mdx +199 -0
  315. package/docs/style.css +14 -0
  316. package/docs/system-map.md +50 -33
  317. package/docs/telemetry-contract.md +106 -52
  318. package/docs/telemetry-events.mdx +475 -0
  319. package/docs/telemetry.md +63 -55
  320. package/docs/testing.md +44 -6
  321. package/docs/token-efficiency.md +37 -27
  322. package/docs/tools-act-and-wait.mdx +173 -0
  323. package/docs/tools-act-sequence.mdx +137 -0
  324. package/docs/tools-act.mdx +95 -0
  325. package/docs/tools-assert.mdx +129 -0
  326. package/docs/tools-console.mdx +63 -0
  327. package/docs/tools-inspect.mdx +88 -0
  328. package/docs/tools-navigate.mdx +99 -0
  329. package/docs/tools-network.mdx +119 -0
  330. package/docs/tools-observe.mdx +145 -0
  331. package/docs/tools-overview.mdx +160 -0
  332. package/docs/tools-query.mdx +126 -0
  333. package/docs/tools-session-and-feedback.mdx +112 -0
  334. package/docs/tools-sessions.mdx +94 -0
  335. package/docs/tools-snapshot.mdx +129 -0
  336. package/docs/tools-state.mdx +104 -0
  337. package/docs/tools-tools-and-run.mdx +156 -0
  338. package/docs/tools-wait-for.mdx +85 -0
  339. package/docs/troubleshooting.mdx +263 -0
  340. package/docs/usage.md +209 -165
  341. package/docs/vs-chrome-devtools-mcp.mdx +123 -0
  342. package/docs/vs-playwright-mcp.mdx +125 -0
  343. package/docs/vs-screenshots.mdx +137 -0
  344. package/docs/what-is-reticle.mdx +63 -0
  345. package/docs/why-reticle.mdx +109 -0
  346. package/package.json +5 -5
  347. package/docs/desktop-apps.md +0 -256
  348. package/docs/matrix/2.5.0/claude-code-machine.json +0 -19
  349. package/docs/matrix/2.5.0/codex-machine.json +0 -20
  350. package/docs/matrix/2.5.0/cursor-machine.json +0 -22
  351. package/docs/matrix/2.5.0/gemini-machine.json +0 -22
  352. package/docs/matrix/2.5.0/opencode-machine.json +0 -22
  353. package/docs/matrix/2.5.0/vscode-machine.json +0 -22
  354. package/docs/matrix/2.5.0/windsurf-machine.json +0 -22
  355. package/docs/matrix/MATRIX.md +0 -26
  356. package/docs/matrix/README.md +0 -59
  357. package/docs/mint.json +0 -61
@@ -168,12 +168,42 @@ const INSTALL_ARGS = {
168
168
  [PackageManager.BUN]: ['add', '-d'],
169
169
  [PackageManager.NPM]: ['i', '-D'],
170
170
  };
171
+ /**
172
+ * Flags added only to the install we RUN, never to the one we print.
173
+ *
174
+ * The install is a child process whose output lands above ours. Measured on a real install: the run
175
+ * opened with "added 602 packages", a funding notice, and "14 vulnerabilities (7 moderate, 7 high)"
176
+ * with `npm audit fix` advice, before one line of Reticle output. A user's first impression of a
177
+ * verification tool was a wall of somebody else's security warnings, at exactly the moment they are
178
+ * deciding whether this tool is careful — and that audit summary describes their existing dependency
179
+ * tree, which our two dev packages neither caused nor can fix.
180
+ *
181
+ * Kept off `installCommand`, which is the string shown in the plan and the one a user copies when
182
+ * running it by hand: nobody should be taught to type our noise-suppression flags.
183
+ *
184
+ * Quieted, never silenced — the exit code and stderr are untouched, so a real failure of the step
185
+ * everything downstream depends on stays as loud as it was.
186
+ *
187
+ * npm only: pnpm, yarn and bun reject these, and an unknown flag would turn a working install into a
188
+ * hard failure, which is the opposite of the problem being fixed.
189
+ */
190
+ const QUIET_INSTALL_ARGS = {
191
+ [PackageManager.NPM]: ['--no-audit', '--no-fund'],
192
+ };
171
193
  /** Build a dev-dependency install command for one or more packages (e.g. the kit + its build plugin). */
172
194
  export function installCommandParts(pm, pkgs) {
173
195
  const list = 'string' === typeof pkgs ? [pkgs] : pkgs;
174
- return { command: pm, args: [...INSTALL_ARGS[pm], ...list] };
196
+ return { command: pm, args: [...INSTALL_ARGS[pm], ...list, ...(QUIET_INSTALL_ARGS[pm] ?? [])] };
175
197
  }
198
+ /**
199
+ * The install command as a human reads it — and deliberately NOT `installCommandParts` joined.
200
+ *
201
+ * This string is what the plan prints and what a user retypes when running the step by hand, so it
202
+ * must not carry the flags we add only to quieten our own child process. Built from `INSTALL_ARGS`
203
+ * directly for that reason; routing it through the parts would put `--no-audit --no-fund` in front of
204
+ * every reader and teach them our noise-suppression as if it were part of installing Reticle.
205
+ */
176
206
  export function installCommand(pm, pkgs) {
177
- const { command, args } = installCommandParts(pm, pkgs);
178
- return `${command} ${args.join(' ')}`;
207
+ const list = 'string' === typeof pkgs ? [pkgs] : pkgs;
208
+ return `${pm} ${[...INSTALL_ARGS[pm], ...list].join(' ')}`;
179
209
  }
@@ -3,6 +3,7 @@ export declare const McpClient: {
3
3
  readonly CURSOR: "cursor";
4
4
  readonly WINDSURF: "windsurf";
5
5
  readonly OPENCODE: "opencode";
6
+ readonly ANTIGRAVITY: "antigravity";
6
7
  readonly CODEX: "codex";
7
8
  readonly GEMINI: "gemini";
8
9
  readonly VSCODE: "vscode";
@@ -18,13 +18,13 @@
18
18
  * an install that reports success and registers nothing, which is the exact failure class this
19
19
  * repo's install gate exists to catch.
20
20
  */
21
- import { NPX, MCP_SERVER_NAME, npxServerArgs } from './mcp.js';
22
- import { RETICLE_NPM_PACKAGE } from '../version/server-version.js';
21
+ import { NPX, MCP_SERVER_NAME, npxServerArgs, isReticleRegistration } from './mcp.js';
23
22
  export const McpClient = {
24
23
  CLAUDE_CODE: 'claude-code',
25
24
  CURSOR: 'cursor',
26
25
  WINDSURF: 'windsurf',
27
26
  OPENCODE: 'opencode',
27
+ ANTIGRAVITY: 'antigravity',
28
28
  CODEX: 'codex',
29
29
  GEMINI: 'gemini',
30
30
  VSCODE: 'vscode',
@@ -107,13 +107,57 @@ export const MCP_CLIENTS = [
107
107
  {
108
108
  id: McpClient.OPENCODE,
109
109
  label: 'OpenCode',
110
- scope: ConfigScope.PROJECT,
111
- relPath: 'opencode.json',
110
+ /**
111
+ * HOME, not PROJECT — OpenCode is installed globally and configured globally, like Cursor.
112
+ *
113
+ * It was project-scoped as `opencode.json`, and registration is gated on the marker already
114
+ * existing, so a project that had never written one was skipped in SILENCE: the user has OpenCode
115
+ * installed, `init` says nothing about it, and the tools never appear. In the field every OpenCode
116
+ * user connected a client and produced zero tool calls and zero app connections, which is what
117
+ * "you were never wired" looks like from outside.
118
+ *
119
+ * Path verified against a real install (OpenCode 1.3.17), not recalled. The extension is `.jsonc`,
120
+ * which the old project marker could not have matched even where a project config existed. JSONC
121
+ * permits comments, and a config that genuinely has them fails to parse — which `mergeClientConfig`
122
+ * already answers with MANUAL and a printed block, rather than rewriting somebody's file and
123
+ * dropping their comments.
124
+ */
125
+ scope: ConfigScope.HOME,
126
+ relPath: '.config/opencode/opencode.jsonc',
112
127
  format: ConfigFormat.JSON,
113
128
  serversKey: 'mcp',
114
129
  entry: openCodeEntry,
115
130
  docs: 'https://opencode.ai/docs/config — `mcp` key, type:"local", command is an array',
116
131
  },
132
+ {
133
+ id: McpClient.ANTIGRAVITY,
134
+ label: 'Antigravity',
135
+ /**
136
+ * Nine users connected an MCP client through Antigravity and drove nothing at all.
137
+ *
138
+ * `init` did not know this client, so they hand-wired a registration - the connections are in the
139
+ * field data, so they got that far - and then never ran `init`, never instrumented an app, and
140
+ * never called a tool. Nothing in that state tells anyone there is a second half.
141
+ *
142
+ * Path and shape from Google's documentation rather than recall: `mcpServers`, at
143
+ * `~/.gemini/config/mcp_config.json`, and one file serves the 2.0 IDE, the CLI and the SDK. Same
144
+ * `command`/`args` object Cursor, Windsurf and Gemini CLI already use.
145
+ *
146
+ * It shares the `~/.gemini` tree with Gemini CLI, which is why the marker matters: registration is
147
+ * gated on the marker DIRECTORY, and these resolve to `.gemini/config` and `.gemini` respectively,
148
+ * so having one installed cannot make `init` write a config for the other.
149
+ *
150
+ * NOT verified against a running install. The path is documented, the merge is the shared JSON
151
+ * path that every other client here uses, and an unparseable config still degrades to a printed
152
+ * block rather than a rewrite.
153
+ */
154
+ scope: ConfigScope.HOME,
155
+ relPath: '.gemini/config/mcp_config.json',
156
+ format: ConfigFormat.JSON,
157
+ serversKey: 'mcpServers',
158
+ entry: commandArgsEntry,
159
+ docs: 'https://antigravity.google/docs/mcp — ~/.gemini/config/mcp_config.json, `mcpServers` key',
160
+ },
117
161
  {
118
162
  id: McpClient.CODEX,
119
163
  label: 'Codex CLI',
@@ -163,7 +207,8 @@ function parseConfig(existing) {
163
207
  *
164
208
  * What IS repaired is a stale entry of our own shape — an old pin, a moved command — which
165
209
  * presence-only idempotency reported as "already registered" and never fixed, so an upgrade could
166
- * not repair the thing an upgrade exists to repair.
210
+ * not repair the thing an upgrade exists to repair — and a WRONG one, naming a Reticle package that
211
+ * has no MCP server in it (see isReticleRegistration).
167
212
  */
168
213
  function leaveEntryAlone(existing, spec) {
169
214
  if (JSON.stringify(existing) === JSON.stringify(spec.entry()))
@@ -173,8 +218,7 @@ function leaveEntryAlone(existing, spec) {
173
218
  const record = existing;
174
219
  // Both shapes carry the package name somewhere in a string; find it without assuming which field.
175
220
  const tokens = [record.command, record.args].flat().filter((v) => 'string' === typeof v);
176
- const ours = tokens.some((t) => t === NPX) && tokens.some((t) => t.includes(RETICLE_NPM_PACKAGE));
177
- return !ours;
221
+ return !isReticleRegistration(tokens);
178
222
  }
179
223
  /**
180
224
  * Merge our server into this client's config.
@@ -41,6 +41,21 @@ export declare const NPX = "npx";
41
41
  * shape is now repaired on re-run rather than reported "already registered" (see cursor.ts).
42
42
  */
43
43
  export declare function npxServerArgs(): string[];
44
+ /**
45
+ * Is this existing registration one WE are responsible for?
46
+ *
47
+ * Deliberately the SCOPE and not the server package. An entry naming any `@reticlehq/*` package is
48
+ * ours to repair — including one naming the WRONG package, which is the case this widened for:
49
+ * `args: ["@reticlehq/core","mcp"]` was reported from the field, where `core` has no `mcp` bin, so
50
+ * the client showed the server errored with zero tools while `init` reported it already wired and
51
+ * left it alone on every re-run. Every `reticle_*` tool was blocked until a human edited that file.
52
+ *
53
+ * An entry that names no Reticle package at all — a local build, a wrapper script — is still someone
54
+ * else's deliberate choice and is left exactly as it is.
55
+ *
56
+ * @param tokens every string in the entry's command + args, in any of the client shapes.
57
+ */
58
+ export declare function isReticleRegistration(tokens: readonly string[]): boolean;
44
59
  interface ClaudeAddCommand {
45
60
  command: string;
46
61
  args: string[];
package/dist/init/mcp.js CHANGED
@@ -49,6 +49,25 @@ const CLAUDE_CLI = 'claude';
49
49
  export function npxServerArgs() {
50
50
  return [RETICLE_PACKAGE, MCP_SUBCOMMAND];
51
51
  }
52
+ /** The npm scope every Reticle package shares — the marker of a registration we are entitled to fix. */
53
+ const RETICLE_SCOPE = '@reticlehq/';
54
+ /**
55
+ * Is this existing registration one WE are responsible for?
56
+ *
57
+ * Deliberately the SCOPE and not the server package. An entry naming any `@reticlehq/*` package is
58
+ * ours to repair — including one naming the WRONG package, which is the case this widened for:
59
+ * `args: ["@reticlehq/core","mcp"]` was reported from the field, where `core` has no `mcp` bin, so
60
+ * the client showed the server errored with zero tools while `init` reported it already wired and
61
+ * left it alone on every re-run. Every `reticle_*` tool was blocked until a human edited that file.
62
+ *
63
+ * An entry that names no Reticle package at all — a local build, a wrapper script — is still someone
64
+ * else's deliberate choice and is left exactly as it is.
65
+ *
66
+ * @param tokens every string in the entry's command + args, in any of the client shapes.
67
+ */
68
+ export function isReticleRegistration(tokens) {
69
+ return tokens.includes(NPX) && tokens.some((t) => t.includes(RETICLE_SCOPE));
70
+ }
52
71
  /** The full `npx …` invocation — the tail after `claude mcp add … --`. */
53
72
  function serverInvocation() {
54
73
  return [NPX, ...npxServerArgs()];
@@ -29,7 +29,13 @@ const ECOSYSTEM_MARKERS = [
29
29
  ['pom.xml', 'Java'],
30
30
  ['build.gradle', 'Java'],
31
31
  ['mix.exs', 'Elixir'],
32
+ // Not like the others. Every ecosystem above can grow a JS front end that Reticle instruments
33
+ // perfectly well, so their message ends with a lead. Flutter web paints into a canvas, and there
34
+ // is no DOM behind it at any path, so the honest answer is a named refusal.
35
+ ['pubspec.yaml', 'Flutter'],
32
36
  ];
37
+ /** The one ecosystem where no directory, front end or flag could ever help. */
38
+ const FLUTTER = 'Flutter';
33
39
  /** The ecosystem this directory looks like, or undefined when nothing says. */
34
40
  export function detectNonJsEcosystem(exists) {
35
41
  for (const [marker, name] of ECOSYSTEM_MARKERS) {
@@ -51,10 +57,28 @@ export function noPackageJsonMessage(exists) {
51
57
  return ('No package.json found here, and no app directory beneath it either. Run `reticle init` from ' +
52
58
  "your app's directory, or from a repo root that contains it.");
53
59
  }
60
+ if (ecosystem === FLUTTER) {
61
+ // An agent on a Flutter workspace asked us to "support Flutter, or clearly identify it as
62
+ // unsupported during init". The second is the truthful one, and saying it by name in one line
63
+ // is the difference between an agent that stops and an agent that spends an hour looking for
64
+ // the package.json we told it was missing.
65
+ return ('This is a Flutter project. Reticle cannot instrument it, and no directory or flag will ' +
66
+ 'change that: Reticle reads the DOM of a running page, and Flutter web paints its entire UI ' +
67
+ 'into a single canvas element with no DOM behind it. Nothing here is missing or misconfigured. ' +
68
+ 'If this repo also contains an ordinary web app with its own package.json, run `reticle init` ' +
69
+ 'inside that directory instead.');
70
+ }
54
71
  return (`This looks like a ${ecosystem} project, and there is no package.json here or in any app ` +
55
- 'directory beneath it. Reticle instruments a page by having its SDK imported into the app’s own ' +
56
- 'JavaScript build — so a server-rendered app with no JS build has nowhere to load it from, and ' +
57
- 'there is no directory you could run this from that would change that. ' +
58
- 'If this project does have a JS front end (a `frontend/`, `client/` or `assets/` directory with ' +
59
- 'its own package.json), run `reticle init` there, or point at it with `--app <dir>`.');
72
+ 'directory beneath it. That is not a blocker: Reticle needs its SDK loaded by the page, not ' +
73
+ 'built by npm, and a page with no build step can load it from a URL. ' +
74
+ // The old message ended at "there is no directory you could run this from that would change
75
+ // that", which read as a refusal and was acted on as one — agents went looking for a bundler,
76
+ // or for a standalone build to inject by hand, or gave up and used a different tool. The
77
+ // capability was there the whole time; only the sentence was missing. Proven end to end on a
78
+ // page served by `python3 -m http.server` before this line was written.
79
+ 'Add the script-tag snippet below to a template you only serve in development, then reload the ' +
80
+ 'page. ' +
81
+ 'If this project ALSO has a JS front end (a `frontend/`, `client/` or `assets/` directory with ' +
82
+ 'its own package.json), running `reticle init` there instead gives you source mapping and ' +
83
+ 'framework state as well: point at it with `--app <dir>`.');
60
84
  }
@@ -57,3 +57,13 @@ export declare function svelteKitSteps(input: PlanInput): Step[];
57
57
  * and a half-edited build config is worse than a documented manual step.
58
58
  */
59
59
  export declare function astroSteps(input: PlanInput): Step[];
60
+ /**
61
+ * A Content-Security-Policy whose `connect-src` excludes the bridge, said out loud at install time.
62
+ *
63
+ * Both reported cases were Next apps where `init` printed success for every step and the app then
64
+ * never connected: the browser blocked the WebSocket and reported it in its own console, which
65
+ * nothing on this side reads. A NOTICE rather than a step, because editing someone's security policy
66
+ * is theirs to do — but it carries the exact text to paste, which is the difference between a
67
+ * warning and a fix.
68
+ */
69
+ export declare function cspStep(input: PlanInput): Step[];
@@ -9,7 +9,9 @@ import { patchAstroConfig, patchAstroLayout } from './astro-patch.js';
9
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';
10
10
  import { PatchKind } from './patch-kind.js';
11
11
  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 { StepStatus } from './plan.js';
12
+ import { RETICLE_CONFIG_FILE, StepStatus } from './plan.js';
13
+ import { RETICLE_DEFAULT_PORT } from '@reticlehq/core';
14
+ import { CSP_STEP_TITLE, cspPlanProblem } from './csp-check.js';
13
15
  /** What adding `reticle()` to a Vite config buys, which differs by framework. */
14
16
  export const VITE_PLUGIN_DETAIL = {
15
17
  /** A plain Vite app gets both halves from the plugin. */
@@ -23,6 +25,36 @@ export const VITE_PLUGIN_DETAIL = {
23
25
  SVELTEKIT: 'add reticle() to plugins (stamps data-reticle-source in .svelte components)',
24
26
  };
25
27
  const CAPABILITIES_TITLE = 'Capabilities + store';
28
+ /**
29
+ * The one step `init` genuinely cannot finish, addressed to the AGENT reading this report.
30
+ *
31
+ * It used to read "Capabilities are empty until you edit that file" and describe the consequence to
32
+ * a human — homework, in a report a human mostly does not read, naming no file to open and no thing
33
+ * to look for. The agent that ran `init` is right there, has the codebase, and can finish this in
34
+ * the same minute; what it needed was the specific instruction, not the rationale.
35
+ *
36
+ * What is left is exactly what could not be PROVEN from source: which atoms/actor/queryClient an
37
+ * adapter-wrapped store should be built from, and which elements matter enough to name. `init`
38
+ * emits nothing it cannot prove, because a wrong import here throws on every dev page load — worse
39
+ * than an empty file.
40
+ */
41
+ const CAPABILITIES_TODO_TITLE = 'AGENT: finish the capabilities file';
42
+ 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` +
51
+ `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.`);
57
+ }
26
58
  /**
27
59
  * The dev module carrying `registerCapabilities` / `registerStore`.
28
60
  *
@@ -37,23 +69,32 @@ function capabilitiesStep(input) {
37
69
  title: CAPABILITIES_TITLE,
38
70
  target: VITE_DEV_MODULE_PATH,
39
71
  status: StepStatus.ALREADY,
40
- detail: 'file exists — left alone, it is yours to edit',
72
+ detail: 'file exists, left alone, it is yours to edit',
41
73
  },
42
74
  ];
43
75
  }
44
76
  const testids = input.testids ?? [];
45
77
  const stores = input.storeHints ?? [];
78
+ const wired = input.foundStores ?? [];
46
79
  const found = testids.length > 0
47
80
  ? `${String(testids.length)} data-testid values`
48
81
  : 'no data-testid values yet';
49
- const nothingToRegister = 0 === testids.length && 0 === stores.length;
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;
50
84
  return [
51
85
  {
52
86
  title: CAPABILITIES_TITLE,
53
87
  target: VITE_DEV_MODULE_PATH,
54
88
  status: StepStatus.APPLY,
55
- detail: `${found}; ${stores.length > 0 ? `store: uncomment the ${String(stores.length)} suggested line(s)` : 'no state library detected'}`,
56
- write: { path: VITE_DEV_MODULE_PATH, content: viteDevModuleFile(testids, stores) },
89
+ detail: `${found}; ${wired.length > 0
90
+ ? `registered ${wired.map((s) => `'${s.key}'`).join(', ')} from your source`
91
+ : stores.length > 0
92
+ ? `store: uncomment the ${String(stores.length)} suggested line(s)`
93
+ : 'no state library detected'}`,
94
+ write: {
95
+ path: VITE_DEV_MODULE_PATH,
96
+ content: viteDevModuleFile(testids, stores, wired, input.detection.uiLibrary),
97
+ },
57
98
  dependsOnInstall: true,
58
99
  },
59
100
  // The write is real; what it registers is not. `registerCapabilities({ testids: [], signals: [],
@@ -67,14 +108,10 @@ function capabilitiesStep(input) {
67
108
  ...(nothingToRegister
68
109
  ? [
69
110
  {
70
- title: 'Capabilities are empty until you edit that file',
111
+ title: CAPABILITIES_TODO_TITLE,
71
112
  target: VITE_DEV_MODULE_PATH,
72
113
  status: StepStatus.NOTICE,
73
- detail: 'the module was written but registers nothing — no data-testid values were found and ' +
74
- 'no state library was detected, so `hasCapabilities` stays false and reticle_state ' +
75
- 'has nothing to read. Add data-testid to the elements your main flow touches, or ' +
76
- 'register a store in that file, and the agent gains what the app BELIEVES rather than ' +
77
- 'only what it rendered.',
114
+ detail: capabilitiesTodo(VITE_DEV_MODULE_PATH, stores),
78
115
  },
79
116
  ]
80
117
  : []),
@@ -94,7 +131,7 @@ function viteConfigSteps(input, detail) {
94
131
  title: 'Vite plugin',
95
132
  target: 'vite.config',
96
133
  status: StepStatus.MANUAL,
97
- detail: viteManual(port),
134
+ detail: viteManual(port, input.detection.uiLibrary),
98
135
  },
99
136
  ];
100
137
  }
@@ -115,7 +152,7 @@ function viteConfigSteps(input, detail) {
115
152
  title: 'Vite plugin',
116
153
  target: cfg.path,
117
154
  status: StepStatus.MANUAL,
118
- detail: `${patch.reason}\n\n${viteManual(port)}`,
155
+ detail: `${patch.reason}\n\n${viteManual(port, input.detection.uiLibrary)}`,
119
156
  },
120
157
  ];
121
158
  }
@@ -177,7 +214,10 @@ export function nextSteps(input) {
177
214
  detail: 'create dev-only connect component',
178
215
  write: {
179
216
  path: devPath,
180
- content: nextReticleDevFile(input.options.port, input.options.projectId, input.testids ?? [], input.storeHints ?? []),
217
+ content: nextReticleDevFile(input.options.port, input.options.projectId, input.testids ?? [], input.storeHints ?? [],
218
+ // Next's dev module is not a sibling of `src/` — its imports are resolved from wherever
219
+ // the component actually lands (`app/`, or `src/app/` in a --src-dir app).
220
+ input.nextFoundStores ?? []),
181
221
  },
182
222
  dependsOnInstall: true,
183
223
  };
@@ -338,7 +378,7 @@ export function svelteKitSteps(input) {
338
378
  detail: 'create dev-only client connect (SvelteKit renders via app.html)',
339
379
  write: {
340
380
  path: SVELTEKIT_HOOKS_PATH,
341
- content: svelteKitHooksFile(input.options.port, input.options.projectId),
381
+ content: svelteKitHooksFile(input.options.port, input.options.projectId, input.detection.uiLibrary),
342
382
  },
343
383
  dependsOnInstall: true,
344
384
  },
@@ -375,7 +415,7 @@ export function astroSteps(input) {
375
415
  // single recipe that does the whole job.
376
416
  const manualWithLayout = astroManual(input.options.port, input.options.projectId, layout.path);
377
417
  const configPatch = patchAstroConfig(config.source);
378
- const layoutPatch = patchAstroLayout(layout.source, input.options.port, input.options.projectId);
418
+ const layoutPatch = patchAstroLayout(layout.source, input.options.port, input.options.projectId, input.detection.uiLibrary);
379
419
  if (configPatch.kind === PatchKind.MANUAL || layoutPatch.kind === PatchKind.MANUAL) {
380
420
  return [
381
421
  {
@@ -391,3 +431,25 @@ export function astroSteps(input) {
391
431
  patchStep('Connect snippet (Astro)', layout.path, layoutPatch, 'add the dev-only connect <script> before </body>', manualWithLayout),
392
432
  ];
393
433
  }
434
+ /**
435
+ * A Content-Security-Policy whose `connect-src` excludes the bridge, said out loud at install time.
436
+ *
437
+ * Both reported cases were Next apps where `init` printed success for every step and the app then
438
+ * never connected: the browser blocked the WebSocket and reported it in its own console, which
439
+ * nothing on this side reads. A NOTICE rather than a step, because editing someone's security policy
440
+ * is theirs to do — but it carries the exact text to paste, which is the difference between a
441
+ * warning and a fix.
442
+ */
443
+ export function cspStep(input) {
444
+ const problem = cspPlanProblem([input.nextConfigSource, input.nextLayout?.source], input.options.port ?? RETICLE_DEFAULT_PORT);
445
+ if (problem === undefined)
446
+ return [];
447
+ return [
448
+ {
449
+ title: CSP_STEP_TITLE,
450
+ target: input.nextConfigFile ?? RETICLE_CONFIG_FILE,
451
+ status: StepStatus.NOTICE,
452
+ detail: problem,
453
+ },
454
+ ];
455
+ }
@@ -3,7 +3,8 @@
3
3
  * contents, produce an ordered list of steps — each marked apply / manual / already / skip. The
4
4
  * runner performs the `write` side-effects; this module decides *what* should happen.
5
5
  */
6
- import { Framework, type Detection } from './detect.js';
6
+ import { Framework, UiLibrary, type Detection } from './detect.js';
7
+ import type { FoundStore } from './capabilities.js';
7
8
  import { type McpClient } from './mcp-clients.js';
8
9
  /**
9
10
  * Pin the SDK to the CLI's own version.
@@ -15,14 +16,20 @@ import { type McpClient } from './mcp-clients.js';
15
16
  * irrelevant, and a skewed pair impossible to install by accident.
16
17
  */
17
18
  export declare function pinnedPackages(packages: readonly string[], version: string | undefined): readonly string[];
18
- /** The dev-dependencies `reticle init` installs for a given framework — kit first, build plugin next. */
19
- export declare function frameworkPackages(framework: Framework): readonly string[];
19
+ /**
20
+ * The dev-dependencies `reticle init` installs — kit (or sensor) first, build plugin next.
21
+ *
22
+ * `uiLibrary` matters because the framework does not always name the renderer. The rule below was
23
+ * already written for Nuxt, correctly, and applied only there: a Vue app on plain Vite is
24
+ * `Framework.VITE` and a SvelteKit app renders Svelte, and both were being handed the React kit
25
+ * right after `init` had detected the real UI library and said so on screen.
26
+ */
27
+ export declare function frameworkPackages(framework: Framework, uiLibrary?: UiLibrary): readonly string[];
20
28
  /** Exported so the init telemetry can tell an MCP-registration failure from a dependency install. */
21
29
  export declare const MCP_TARGET = "global (claude user scope)";
22
- /** True when this step is what makes the app dial the daemon. */
23
- export declare function isConnectStep(title: string): boolean;
24
30
  /** The step that runs the package manager — the other thing that commonly fails on a user's machine. */
25
31
  export declare const DEPS_TARGET = "package.json";
32
+ export declare const RETICLE_CONFIG_FILE = ".reticle.json";
26
33
  export declare const StepStatus: {
27
34
  readonly APPLY: "apply";
28
35
  readonly MANUAL: "manual";
@@ -77,6 +84,13 @@ export interface Step {
77
84
  }
78
85
  export interface Plan {
79
86
  framework: Framework;
87
+ /**
88
+ * The renderer this app actually uses, carried so every consumer agrees on WHICH packages the
89
+ * plan installed. The retry guard checks node_modules for exactly those names; without this it
90
+ * looked for `@reticlehq/react` in a Vue app that had correctly been given the sensor, decided the
91
+ * install had failed, and skipped every wiring step on the retry.
92
+ */
93
+ uiLibrary: UiLibrary;
80
94
  steps: Step[];
81
95
  }
82
96
  export interface PlanInput {
@@ -144,6 +158,10 @@ export interface PlanInput {
144
158
  testids?: readonly string[] | undefined;
145
159
  /** Ready-to-uncomment `registerStore` lines for the state libraries the app actually depends on. */
146
160
  storeHints?: readonly string[] | undefined;
161
+ /** Store instances found in the app's own source — imported and registered outright, not hinted. */
162
+ foundStores?: readonly FoundStore[] | undefined;
163
+ /** The same stores, with specifiers resolved from Next's dev-module directory instead of `src/`. */
164
+ nextFoundStores?: readonly FoundStore[] | undefined;
147
165
  /** Whether src/reticle-dev.ts already exists — it is the one generated file users are meant to edit. */
148
166
  viteDevModuleExists?: boolean | undefined;
149
167
  /** Whether src/hooks.client.ts already exists (SvelteKit idempotency). */
@@ -159,10 +177,19 @@ export interface PlanInput {
159
177
  pairingToken?: string;
160
178
  /** Whether .reticle.json already exists in the project root (idempotency). */
161
179
  reticleConfigExists?: boolean;
180
+ /**
181
+ * Its CONTENT, so an existing config can be checked instead of trusted.
182
+ *
183
+ * Existence alone said "a file is present" and was reported as "this is configured correctly" —
184
+ * see reticleConfigStep for the port that survived every re-run because of it.
185
+ */
186
+ reticleConfigSource?: string | null | undefined;
162
187
  /** Current project-root CLAUDE.md content (for the idempotent agent-rule merge), or null/undefined. */
163
188
  claudeMdContent?: string | null | undefined;
164
- /** Current project-root AGENTS.md content (cross-agent fallback rule), or null/undefined. */
189
+ /** Current project-root AGENTS.md content (the cross-agent rule), or null/undefined. */
165
190
  agentsMdContent?: string | null | undefined;
191
+ /** Current project-root RETICLE.md content (the full rules), or null when absent. */
192
+ reticleMdContent?: string | null | undefined;
166
193
  /**
167
194
  * Current .cursor/rules/reticle.mdc content, or null when absent.
168
195
  *
@@ -175,6 +202,20 @@ export interface PlanInput {
175
202
  claudeCommandContent?: string | null | undefined;
176
203
  /** Current .cursor/commands/reticle.md content, or null when absent. */
177
204
  cursorCommandContent?: string | null | undefined;
205
+ /**
206
+ * Absolute directory the AGENT runs in, when that is not the app's directory.
207
+ *
208
+ * The rule and command files are read by the agent, not by the app, so a monorepo whose app is a
209
+ * directory down must still get its `/reticle` where the human's session actually stands. Absent
210
+ * (the single-package case) leaves every path project-relative exactly as before.
211
+ */
212
+ agentFileRoot?: string | undefined;
213
+ /**
214
+ * Content of the `.reticle.json` already sitting at that agent root, or null/undefined when there
215
+ * is none. Content rather than existence, for the reason `reticleConfigSource` is: a root config
216
+ * that disagrees with the app's is worse than no root config, and only reading it can tell.
217
+ */
218
+ agentRootConfigSource?: string | null | undefined;
178
219
  options: {
179
220
  port: number | undefined;
180
221
  mcp: boolean;