@reticlehq/server 2.3.0 → 2.5.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 (424) hide show
  1. package/SKILL.md +702 -0
  2. package/dist/bridge/auth-failure-reason.d.ts +19 -0
  3. package/dist/bridge/auth-failure-reason.js +29 -0
  4. package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
  5. package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
  6. package/dist/{bridge.d.ts → bridge/bridge.d.ts} +1 -1
  7. package/dist/{bridge.js → bridge/bridge.js} +105 -15
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -9
  10. package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
  11. package/dist/capsule/capsule-store.d.ts +8 -3
  12. package/dist/capsule/capsule-store.js +7 -2
  13. package/dist/capsule/capsule.js +3 -3
  14. package/dist/capsule/causal-summary.d.ts +8 -0
  15. package/dist/capsule/causal-summary.js +22 -12
  16. package/dist/capsule/divergence.d.ts +9 -4
  17. package/dist/capsule/divergence.js +8 -8
  18. package/dist/capsule/predicate-to-links.js +11 -8
  19. package/dist/{cli-doctor.js → cli/cli-doctor.js} +9 -2
  20. package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
  21. package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
  22. package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
  23. package/dist/cli/cli-launch.js +171 -0
  24. package/dist/cli/cli-parse.d.ts +143 -0
  25. package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
  26. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
  27. package/dist/{cli-port.js → cli/cli-port.js} +29 -8
  28. package/dist/cli/cli-update-commands.d.ts +4 -0
  29. package/dist/cli/cli-update-commands.js +93 -0
  30. package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
  31. package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
  32. package/dist/cli.d.ts +2 -2
  33. package/dist/cli.js +182 -93
  34. package/dist/cloud/cloud-config.d.ts +0 -1
  35. package/dist/cloud/cloud-config.js +9 -9
  36. package/dist/cloud/cloud-sync.d.ts +1 -7
  37. package/dist/cloud/cloud-sync.js +12 -12
  38. package/dist/crawl/crawl-empty.d.ts +16 -0
  39. package/dist/crawl/crawl-empty.js +24 -0
  40. package/dist/crawl/crawl-tools.js +4 -1
  41. package/dist/crawl/crawl.js +26 -7
  42. package/dist/daemon/daemon-resilience.d.ts +49 -0
  43. package/dist/daemon/daemon-resilience.js +191 -0
  44. package/dist/daemon/daemon-usefulness.d.ts +61 -0
  45. package/dist/daemon/daemon-usefulness.js +62 -0
  46. package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
  47. package/dist/{daemon.js → daemon/daemon.js} +80 -48
  48. package/dist/daemon/idle-grace.d.ts +32 -0
  49. package/dist/daemon/idle-grace.js +41 -0
  50. package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
  51. package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
  52. package/dist/domain/domain-model.js +2 -2
  53. package/dist/events/body-failures.js +8 -8
  54. package/dist/events/contradictions.d.ts +1 -1
  55. package/dist/events/contradictions.js +60 -10
  56. package/dist/events/echo-mismatch.js +10 -10
  57. package/dist/events/event-filters.js +6 -6
  58. package/dist/events/json-salvage.d.ts +2 -1
  59. package/dist/events/json-salvage.js +6 -6
  60. package/dist/events/observed-in-window.d.ts +12 -0
  61. package/dist/events/observed-in-window.js +21 -0
  62. package/dist/events/predicate-eval.d.ts +43 -20
  63. package/dist/events/predicate-eval.js +159 -55
  64. package/dist/events/predicate.d.ts +2 -2
  65. package/dist/events/predicate.js +112 -35
  66. package/dist/events/reconcile.js +5 -5
  67. package/dist/events/ring-buffer.js +1 -1
  68. package/dist/events/stale-response.js +6 -6
  69. package/dist/events/testid-near-miss.d.ts +22 -0
  70. package/dist/events/testid-near-miss.js +33 -0
  71. package/dist/events/unit-mismatch.js +8 -8
  72. package/dist/flows/affected-tools.js +19 -4
  73. package/dist/flows/affected.js +1 -1
  74. package/dist/flows/annotate-target.d.ts +1 -0
  75. package/dist/flows/annotate-target.js +20 -0
  76. package/dist/flows/annotate-tools.js +25 -3
  77. package/dist/flows/annotate.js +17 -4
  78. package/dist/flows/assertion-integrity.d.ts +2 -1
  79. package/dist/flows/assertion-tiers-store.d.ts +3 -66
  80. package/dist/flows/assertion-tiers-store.js +2 -2
  81. package/dist/flows/attributed-failure.d.ts +17 -0
  82. package/dist/flows/attributed-failure.js +20 -0
  83. package/dist/flows/buddy-status.d.ts +2 -1
  84. package/dist/flows/buddy-status.js +2 -2
  85. package/dist/flows/coverage.d.ts +3 -2
  86. package/dist/flows/coverage.js +2 -2
  87. package/dist/flows/decision.d.ts +0 -6
  88. package/dist/flows/decision.js +64 -8
  89. package/dist/flows/empty-flow.d.ts +6 -0
  90. package/dist/flows/empty-flow.js +24 -0
  91. package/dist/flows/flake-store.d.ts +0 -1
  92. package/dist/flows/flake-store.js +1 -1
  93. package/dist/flows/flake.d.ts +2 -1
  94. package/dist/flows/flake.js +2 -2
  95. package/dist/flows/flow-classify.js +12 -0
  96. package/dist/flows/flow-replay-run.js +4 -4
  97. package/dist/flows/flow-replay.d.ts +5 -7
  98. package/dist/flows/flow-replay.js +114 -47
  99. package/dist/flows/flow-report.js +1 -1
  100. package/dist/flows/flow-scope.d.ts +1 -6
  101. package/dist/flows/flow-step-runners.d.ts +26 -6
  102. package/dist/flows/flow-step-runners.js +157 -6
  103. package/dist/flows/flow-success.js +20 -15
  104. package/dist/flows/flow-tools.js +67 -13
  105. package/dist/flows/flows.js +15 -11
  106. package/dist/flows/gate.d.ts +4 -3
  107. package/dist/flows/gate.js +1 -1
  108. package/dist/flows/heal-run.d.ts +0 -8
  109. package/dist/flows/heal-run.js +5 -5
  110. package/dist/flows/heal.js +3 -3
  111. package/dist/flows/predicate-to-expect.d.ts +38 -0
  112. package/dist/flows/predicate-to-expect.js +95 -0
  113. package/dist/flows/replay.d.ts +16 -1
  114. package/dist/flows/replay.js +58 -22
  115. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  116. package/dist/flows/role-anchor-nearest.js +45 -0
  117. package/dist/flows/server-verify.d.ts +1 -1
  118. package/dist/flows/server-verify.js +5 -5
  119. package/dist/flows/verify-change-tools.js +32 -10
  120. package/dist/flows/verify-change-verdict.d.ts +15 -0
  121. package/dist/flows/verify-change-verdict.js +25 -0
  122. package/dist/flows/watch-batcher.d.ts +3 -2
  123. package/dist/honesty/already-true.d.ts +2 -0
  124. package/dist/honesty/already-true.js +31 -0
  125. package/dist/honesty/blind-spots.d.ts +16 -3
  126. package/dist/honesty/blind-spots.js +24 -12
  127. package/dist/honesty/honesty.d.ts +3 -2
  128. package/dist/honesty/honesty.js +4 -4
  129. package/dist/honesty/uncaptured-bodies.js +1 -1
  130. package/dist/honesty/unread-outcome.js +2 -2
  131. package/dist/honesty/verified.d.ts +22 -3
  132. package/dist/honesty/verified.js +48 -8
  133. package/dist/http-server.js +14 -7
  134. package/dist/hunt/hunt-report.d.ts +2 -1
  135. package/dist/hunt/hunt-report.js +2 -2
  136. package/dist/index.d.ts +8 -6
  137. package/dist/index.js +32 -25
  138. package/dist/init/agent-rules.d.ts +2 -1
  139. package/dist/init/agent-rules.js +45 -7
  140. package/dist/init/app-choice.d.ts +20 -0
  141. package/dist/init/app-choice.js +25 -0
  142. package/dist/init/astro-host.d.ts +21 -0
  143. package/dist/init/astro-host.js +27 -0
  144. package/dist/init/astro-patch.d.ts +16 -0
  145. package/dist/init/astro-patch.js +240 -0
  146. package/dist/init/capabilities.d.ts +17 -0
  147. package/dist/init/capabilities.js +54 -0
  148. package/dist/init/cra.d.ts +37 -0
  149. package/dist/init/cra.js +90 -0
  150. package/dist/init/cursor.js +39 -4
  151. package/dist/init/desktop-doctor.d.ts +3 -2
  152. package/dist/init/desktop-doctor.js +4 -4
  153. package/dist/init/detect.d.ts +26 -0
  154. package/dist/init/detect.js +78 -5
  155. package/dist/init/mcp-registered.d.ts +12 -0
  156. package/dist/init/mcp-registered.js +14 -0
  157. package/dist/init/mcp.d.ts +27 -2
  158. package/dist/init/mcp.js +40 -4
  159. package/dist/init/next-patch.d.ts +39 -0
  160. package/dist/init/next-patch.js +196 -0
  161. package/dist/init/node-io.js +48 -6
  162. package/dist/init/patch-kind.d.ts +20 -0
  163. package/dist/init/patch-kind.js +10 -0
  164. package/dist/init/plan-framework.d.ts +50 -0
  165. package/dist/init/plan-framework.js +341 -0
  166. package/dist/init/plan.d.ts +119 -6
  167. package/dist/init/plan.js +230 -131
  168. package/dist/init/project-id.d.ts +5 -9
  169. package/dist/init/project-id.js +10 -22
  170. package/dist/init/run.d.ts +22 -0
  171. package/dist/init/run.js +393 -28
  172. package/dist/init/slash-command.d.ts +27 -0
  173. package/dist/init/slash-command.js +61 -0
  174. package/dist/init/snippets.d.ts +41 -3
  175. package/dist/init/snippets.js +185 -10
  176. package/dist/init/vite-config.d.ts +4 -10
  177. package/dist/init/vite-config.js +15 -7
  178. package/dist/init/workspace-apps.d.ts +23 -0
  179. package/dist/init/workspace-apps.js +68 -0
  180. package/dist/input/driven-redaction.d.ts +15 -0
  181. package/dist/input/driven-redaction.js +76 -0
  182. package/dist/input/network-detail.d.ts +9 -3
  183. package/dist/input/network-detail.js +43 -23
  184. package/dist/input/network-mock-tools.js +2 -2
  185. package/dist/input/network-mock.js +4 -4
  186. package/dist/input/real-input.js +8 -3
  187. package/dist/input/scroll-find.js +2 -2
  188. package/dist/input/scroll-tools.d.ts +0 -5
  189. package/dist/input/scroll-tools.js +11 -4
  190. package/dist/input/viewport-tools.js +2 -2
  191. package/dist/journal/ambient-store.d.ts +0 -2
  192. package/dist/journal/ambient-store.js +1 -1
  193. package/dist/journal/ambient.js +1 -1
  194. package/dist/journal/attach-journal.d.ts +2 -1
  195. package/dist/journal/deviation-report.js +6 -6
  196. package/dist/journal/deviation-service.js +1 -1
  197. package/dist/journal/envelope-store.d.ts +0 -2
  198. package/dist/journal/envelope-store.js +1 -1
  199. package/dist/journal/envelope.d.ts +2 -3
  200. package/dist/journal/envelope.js +3 -3
  201. package/dist/journal/journal-query.js +1 -1
  202. package/dist/journal/journal-recorder.d.ts +2 -1
  203. package/dist/journal/journal-recorder.js +2 -2
  204. package/dist/journal/rollups.js +9 -9
  205. package/dist/journal/session-end.d.ts +2 -1
  206. package/dist/journal/session-journal.js +4 -4
  207. package/dist/license/license.d.ts +0 -14
  208. package/dist/license/license.js +8 -8
  209. package/dist/log.d.ts +10 -0
  210. package/dist/log.js +11 -1
  211. package/dist/mcp/mcp-is-error.d.ts +13 -0
  212. package/dist/mcp/mcp-is-error.js +18 -0
  213. package/dist/mcp/mcp-outage.d.ts +31 -0
  214. package/dist/mcp/mcp-outage.js +48 -0
  215. package/dist/mcp/mcp-proxy.d.ts +124 -0
  216. package/dist/mcp/mcp-proxy.js +697 -0
  217. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  218. package/dist/{mcp.js → mcp/mcp.js} +110 -35
  219. package/dist/mcp/proxy-handshake.d.ts +3 -0
  220. package/dist/mcp/proxy-handshake.js +54 -0
  221. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  222. package/dist/mcp/proxy-lifecycle.js +70 -0
  223. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  224. package/dist/mcp/tool-catalog-cache.js +55 -0
  225. package/dist/oracles/propose-consequences.d.ts +2 -1
  226. package/dist/oracles/propose-consequences.js +16 -11
  227. package/dist/oracles/self-instrument.d.ts +2 -1
  228. package/dist/oracles/self-instrument.js +1 -1
  229. package/dist/phenomena/phenomena.js +3 -3
  230. package/dist/platform.d.ts +16 -0
  231. package/dist/platform.js +16 -0
  232. package/dist/pool/playwright-launcher.d.ts +15 -2
  233. package/dist/pool/playwright-launcher.js +21 -2
  234. package/dist/project/fs-port.js +1 -1
  235. package/dist/project/project-tools.js +2 -2
  236. package/dist/runs/build-verification-run.js +1 -1
  237. package/dist/runs/repair-prompt.d.ts +0 -6
  238. package/dist/runs/repair-prompt.js +3 -3
  239. package/dist/runs/risk-classify.js +1 -1
  240. package/dist/runs/run-diff.d.ts +0 -2
  241. package/dist/runs/run-diff.js +3 -3
  242. package/dist/runs/run-tools.js +2 -2
  243. package/dist/runs/verification-sync.js +2 -2
  244. package/dist/runs/verify-http.js +1 -1
  245. package/dist/runs/verify-server.js +1 -1
  246. package/dist/session/command-timeout.d.ts +11 -3
  247. package/dist/session/command-timeout.js +2 -2
  248. package/dist/session/control-envelope.d.ts +6 -0
  249. package/dist/session/control-envelope.js +7 -1
  250. package/dist/session/dev-server-probe.d.ts +13 -0
  251. package/dist/session/dev-server-probe.js +52 -0
  252. package/dist/session/last-act.d.ts +17 -3
  253. package/dist/session/last-act.js +16 -4
  254. package/dist/session/live-control-tools.js +7 -2
  255. package/dist/session/live-control.js +1 -1
  256. package/dist/session/looks-like-dev-server.d.ts +14 -0
  257. package/dist/session/looks-like-dev-server.js +25 -0
  258. package/dist/session/no-session-diagnosis.d.ts +38 -0
  259. package/dist/session/no-session-diagnosis.js +70 -0
  260. package/dist/session/no-session-watch.d.ts +19 -0
  261. package/dist/session/no-session-watch.js +61 -0
  262. package/dist/session/observed-state.d.ts +4 -0
  263. package/dist/session/observed-state.js +19 -1
  264. package/dist/session/output-budget.js +1 -1
  265. package/dist/session/session-health.d.ts +8 -1
  266. package/dist/session/session-health.js +8 -7
  267. package/dist/session/session-info.d.ts +26 -7
  268. package/dist/session/session-info.js +42 -1
  269. package/dist/session/session-lease.d.ts +0 -11
  270. package/dist/session/session-lease.js +1 -1
  271. package/dist/session/session-manager.d.ts +3 -0
  272. package/dist/session/session-manager.js +58 -9
  273. package/dist/session/session-readiness.d.ts +1 -1
  274. package/dist/session/session-readiness.js +6 -1
  275. package/dist/session/session-reaper.js +1 -1
  276. package/dist/session/session-reconnect.d.ts +32 -0
  277. package/dist/session/session-reconnect.js +42 -0
  278. package/dist/session/session.d.ts +20 -2
  279. package/dist/session/session.js +76 -26
  280. package/dist/session/state-select.d.ts +1 -1
  281. package/dist/session/state-select.js +1 -1
  282. package/dist/status-payload.d.ts +19 -0
  283. package/dist/status-payload.js +11 -0
  284. package/dist/telemetry/argument-shape.js +10 -1
  285. package/dist/telemetry/browser-mode.d.ts +27 -0
  286. package/dist/telemetry/browser-mode.js +33 -0
  287. package/dist/telemetry/bug-found.d.ts +17 -21
  288. package/dist/telemetry/bug-found.js +120 -8
  289. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  290. package/dist/telemetry/cli-telemetry.js +27 -4
  291. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  292. package/dist/telemetry/daemon-telemetry.js +12 -2
  293. package/dist/telemetry/dev-repo.js +4 -4
  294. package/dist/telemetry/error-fingerprint.js +21 -2
  295. package/dist/telemetry/feedback-cli.d.ts +1 -1
  296. package/dist/telemetry/feedback-cli.js +4 -4
  297. package/dist/telemetry/feedback-context.d.ts +22 -0
  298. package/dist/telemetry/feedback-context.js +41 -1
  299. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  300. package/dist/telemetry/feedback-delivery.js +30 -0
  301. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  302. package/dist/telemetry/feedback-outbox.js +87 -0
  303. package/dist/telemetry/feedback.d.ts +22 -1
  304. package/dist/telemetry/feedback.js +67 -8
  305. package/dist/telemetry/git-facts.js +1 -1
  306. package/dist/telemetry/session-metrics.d.ts +2 -0
  307. package/dist/telemetry/session-metrics.js +68 -6
  308. package/dist/telemetry/telemetry.d.ts +27 -2
  309. package/dist/telemetry/telemetry.js +119 -29
  310. package/dist/telemetry/verification-of.d.ts +22 -0
  311. package/dist/telemetry/verification-of.js +84 -0
  312. package/dist/tools/act-capsule.js +2 -2
  313. package/dist/tools/act-danger.d.ts +12 -0
  314. package/dist/tools/act-danger.js +20 -3
  315. package/dist/tools/act-helpers.js +4 -4
  316. package/dist/tools/act-tools.d.ts +0 -8
  317. package/dist/tools/act-tools.js +84 -115
  318. package/dist/tools/act-view.js +7 -7
  319. package/dist/tools/alias-args.d.ts +17 -0
  320. package/dist/tools/alias-args.js +25 -0
  321. package/dist/tools/assert-grade.js +9 -9
  322. package/dist/tools/assert-verdict.d.ts +3 -1
  323. package/dist/tools/assert-verdict.js +8 -5
  324. package/dist/tools/browser-tools.js +30 -11
  325. package/dist/tools/contract-tools.js +1 -1
  326. package/dist/tools/coverage-identity.d.ts +34 -0
  327. package/dist/tools/coverage-identity.js +46 -0
  328. package/dist/tools/coverage-tools.js +10 -14
  329. package/dist/tools/dynamic-tools.d.ts +2 -1
  330. package/dist/tools/dynamic-tools.js +90 -18
  331. package/dist/tools/error-recovery.d.ts +20 -2
  332. package/dist/tools/error-recovery.js +179 -4
  333. package/dist/tools/feedback-tools.d.ts +12 -1
  334. package/dist/tools/feedback-tools.js +28 -5
  335. package/dist/tools/invoke-tool.d.ts +0 -6
  336. package/dist/tools/invoke-tool.js +57 -32
  337. package/dist/tools/lease-hint.d.ts +17 -0
  338. package/dist/tools/lease-hint.js +24 -0
  339. package/dist/tools/lease-tools.js +6 -5
  340. package/dist/tools/merge-tools.d.ts +10 -1
  341. package/dist/tools/merge-tools.js +9 -3
  342. package/dist/tools/merged-name-redirect.d.ts +13 -0
  343. package/dist/tools/merged-name-redirect.js +55 -0
  344. package/dist/tools/navigate-result.d.ts +17 -0
  345. package/dist/tools/navigate-result.js +31 -0
  346. package/dist/tools/observe-tools.js +54 -20
  347. package/dist/tools/observed-nothing.d.ts +25 -0
  348. package/dist/tools/observed-nothing.js +33 -0
  349. package/dist/tools/query-paginate.js +2 -2
  350. package/dist/tools/query-shape.d.ts +18 -0
  351. package/dist/tools/query-shape.js +39 -0
  352. package/dist/tools/read-tools.js +85 -20
  353. package/dist/tools/real-input-attempt.d.ts +28 -0
  354. package/dist/tools/real-input-attempt.js +88 -0
  355. package/dist/tools/reconcile-tools.js +7 -7
  356. package/dist/tools/reload-result.d.ts +14 -0
  357. package/dist/tools/reload-result.js +29 -0
  358. package/dist/tools/snapshot-delta.d.ts +4 -5
  359. package/dist/tools/snapshot-delta.js +0 -0
  360. package/dist/tools/tool-kit.d.ts +8 -0
  361. package/dist/tools/tool-surface.d.ts +83 -0
  362. package/dist/tools/tool-surface.js +204 -0
  363. package/dist/tools/tools-helpers.js +6 -6
  364. package/dist/tools/tools.d.ts +15 -0
  365. package/dist/tools/tools.js +53 -17
  366. package/dist/tools/unadvertised-help.d.ts +5 -0
  367. package/dist/tools/unadvertised-help.js +39 -0
  368. package/dist/trace.d.ts +69 -0
  369. package/dist/trace.js +150 -0
  370. package/dist/update/nudge-credit.d.ts +4 -0
  371. package/dist/update/nudge-credit.js +53 -0
  372. package/dist/update/sdk-sync.d.ts +21 -0
  373. package/dist/update/sdk-sync.js +42 -0
  374. package/dist/update/update-checker.js +3 -3
  375. package/dist/update/update-nudge.d.ts +63 -6
  376. package/dist/update/update-nudge.js +128 -15
  377. package/dist/update/updater.d.ts +1 -9
  378. package/dist/update/updater.js +13 -8
  379. package/dist/version/peer-announce.d.ts +4 -0
  380. package/dist/version/peer-announce.js +30 -0
  381. package/dist/{server-version.js → version/server-version.js} +5 -1
  382. package/dist/version/version-nudge.d.ts +28 -0
  383. package/dist/version/version-nudge.js +40 -0
  384. package/dist/version/version-skew.d.ts +66 -0
  385. package/dist/version/version-skew.js +71 -0
  386. package/dist/visual/visual-diff.js +2 -2
  387. package/dist/visual/visual-tools.js +4 -4
  388. package/docs/agent-cheatsheet.md +85 -0
  389. package/docs/architecture.md +113 -0
  390. package/docs/benchmarks.md +255 -0
  391. package/docs/debugging.md +102 -0
  392. package/docs/deploy-checks.md +69 -0
  393. package/docs/desktop-apps.md +256 -0
  394. package/docs/enterprise.md +62 -0
  395. package/docs/fixtures.md +28 -0
  396. package/docs/flows.md +166 -0
  397. package/docs/getting-started.md +469 -0
  398. package/docs/human-control.md +63 -0
  399. package/docs/integration-patterns.md +171 -0
  400. package/docs/local-registry.md +126 -0
  401. package/docs/mint.json +61 -0
  402. package/docs/multi-agent-testing.md +55 -0
  403. package/docs/platform-integration.md +122 -0
  404. package/docs/telemetry-contract.md +214 -0
  405. package/docs/telemetry.md +184 -0
  406. package/docs/testing.md +82 -0
  407. package/docs/token-efficiency.md +80 -0
  408. package/docs/usage.md +1046 -0
  409. package/package.json +8 -5
  410. package/dist/cli-launch.js +0 -112
  411. package/dist/cli-parse.d.ts +0 -140
  412. package/dist/daemon-resilience.d.ts +0 -22
  413. package/dist/daemon-resilience.js +0 -85
  414. package/dist/mcp-proxy.d.ts +0 -35
  415. package/dist/mcp-proxy.js +0 -190
  416. package/dist/tools/profiles.d.ts +0 -37
  417. package/dist/tools/profiles.js +0 -139
  418. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  419. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  420. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  421. /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
  422. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  423. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  424. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
package/dist/init/plan.js CHANGED
@@ -3,12 +3,13 @@
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, installCommand, installCommandParts } from './detect.js';
6
+ import { Framework, PackageManager, UiLibrary, installCommand, installCommandParts, } from './detect.js';
7
7
  import { claudeAddCommand, mcpManual } from './mcp.js';
8
8
  import { mergeCursorConfig, CursorMergeStatus, cursorServerEntry } from './cursor.js';
9
+ import { CLAUDE_COMMAND_PATH, CURSOR_COMMAND_PATH, SLASH_COMMAND_BODY, SLASH_COMMAND_SIGNATURE, } from './slash-command.js';
9
10
  import { mergeMarkedInstruction, cursorRuleFile, AgentRuleStatus, CLAUDE_MD_PATH, AGENTS_MD_PATH, CURSOR_RULE_PATH, } from './agent-rules.js';
10
- import { patchViteConfig, VitePatchKind } from './vite-config.js';
11
- import { viteManual, htmlManual, NEXT_LAYOUT_MANUAL, nextReticleDevFile, NEXT_RETICLE_DEV_PATH, nextConfigManual, reticleConfigContent, svelteKitHooksFile, SVELTEKIT_HOOKS_PATH, UNVERIFIED_FRAMEWORK_NOTE, } from './snippets.js';
11
+ import { viteSteps, nextSteps, craSteps, svelteKitSteps, astroSteps, VITE_PLUGIN_DETAIL, } from './plan-framework.js';
12
+ import { htmlManual, reticleConfigContent, unverifiedUiLibraryNote } from './snippets.js';
12
13
  // An app dev installs exactly the audience-scoped browser-side dependencies — never the retired
13
14
  // `@reticlehq/core` umbrella (which dragged the Node MCP server + ws into every app). The kit is the
14
15
  // framework adapter (it re-exports the browser sensor), paired with that framework's dev-only build
@@ -16,8 +17,22 @@ import { viteManual, htmlManual, NEXT_LAYOUT_MANUAL, nextReticleDevFile, NEXT_RE
16
17
  const RETICLE_REACT_KIT = '@reticlehq/react';
17
18
  const RETICLE_VITE_PLUGIN = '@reticlehq/vite-plugin';
18
19
  const RETICLE_NEXT_PLUGIN = '@reticlehq/next';
20
+ /**
21
+ * Pin the SDK to the CLI's own version.
22
+ *
23
+ * `pnpm add -D @reticlehq/react` installed **2.2.1** in one project while npm and yarn took 2.3.0 in
24
+ * the next — a stale registry metadata cache, invisible to the user and to us. A version-skewed SDK
25
+ * talking to a newer daemon is the `-32000` failure path: the app connects, the protocol disagrees,
26
+ * and nothing on either side names a version. Asking for the CLI's exact version makes the cache
27
+ * irrelevant, and a skewed pair impossible to install by accident.
28
+ */
29
+ export function pinnedPackages(packages, version) {
30
+ if (version === undefined || 0 === version.length)
31
+ return packages;
32
+ return packages.map((p) => `${p}@${version}`);
33
+ }
19
34
  /** The dev-dependencies `reticle init` installs for a given framework — kit first, build plugin next. */
20
- export function frameworkPackages(framework) {
35
+ function frameworkPackages(framework) {
21
36
  switch (framework) {
22
37
  case Framework.NEXT:
23
38
  return [RETICLE_REACT_KIT, RETICLE_NEXT_PLUGIN];
@@ -25,6 +40,14 @@ export function frameworkPackages(framework) {
25
40
  case Framework.SVELTEKIT:
26
41
  // SvelteKit builds on Vite; until a dedicated Svelte kit exists it uses the Vite build plugin.
27
42
  return [RETICLE_REACT_KIT, RETICLE_VITE_PLUGIN];
43
+ case Framework.ASTRO:
44
+ // Astro owns its own Vite instance and renders its own HTML, so there is no config for the
45
+ // plugin to attach to — the kit alone, connected from a page <script> (see astroManual).
46
+ return [RETICLE_REACT_KIT];
47
+ case Framework.CRA:
48
+ // react-scripts owns its webpack config and cannot be extended without ejecting, so there is
49
+ // no build plugin — the kit alone, imported from src/index.tsx (see cra.ts).
50
+ return [RETICLE_REACT_KIT];
28
51
  case Framework.HTML:
29
52
  // No bundler plugin to install — just the kit; connect is wired by hand (see htmlManual).
30
53
  return [RETICLE_REACT_KIT];
@@ -32,6 +55,27 @@ export function frameworkPackages(framework) {
32
55
  }
33
56
  /** Exported so the init telemetry can tell an MCP-registration failure from a dependency install. */
34
57
  export const MCP_TARGET = 'global (claude user scope)';
58
+ /**
59
+ * Titles of the steps WITHOUT which no session ever appears.
60
+ *
61
+ * A ⚠ on one of these is not a warning, it is a guaranteed failure: nothing performs the manual step,
62
+ * so the app will not connect and every Reticle tool will answer "no browser session connected".
63
+ * Reported from a field sweep, where the ⚠ count and "did it connect" were treated as independent
64
+ * signals and are not.
65
+ */
66
+ const CONNECT_STEP_TITLES = new Set([
67
+ 'Connect snippet',
68
+ 'Connect snippet (CRA)',
69
+ 'Connect snippet (Astro)',
70
+ 'Reticle client hook',
71
+ 'Reticle connect module',
72
+ 'ReticleDev component',
73
+ 'Vite plugin',
74
+ ]);
75
+ /** True when this step is what makes the app dial the daemon. */
76
+ export function isConnectStep(title) {
77
+ return CONNECT_STEP_TITLES.has(title);
78
+ }
35
79
  /** The step that runs the package manager — the other thing that commonly fails on a user's machine. */
36
80
  export const DEPS_TARGET = 'package.json';
37
81
  const RETICLE_CONFIG_FILE = '.reticle.json';
@@ -40,6 +84,13 @@ export const StepStatus = {
40
84
  MANUAL: 'manual',
41
85
  ALREADY: 'already',
42
86
  SKIP: 'skip',
87
+ /**
88
+ * Something the user should KNOW, not something they must DO. The UNVERIFIED lines are the case:
89
+ * a Preact or SvelteKit app is wired and working, it just isn't covered by a gate. Reporting those
90
+ * as `manual` made "steps left to do" a number that could never reach zero, and made a release gate
91
+ * read two regressions that were not regressions.
92
+ */
93
+ NOTICE: 'notice',
43
94
  };
44
95
  const CLAUDE_MCP_TITLE = 'MCP server (Claude, global)';
45
96
  const CURSOR_MCP_TITLE = 'MCP server (Cursor, global)';
@@ -99,14 +150,19 @@ function mcpSteps(input) {
99
150
  title: 'MCP server (global)',
100
151
  target: MCP_TARGET,
101
152
  status: StepStatus.SKIP,
102
- detail: '--no-mcp',
153
+ // Names everything it turns off. `--no-mcp` reads like "skip one step" and skips three: the
154
+ // registration, the agent rule files, and the /reticle command. A gate running with this flag
155
+ // therefore covers far less than its name suggests, which is worth saying out loud.
156
+ detail: '--no-mcp — also skips the agent rule files (CLAUDE.md / AGENTS.md / .cursor) and the /reticle command',
103
157
  },
104
158
  ];
105
159
  }
106
- const steps = [claudeMcpStep(input), cursorMcpStep(input)].filter((s) => s !== null);
160
+ const steps = stepsForAgents(input, (a) => a.mcpStep);
107
161
  if (steps.length > 0)
108
162
  return steps;
109
- // No supported agent detected — print the one-time global instructions.
163
+ // No supported agent detected — print the one-time global instructions. Reached when the `claude`
164
+ // CLI is absent AND ~/.cursor does not exist, which includes Cursor installed with a fresh profile
165
+ // that has not written its config directory yet, so the manual text covers both agents.
110
166
  return [
111
167
  {
112
168
  title: 'MCP server (global)',
@@ -116,6 +172,52 @@ function mcpSteps(input) {
116
172
  },
117
173
  ];
118
174
  }
175
+ const SLASH_COMMAND_TITLE = 'The /reticle command';
176
+ /**
177
+ * Nothing to do for this command file: it already holds the CURRENT body, or it is not ours at all.
178
+ *
179
+ * Gating on mere existence froze the command at whatever release wrote it. Rewriting anything found
180
+ * there would be worse — a human may have claimed `/reticle` for their own prompt — so a file without
181
+ * our signature is left exactly as it is.
182
+ */
183
+ function commandIsSettled(content) {
184
+ if (null === content || content === undefined)
185
+ return false;
186
+ return content === SLASH_COMMAND_BODY || !content.includes(SLASH_COMMAND_SIGNATURE);
187
+ }
188
+ /**
189
+ * `/reticle` — the entry point SKILL.md promises in three places and nothing ever created, so it
190
+ * silently did nothing in every tool.
191
+ *
192
+ * CURRENT, not merely present — same reason as the Cursor rule: a command file frozen at whatever
193
+ * release created it is a command that can never be improved for anyone who already ran init. The
194
+ * whole file is Reticle's, so a stale one is rewritten.
195
+ */
196
+ function commandStepFor(path, present, content) {
197
+ if (!present)
198
+ return null;
199
+ return commandIsSettled(content)
200
+ ? {
201
+ title: SLASH_COMMAND_TITLE,
202
+ target: path,
203
+ status: StepStatus.ALREADY,
204
+ detail: 'command already exists',
205
+ }
206
+ : {
207
+ title: SLASH_COMMAND_TITLE,
208
+ target: path,
209
+ status: StepStatus.APPLY,
210
+ detail: 'type /reticle to verify one flow in the browser',
211
+ write: { path, content: SLASH_COMMAND_BODY },
212
+ };
213
+ }
214
+ function claudeCommandStep(input) {
215
+ return commandStepFor(CLAUDE_COMMAND_PATH, input.claudeCli, input.claudeCommandContent);
216
+ }
217
+ function cursorCommandStep(input) {
218
+ const present = true === input.cursorProjectPresent || (input.cursorPresent && !input.claudeCli);
219
+ return commandStepFor(CURSOR_COMMAND_PATH, present, input.cursorCommandContent);
220
+ }
119
221
  const AGENT_RULE_TITLE = 'Agent verification rule';
120
222
  const AGENT_RULE_DETAIL = 'teach the agent to verify features with Reticle after building them';
121
223
  function claudeRuleStep(input) {
@@ -138,10 +240,20 @@ function claudeRuleStep(input) {
138
240
  write: { path: CLAUDE_MD_PATH, content: r.content },
139
241
  };
140
242
  }
243
+ /**
244
+ * The Cursor rule is a PROJECT file, so it is written only when Cursor plausibly works on THIS
245
+ * project — the repo has a `.cursor/` dir, or Cursor is the only agent found. `~/.cursor` merely
246
+ * existing on the machine meant every Claude Code user got an unexplained `.cursor/rules/reticle.mdc`
247
+ * committed into their repo. (Global MCP registration is different: it is global, and stays.)
248
+ */
141
249
  function cursorRuleStep(input) {
142
250
  if (!input.cursorPresent)
143
251
  return null;
144
- if (input.cursorRuleExists === true) {
252
+ if (input.cursorProjectPresent !== true && input.claudeCli)
253
+ return null;
254
+ // The whole file is Reticle's — init created it — so a stale one is REWRITTEN rather than merged.
255
+ // Comparing content is what makes the rule updatable; comparing existence made it permanent.
256
+ if (input.cursorRuleContent === cursorRuleFile()) {
145
257
  return {
146
258
  title: AGENT_RULE_TITLE,
147
259
  target: CURSOR_RULE_PATH,
@@ -157,6 +269,46 @@ function cursorRuleStep(input) {
157
269
  write: { path: CURSOR_RULE_PATH, content: cursorRuleFile() },
158
270
  };
159
271
  }
272
+ /**
273
+ * Every coding agent `reticle init` knows how to wire itself into, and the three surfaces it wires:
274
+ * the global MCP registration, the project rule file that makes the agent USE Reticle, and the
275
+ * `/reticle` command.
276
+ *
277
+ * One list, because those three surfaces used to enumerate Claude and Cursor separately in three
278
+ * places — so supporting a fourth agent meant finding all three and getting each right. Adding one
279
+ * is now an entry here plus its builders; each builder answers null when that agent is not present
280
+ * for this user or this project, which is also how "no agent detected" falls through to the
281
+ * cross-agent AGENTS.md.
282
+ *
283
+ * Deliberately functions rather than data: registering with Claude runs its CLI while Cursor merges
284
+ * a JSON file, and pretending those are the same shape would cost more than it saves.
285
+ */
286
+ const AgentId = {
287
+ CLAUDE: 'claude',
288
+ CURSOR: 'cursor',
289
+ };
290
+ const AGENT_INTEGRATIONS = [
291
+ {
292
+ id: AgentId.CLAUDE,
293
+ mcpStep: claudeMcpStep,
294
+ ruleStep: claudeRuleStep,
295
+ commandStep: claudeCommandStep,
296
+ },
297
+ {
298
+ id: AgentId.CURSOR,
299
+ mcpStep: cursorMcpStep,
300
+ ruleStep: cursorRuleStep,
301
+ commandStep: cursorCommandStep,
302
+ },
303
+ ];
304
+ /** The steps one surface contributes across every known agent, in registry order. */
305
+ function stepsForAgents(input, surface) {
306
+ return AGENT_INTEGRATIONS.map((a) => surface(a)(input)).filter((s) => s !== null);
307
+ }
308
+ /** The `/reticle` command file for every agent that has a command surface and is present here. */
309
+ function slashCommandSteps(input) {
310
+ return stepsForAgents(input, (a) => a.commandStep);
311
+ }
160
312
  /**
161
313
  * The behavioral rule that makes the agent actually USE Reticle. Written into the detected agent's
162
314
  * instruction file (Claude / Cursor, or both), falling back to the cross-agent AGENTS.md when neither
@@ -165,7 +317,7 @@ function cursorRuleStep(input) {
165
317
  function agentRuleSteps(input) {
166
318
  if (!input.options.mcp)
167
319
  return [];
168
- const detected = [claudeRuleStep(input), cursorRuleStep(input)].filter((s) => s !== null);
320
+ const detected = stepsForAgents(input, (a) => a.ruleStep);
169
321
  if (detected.length > 0)
170
322
  return detected;
171
323
  const r = mergeMarkedInstruction(input.agentsMdContent);
@@ -186,9 +338,36 @@ function agentRuleSteps(input) {
186
338
  },
187
339
  ];
188
340
  }
341
+ /**
342
+ * What to say when the install command fails.
343
+ *
344
+ * pnpm's `minimumReleaseAge` refuses any release younger than the configured window — a deliberate
345
+ * supply-chain policy, not a bug — with `ERR_PNPM_NO_MATURE_MATCHING_VERSION`. Unpinned it silently
346
+ * resolves to an OLDER version instead, which is how an app ends up running a 2.2.1 SDK against a
347
+ * 2.3.0 daemon: the connection succeeds, the protocol disagrees, and the failure surfaces as -32000
348
+ * with nothing naming a version. Pinning turns that into this loud failure, which is the better
349
+ * trade — but only if the message says what to do about it.
350
+ */
351
+ /** Said out loud when the exact-version install was refused and the unpinned one worked. */
352
+ function unpinnedRetryNote(version) {
353
+ const wanted = version === undefined ? 'the exact version' : version;
354
+ return (`the registry refused ${wanted} (pnpm's minimumReleaseAge holds new releases back), so the ` +
355
+ `newest ACCEPTED version was installed instead. That may not match the daemon — if the agent ` +
356
+ `reports protocol errors, check \`versionSkew\` in reticle_sessions, then either wait out the ` +
357
+ `window or allow these packages: pnpm config set minimumReleaseAgeExclude "@reticlehq/*"`);
358
+ }
359
+ function installFailureHint(pm) {
360
+ if (pm !== PackageManager.PNPM)
361
+ return 'If the version was refused, install the SDK yourself.';
362
+ return ('If pnpm reported ERR_PNPM_NO_MATURE_MATCHING_VERSION, its minimumReleaseAge setting is holding ' +
363
+ 'this release back. Either wait out the window, or allow these packages explicitly:\n' +
364
+ ' pnpm config set minimumReleaseAgeExclude "@reticlehq/*"\n' +
365
+ 'Do NOT drop the version pin — unpinned, pnpm installs an older SDK against a newer daemon, and ' +
366
+ 'that mismatch surfaces as a -32000 with nothing naming a version.');
367
+ }
189
368
  function installStep(input) {
190
369
  const pm = input.detection.packageManager;
191
- const packages = frameworkPackages(input.detection.framework);
370
+ const packages = pinnedPackages(frameworkPackages(input.detection.framework), input.options.sdkVersion);
192
371
  const command = installCommand(pm, packages);
193
372
  if (!input.options.install) {
194
373
  return {
@@ -204,132 +383,21 @@ function installStep(input) {
204
383
  target: 'package.json',
205
384
  status: StepStatus.APPLY,
206
385
  detail: command,
207
- exec: { command: parts.command, args: parts.args, fallback: command },
208
- };
209
- }
210
- function viteSteps(input) {
211
- const cfg = input.viteConfig;
212
- const port = input.options.port;
213
- if (cfg === null) {
214
- return [
215
- {
216
- title: 'Vite plugin',
217
- target: 'vite.config',
218
- status: StepStatus.MANUAL,
219
- detail: viteManual(port),
220
- },
221
- ];
222
- }
223
- const patch = patchViteConfig(cfg.source, port);
224
- if (patch.kind === VitePatchKind.ALREADY) {
225
- return [
226
- {
227
- title: 'Vite plugin',
228
- target: cfg.path,
229
- status: StepStatus.ALREADY,
230
- detail: 'reticle() already in plugins',
231
- },
232
- ];
233
- }
234
- if (patch.kind === VitePatchKind.MANUAL) {
235
- return [
236
- {
237
- title: 'Vite plugin',
238
- target: cfg.path,
239
- status: StepStatus.MANUAL,
240
- detail: `${patch.reason}\n\n${viteManual(port)}`,
241
- },
242
- ];
243
- }
244
- return [
245
- {
246
- title: 'Vite plugin',
247
- target: cfg.path,
248
- status: StepStatus.APPLY,
249
- detail: 'add reticle() to plugins (also injects connect())',
250
- write: { path: cfg.path, content: patch.code },
386
+ exec: {
387
+ command: parts.command,
388
+ args: parts.args,
389
+ fallback: `${command}\n\n${installFailureHint(pm)}`,
251
390
  },
252
- ];
253
- }
254
- function nextSteps(input) {
255
- const configFile = input.nextConfigFile ?? 'next.config.mjs';
256
- const devFile = input.nextReticleDevExists
257
- ? {
258
- title: 'ReticleDev component',
259
- target: NEXT_RETICLE_DEV_PATH,
260
- status: StepStatus.ALREADY,
261
- detail: 'file exists',
262
- }
263
- : {
264
- title: 'ReticleDev component',
265
- target: NEXT_RETICLE_DEV_PATH,
266
- status: StepStatus.APPLY,
267
- detail: 'create dev-only connect component',
268
- write: {
269
- path: NEXT_RETICLE_DEV_PATH,
270
- content: nextReticleDevFile(input.options.port, input.options.projectId),
271
- },
272
- };
273
- return [
274
- devFile,
275
- {
276
- title: 'Next config (withReticle)',
277
- target: configFile,
278
- status: StepStatus.MANUAL,
279
- detail: nextConfigManual(configFile),
391
+ // Unpinned. pnpm resolves the newest MATURE version there, which is how a project with a
392
+ // release-age hold gets a working install instead of no install.
393
+ retry: {
394
+ ...installCommandParts(pm, frameworkPackages(input.detection.framework)),
395
+ note: unpinnedRetryNote(input.options.sdkVersion),
280
396
  },
281
- {
282
- title: 'Mount ReticleDev',
283
- target: 'app/layout.tsx',
284
- status: StepStatus.MANUAL,
285
- detail: NEXT_LAYOUT_MANUAL,
286
- },
287
- ];
288
- }
289
- /**
290
- * SvelteKit is WIRED but not SUPPORTED, and the plan says so out loud.
291
- *
292
- * There is no SvelteKit app in `apps/` and no CI gate for one, so nothing proves this hook still
293
- * registers a session — every other framework init offers (React, Next, Remix, Astro) has both. The
294
- * wiring is real and may well work; what is missing is anything that would tell us when it stops.
295
- * Silently emitting it reads as a support claim, which is the thing this project exists to not do.
296
- */
297
- function svelteKitSteps(input) {
298
- const unverified = {
299
- title: 'SvelteKit is UNVERIFIED',
300
- target: SVELTEKIT_HOOKS_PATH,
301
- status: StepStatus.MANUAL,
302
- detail: UNVERIFIED_FRAMEWORK_NOTE,
303
397
  };
304
- // SvelteKit can't use the Vite-plugin injection (it renders via app.html) — wire a client hook
305
- // that SvelteKit runs on startup, which is the path that can register a session at all.
306
- if (input.svelteKitHooksExists === true) {
307
- return [
308
- unverified,
309
- {
310
- title: 'Reticle client hook',
311
- target: SVELTEKIT_HOOKS_PATH,
312
- status: StepStatus.ALREADY,
313
- detail: 'file exists',
314
- },
315
- ];
316
- }
317
- return [
318
- unverified,
319
- {
320
- title: 'Reticle client hook',
321
- target: SVELTEKIT_HOOKS_PATH,
322
- status: StepStatus.APPLY,
323
- detail: 'create dev-only client connect (SvelteKit renders via app.html)',
324
- write: {
325
- path: SVELTEKIT_HOOKS_PATH,
326
- content: svelteKitHooksFile(input.options.port, input.options.projectId),
327
- },
328
- },
329
- ];
330
398
  }
331
399
  function reticleConfigStep(input) {
332
- if (input.reticleConfigExists === true) {
400
+ if (true === input.reticleConfigExists) {
333
401
  return {
334
402
  title: 'Reticle config',
335
403
  target: RETICLE_CONFIG_FILE,
@@ -346,10 +414,31 @@ function reticleConfigStep(input) {
346
414
  write: { path: RETICLE_CONFIG_FILE, content },
347
415
  };
348
416
  }
417
+ /**
418
+ * A step that says out loud when the app isn't React. SvelteKit already carries its own unverified
419
+ * note, so it isn't doubled up here.
420
+ */
421
+ function uiLibraryStep(input) {
422
+ const lib = input.detection.uiLibrary;
423
+ if (lib === UiLibrary.REACT || input.detection.framework === Framework.SVELTEKIT)
424
+ return [];
425
+ if (lib === UiLibrary.UNKNOWN)
426
+ return [];
427
+ return [
428
+ {
429
+ title: `${lib} is UNVERIFIED`,
430
+ target: 'package.json',
431
+ status: StepStatus.NOTICE,
432
+ detail: unverifiedUiLibraryNote(lib),
433
+ },
434
+ ];
435
+ }
349
436
  export function buildPlan(input) {
350
437
  const steps = [
351
438
  ...mcpSteps(input),
352
439
  ...agentRuleSteps(input),
440
+ ...slashCommandSteps(input),
441
+ ...uiLibraryStep(input),
353
442
  installStep(input),
354
443
  reticleConfigStep(input),
355
444
  ];
@@ -359,8 +448,18 @@ export function buildPlan(input) {
359
448
  else if (input.detection.framework === Framework.NEXT) {
360
449
  steps.push(...nextSteps(input));
361
450
  }
451
+ else if (input.detection.framework === Framework.ASTRO) {
452
+ steps.push(...astroSteps(input));
453
+ }
454
+ else if (input.detection.framework === Framework.CRA) {
455
+ steps.push(...craSteps(input));
456
+ }
362
457
  else if (input.detection.framework === Framework.SVELTEKIT) {
363
458
  steps.push(...svelteKitSteps(input));
459
+ // The Vite plugin as well as the client hook. `init` already INSTALLS @reticlehq/vite-plugin for
460
+ // SvelteKit and then never wired it into the config, so it sat in package.json doing nothing —
461
+ // which is why a SvelteKit app connected fine and every verdict came back with no file:line.
462
+ steps.push(...viteSteps(input, VITE_PLUGIN_DETAIL.SVELTEKIT));
364
463
  }
365
464
  else {
366
465
  steps.push({
@@ -1,16 +1,12 @@
1
1
  /**
2
- * Project-identity derivation for `reticle init` — the Next/HTML/.reticle.json side of the same scheme the
3
- * Vite plugin uses at build time. Kept algorithmically identical (slug of package.json name + 8-char
4
- * hash of the absolute root) so a Vite app's plugin-stamped projectId matches what init records.
2
+ * Project-identity for `reticle init` — the `.reticle.json` side of the scheme the Vite plugin
3
+ * stamps at build time. The RULE lives in `@reticlehq/core` (projectIdFrom) so both sides spell the
4
+ * id the same way by construction; this file supplies only the Node-only hashing it needs.
5
5
  */
6
- /** `@acme/web` → `acme-web`; non-alphanumerics collapse to single dashes; edges trimmed. */
7
- export declare function slugifyPackageName(name: string): string;
6
+ export { slugifyPackageName } from '@reticlehq/core';
8
7
  /** Short, stable hex fingerprint of the absolute project root. */
9
8
  export declare function shortHash(input: string): string;
10
- /**
11
- * Derive the stable projectId from the package name (may be undefined) and the absolute root path.
12
- * Falls back to the root folder name, then "app". Pure.
13
- */
9
+ /** Derive the stable projectId from the package name (may be undefined) and the absolute root path. */
14
10
  export declare function deriveProjectId(pkgName: string | undefined, rootPath: string): string;
15
11
  /** Pull a string `name` out of an already-parsed package.json object, or undefined. */
16
12
  export declare function packageName(pkg: unknown): string | undefined;
@@ -1,36 +1,24 @@
1
1
  /**
2
- * Project-identity derivation for `reticle init` — the Next/HTML/.reticle.json side of the same scheme the
3
- * Vite plugin uses at build time. Kept algorithmically identical (slug of package.json name + 8-char
4
- * hash of the absolute root) so a Vite app's plugin-stamped projectId matches what init records.
2
+ * Project-identity for `reticle init` — the `.reticle.json` side of the scheme the Vite plugin
3
+ * stamps at build time. The RULE lives in `@reticlehq/core` (projectIdFrom) so both sides spell the
4
+ * id the same way by construction; this file supplies only the Node-only hashing it needs.
5
5
  */
6
6
  import { createHash } from 'node:crypto';
7
- import { basename } from 'node:path';
8
- /** `@acme/web` → `acme-web`; non-alphanumerics collapse to single dashes; edges trimmed. */
9
- export function slugifyPackageName(name) {
10
- return name
11
- .toLowerCase()
12
- .replace(/^@/, '')
13
- .replace(/[^a-z0-9]+/g, '-')
14
- .replace(/^-+|-+$/g, '');
15
- }
7
+ import { PROJECT_ID_HASH_LENGTH, projectIdFrom } from '@reticlehq/core';
8
+ export { slugifyPackageName } from '@reticlehq/core';
16
9
  /** Short, stable hex fingerprint of the absolute project root. */
17
10
  export function shortHash(input) {
18
- return createHash('sha1').update(input).digest('hex').slice(0, 8);
11
+ return createHash('sha1').update(input).digest('hex').slice(0, PROJECT_ID_HASH_LENGTH);
19
12
  }
20
- /**
21
- * Derive the stable projectId from the package name (may be undefined) and the absolute root path.
22
- * Falls back to the root folder name, then "app". Pure.
23
- */
13
+ /** Derive the stable projectId from the package name (may be undefined) and the absolute root path. */
24
14
  export function deriveProjectId(pkgName, rootPath) {
25
- const fromName = pkgName !== undefined ? slugifyPackageName(pkgName) : '';
26
- const base = fromName.length > 0 ? fromName : slugifyPackageName(basename(rootPath)) || 'app';
27
- return `${base}-${shortHash(rootPath)}`;
15
+ return projectIdFrom(pkgName, rootPath, shortHash);
28
16
  }
29
17
  /** Pull a string `name` out of an already-parsed package.json object, or undefined. */
30
18
  export function packageName(pkg) {
31
- if (typeof pkg === 'object' && pkg !== null) {
19
+ if ('object' === typeof pkg && pkg !== null) {
32
20
  const name = pkg['name'];
33
- if (typeof name === 'string' && name.length > 0)
21
+ if ('string' === typeof name && name.length > 0)
34
22
  return name;
35
23
  }
36
24
  return undefined;
@@ -15,6 +15,13 @@ export interface InitOptions {
15
15
  mcp: boolean;
16
16
  dryRun: boolean;
17
17
  install: boolean;
18
+ /**
19
+ * Which app in a monorepo to wire, when several are found. Without it `init` refuses to guess, and
20
+ * "re-run inside the one you want" is not an instruction a script or an agent can follow.
21
+ */
22
+ app?: string;
23
+ /** Set on the recursive call after a workspace redirect, so the search happens at most once. */
24
+ redirected?: boolean;
18
25
  }
19
26
  export interface InitIo {
20
27
  /** Returns file content or null if it does not exist. Path is project-relative or absolute. */
@@ -26,6 +33,12 @@ export interface InitIo {
26
33
  homeDir(): string;
27
34
  /** Basenames present in the project root. */
28
35
  rootFiles(): readonly string[];
36
+ /** Subdirectory names inside a project-relative directory; empty when it isn't one. */
37
+ listDirs(relPath: string): readonly string[];
38
+ /** File (non-directory) basenames inside a project-relative directory, including dotfiles. */
39
+ listFiles(relPath: string): readonly string[];
40
+ /** The same IO re-rooted at a project-relative subdirectory (used for the workspace redirect). */
41
+ scoped(relPath: string): InitIo;
29
42
  /** Runs a subprocess to completion (inherits stdio); returns true on exit code 0. */
30
43
  exec(command: string, args: readonly string[]): boolean;
31
44
  /** Runs a subprocess quietly (no stdio) for a yes/no check; returns true on exit code 0. */
@@ -37,5 +50,14 @@ interface InitResult {
37
50
  applied: number;
38
51
  manual: number;
39
52
  }
53
+ /**
54
+ * App directories under a workspace root.
55
+ *
56
+ * Running `reticle init` at the repo root is what people actually do, and in a monorepo the app is a
57
+ * directory down — so init detected "no framework", printed a wall of manual HTML instructions, and
58
+ * would have installed the SDK into the ROOT package.json. It already walks UP for the lockfile, so
59
+ * it knows it is in a workspace; this is the matching walk DOWN.
60
+ */
61
+ export declare function findWorkspaceApps(io: Pick<InitIo, 'exists' | 'readFile' | 'listDirs'>): string[];
40
62
  export declare function runInit(options: InitOptions, io: InitIo): InitResult;
41
63
  export {};