@reticlehq/server 3.2.0 → 3.4.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 (437) hide show
  1. package/LICENSE-ENTERPRISE +1 -1
  2. package/README.md +3 -3
  3. package/SKILL.md +23 -22
  4. package/dist/chromium-launch-options.d.ts +4 -3
  5. package/dist/chromium-launch-options.js +6 -2
  6. package/dist/command/cli/adhoc-suite.d.ts +41 -0
  7. package/dist/command/cli/adhoc-suite.js +159 -0
  8. package/dist/command/cli/adhoc-verdict.d.ts +58 -2
  9. package/dist/command/cli/adhoc-verdict.js +108 -13
  10. package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
  11. package/dist/command/cli/answers/gate-hook-message.js +6 -0
  12. package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
  13. package/dist/command/cli/auth/cloud-keystore.js +0 -3
  14. package/dist/command/cli/auth/cloud-session.d.ts +4 -0
  15. package/dist/command/cli/auth/cloud-session.js +2 -0
  16. package/dist/command/cli/cli-doctor.js +30 -8
  17. package/dist/command/cli/cli-flow-commands.d.ts +3 -6
  18. package/dist/command/cli/cli-flow-commands.js +67 -4
  19. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  20. package/dist/command/cli/cli-parse-grammar.js +7 -0
  21. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  22. package/dist/command/cli/cli-parse-verify.js +86 -13
  23. package/dist/command/cli/cli-parse.d.ts +14 -1
  24. package/dist/command/cli/cli-parse.js +54 -8
  25. package/dist/command/cli/cli-update-commands.js +8 -1
  26. package/dist/command/cli/cli-verify.d.ts +80 -0
  27. package/dist/command/cli/cli-verify.js +181 -26
  28. package/dist/command/cli/cloud-cli.js +5 -2
  29. package/dist/command/cli/cloud-kit.d.ts +0 -2
  30. package/dist/command/cli/cloud-kit.js +3 -5
  31. package/dist/command/cli/cloud-login.js +21 -3
  32. package/dist/command/cli/demo/demo-page.js +6 -3
  33. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
  34. package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
  35. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  36. package/dist/command/cli/launch/cli-launch.d.ts +9 -29
  37. package/dist/command/cli/launch/cli-launch.js +27 -49
  38. package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
  39. package/dist/command/cli/launch/sdk-version-match.js +206 -0
  40. package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
  41. package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
  42. package/dist/command/cli/ports/resolve/cli-port.js +169 -15
  43. package/dist/command/cli/report-command.d.ts +16 -0
  44. package/dist/command/cli/report-command.js +97 -0
  45. package/dist/command/cli/setup-mcp-cli.js +13 -13
  46. package/dist/command/cli/tutorial.d.ts +2 -2
  47. package/dist/command/cli/tutorial.js +21 -7
  48. package/dist/command/cli.js +67 -10
  49. package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
  50. package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
  51. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  52. package/dist/command/daemon/daemon-resolve.d.ts +9 -0
  53. package/dist/command/daemon/daemon-resolve.js +1 -1
  54. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  55. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
  56. package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
  57. package/dist/command/dev/stale-issue-guard.d.ts +3 -4
  58. package/dist/command/dev/stale-issue-guard.js +8 -8
  59. package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
  60. package/dist/command/setup/bringup/connect-lease.js +38 -0
  61. package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
  62. package/dist/command/setup/bringup/dev-server-files.js +131 -0
  63. package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
  64. package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
  65. package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
  66. package/dist/command/setup/bringup/ensure-daemon.js +135 -16
  67. package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
  68. package/dist/command/setup/bringup/static-page-server.js +151 -0
  69. package/dist/command/setup/desktop-shape.d.ts +4 -0
  70. package/dist/command/setup/desktop-shape.js +18 -2
  71. package/dist/command/setup/init/init-host.js +8 -0
  72. package/dist/command/setup/init/init-port.d.ts +15 -0
  73. package/dist/command/setup/init/init-port.js +44 -0
  74. package/dist/command/setup/init/init-runtime.d.ts +1 -1
  75. package/dist/command/setup/init/init-runtime.js +39 -2
  76. package/dist/command/setup/node-effects.d.ts +27 -14
  77. package/dist/command/setup/node-effects.js +80 -44
  78. package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
  79. package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
  80. package/dist/command/setup/probe/page-probe.d.ts +13 -2
  81. package/dist/command/setup/probe/page-probe.js +18 -3
  82. package/dist/command/setup/run-setup.d.ts +26 -1
  83. package/dist/command/setup/run-setup.js +96 -13
  84. package/dist/command/setup/session-pick.d.ts +13 -0
  85. package/dist/command/setup/session-pick.js +20 -0
  86. package/dist/command/setup/setup-command.d.ts +2 -14
  87. package/dist/command/setup/setup-command.js +105 -31
  88. package/dist/command/setup/setup-mcp.js +3 -3
  89. package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
  90. package/dist/command/setup/terminal/wait-progress.js +17 -0
  91. package/dist/features/crawl/crawl-empty.js +1 -1
  92. package/dist/features/crawl/crawl-tools.d.ts +6 -0
  93. package/dist/features/crawl/crawl-tools.js +57 -0
  94. package/dist/features/crawl/crawl.d.ts +2 -0
  95. package/dist/features/crawl/crawl.js +171 -156
  96. package/dist/features/exhaust/app-coverage.d.ts +33 -0
  97. package/dist/features/exhaust/app-coverage.js +31 -0
  98. package/dist/features/exhaust/code-coverage.d.ts +47 -0
  99. package/dist/features/exhaust/code-coverage.js +77 -0
  100. package/dist/features/exhaust/exhaust-run.d.ts +33 -0
  101. package/dist/features/exhaust/exhaust-run.js +82 -0
  102. package/dist/features/exhaust/explorer.d.ts +103 -0
  103. package/dist/features/exhaust/explorer.js +195 -0
  104. package/dist/features/exhaust/failure-branches.d.ts +33 -0
  105. package/dist/features/exhaust/failure-branches.js +92 -0
  106. package/dist/features/exhaust/ledger.d.ts +202 -0
  107. package/dist/features/exhaust/ledger.js +252 -0
  108. package/dist/features/exhaust/session-fold.d.ts +31 -0
  109. package/dist/features/exhaust/session-fold.js +79 -0
  110. package/dist/features/exhaust/session-port.d.ts +36 -0
  111. package/dist/features/exhaust/session-port.js +102 -0
  112. package/dist/features/harness/drive-report.d.ts +0 -9
  113. package/dist/features/harness/drive-report.js +18 -0
  114. package/dist/features/harness/driver.js +4 -7
  115. package/dist/features/harness/fill-values.d.ts +6 -0
  116. package/dist/features/harness/fill-values.js +3 -0
  117. package/dist/features/harness/jev-driver.js +36 -22
  118. package/dist/features/harness/openai-driver.js +4 -7
  119. package/dist/features/harness/platform-config.d.ts +10 -0
  120. package/dist/features/harness/platform-config.js +13 -6
  121. package/dist/index.d.ts +10 -1
  122. package/dist/index.js +78 -104
  123. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  124. package/dist/judgement/capsule/capsule-store.js +58 -6
  125. package/dist/judgement/capsule/capsule.js +5 -0
  126. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  127. package/dist/judgement/capsule/causal-summary.js +7 -0
  128. package/dist/judgement/domain/domain-model.js +40 -9
  129. package/dist/judgement/oracles/self-instrument.js +4 -2
  130. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  131. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  132. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  133. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  134. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  135. package/dist/judgement/runs/artifact/render-report.js +4 -1
  136. package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
  137. package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
  138. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  139. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  140. package/dist/judgement/runs/context-tools.js +21 -3
  141. package/dist/judgement/runs/drive-run.js +7 -2
  142. package/dist/judgement/runs/verification-sync.d.ts +3 -1
  143. package/dist/judgement/runs/verification-sync.js +1 -1
  144. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  145. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  146. package/dist/language/flows/change/affected.d.ts +9 -0
  147. package/dist/language/flows/change/affected.js +35 -0
  148. package/dist/language/flows/change/gate.d.ts +20 -0
  149. package/dist/language/flows/change/gate.js +12 -1
  150. package/dist/language/flows/flow-anchor.d.ts +12 -0
  151. package/dist/language/flows/flow-anchor.js +20 -0
  152. package/dist/language/flows/flow-author.d.ts +7 -0
  153. package/dist/language/flows/flow-author.js +19 -0
  154. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  155. package/dist/language/flows/flow-expect-grammar.js +92 -11
  156. package/dist/language/flows/flow-intent.js +1 -1
  157. package/dist/language/flows/flow-journey.d.ts +54 -0
  158. package/dist/language/flows/flow-journey.js +119 -0
  159. package/dist/language/flows/flow-learning.d.ts +3 -0
  160. package/dist/language/flows/flow-learning.js +39 -8
  161. package/dist/language/flows/flow-replay-run.d.ts +33 -12
  162. package/dist/language/flows/flow-replay-run.js +131 -52
  163. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  164. package/dist/language/flows/flow-replay.d.ts +27 -12
  165. package/dist/language/flows/flow-replay.js +127 -111
  166. package/dist/language/flows/flow-result.d.ts +2 -0
  167. package/dist/language/flows/flow-result.js +25 -0
  168. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  169. package/dist/language/flows/flow-step-runners.js +20 -4
  170. package/dist/language/flows/flow-success.d.ts +21 -6
  171. package/dist/language/flows/flow-success.js +50 -138
  172. package/dist/language/flows/flow-tools.js +17 -5
  173. package/dist/language/flows/flows.d.ts +18 -5
  174. package/dist/language/flows/flows.js +101 -16
  175. package/dist/language/flows/heal.d.ts +9 -1
  176. package/dist/language/flows/heal.js +24 -2
  177. package/dist/language/flows/learned-sources.d.ts +21 -0
  178. package/dist/language/flows/learned-sources.js +84 -0
  179. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  180. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  181. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  182. package/dist/language/flows/recording/replay-halt.js +3 -1
  183. package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
  184. package/dist/language/flows/recording/tape/recordings.js +55 -1
  185. package/dist/language/flows/replay.d.ts +19 -0
  186. package/dist/language/flows/replay.js +53 -13
  187. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  188. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  189. package/dist/language/flows/stores/flake-store.js +2 -3
  190. package/dist/language/flows/suite/coverage.d.ts +1 -1
  191. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  192. package/dist/language/flows/verify-change-tools.js +19 -2
  193. package/dist/launch-chromium.d.ts +80 -0
  194. package/dist/launch-chromium.js +218 -0
  195. package/dist/memory/cloud/cloud-config.d.ts +11 -2
  196. package/dist/memory/cloud/cloud-config.js +47 -7
  197. package/dist/memory/cloud/cloud-sync.d.ts +4 -3
  198. package/dist/memory/cloud/cloud-sync.js +7 -10
  199. package/dist/memory/cloud/harness-config.d.ts +2 -0
  200. package/dist/memory/cloud/harness-offer.js +5 -6
  201. package/dist/memory/cloud/harness-switch.js +5 -6
  202. package/dist/memory/cloud/sync-cycle.d.ts +78 -1
  203. package/dist/memory/cloud/sync-cycle.js +321 -53
  204. package/dist/memory/cloud/sync-daemon.d.ts +13 -0
  205. package/dist/memory/cloud/sync-daemon.js +45 -20
  206. package/dist/memory/cloud/sync-disk.js +27 -8
  207. package/dist/memory/impact/impact-store.js +6 -0
  208. package/dist/memory/intent/inline-intent.js +8 -3
  209. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  210. package/dist/memory/intent/intent-shard-store.js +252 -140
  211. package/dist/memory/intent/intent-shard.d.ts +0 -23
  212. package/dist/memory/intent/intent-shard.js +1 -11
  213. package/dist/memory/intent/intent-store.d.ts +13 -8
  214. package/dist/memory/intent/intent-store.js +46 -90
  215. package/dist/memory/intent/intent-tools.js +34 -23
  216. package/dist/memory/journal/ambient-store.js +2 -3
  217. package/dist/memory/journal/deviation-report.js +4 -1
  218. package/dist/memory/journal/deviation-service.js +10 -2
  219. package/dist/memory/journal/drive-flow.d.ts +19 -14
  220. package/dist/memory/journal/drive-flow.js +65 -48
  221. package/dist/memory/journal/envelope-store.js +2 -3
  222. package/dist/memory/journal/journal-recorder.d.ts +21 -0
  223. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  224. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  225. package/dist/memory/journal/on-disk/retention.d.ts +14 -10
  226. package/dist/memory/journal/on-disk/retention.js +13 -12
  227. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  228. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  229. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
  230. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
  231. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  232. package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
  233. package/dist/memory/journal/route-template.d.ts +22 -0
  234. package/dist/memory/journal/route-template.js +44 -0
  235. package/dist/memory/journal/session-end.d.ts +13 -2
  236. package/dist/memory/journal/session-end.js +88 -18
  237. package/dist/memory/journal/session-journal.d.ts +8 -1
  238. package/dist/memory/journal/session-journal.js +10 -0
  239. package/dist/memory/project/baselines.d.ts +1 -1
  240. package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
  241. package/dist/memory/project/dir/reticle-dir.js +1 -0
  242. package/dist/memory/project/fs/fs-port.js +44 -5
  243. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  244. package/dist/memory/project/fs/write-atomic.js +48 -0
  245. package/dist/memory/project/project-tools.js +3 -1
  246. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  247. package/dist/memory/recall/prior/connection-memory.js +8 -0
  248. package/dist/memory/recall/registered-projects.d.ts +2 -1
  249. package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
  250. package/dist/portal/bridge/auth-failure-reason.js +9 -4
  251. package/dist/portal/bridge/bridge.d.ts +8 -0
  252. package/dist/portal/bridge/bridge.js +43 -2
  253. package/dist/portal/input/js-coverage.d.ts +25 -0
  254. package/dist/portal/input/js-coverage.js +30 -0
  255. package/dist/portal/input/real-input.d.ts +11 -0
  256. package/dist/portal/input/real-input.js +31 -5
  257. package/dist/portal/pool/browser-pool.d.ts +10 -0
  258. package/dist/portal/pool/browser-pool.js +10 -0
  259. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  260. package/dist/portal/pool/playwright-launcher.js +21 -13
  261. package/dist/portal/pool/pool-contract.d.ts +2 -0
  262. package/dist/portal/pool/storage-seed.d.ts +2 -1
  263. package/dist/portal/pool/zero-install.d.ts +27 -0
  264. package/dist/portal/pool/zero-install.js +54 -0
  265. package/dist/portal/realm/web-realm.js +6 -0
  266. package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
  267. package/dist/portal/session/dev-server/dev-command.js +30 -12
  268. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  269. package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
  270. package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
  271. package/dist/portal/session/dev-server/route-status-probe.js +57 -0
  272. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  273. package/dist/portal/session/dev-server/served-document.js +57 -0
  274. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  275. package/dist/portal/session/facts/background-traffic.js +25 -0
  276. package/dist/portal/session/facts/observed-state.d.ts +11 -0
  277. package/dist/portal/session/facts/observed-state.js +34 -0
  278. package/dist/portal/session/live-control-tools.js +48 -3
  279. package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
  280. package/dist/portal/session/no-session-diagnosis.js +62 -5
  281. package/dist/portal/session/no-session-next-action.d.ts +13 -0
  282. package/dist/portal/session/no-session-next-action.js +48 -9
  283. package/dist/portal/session/no-session-watch.d.ts +18 -0
  284. package/dist/portal/session/no-session-watch.js +88 -2
  285. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  286. package/dist/portal/session/session-health.d.ts +61 -0
  287. package/dist/portal/session/session-health.js +43 -3
  288. package/dist/portal/session/session-info.d.ts +6 -0
  289. package/dist/portal/session/session-manager.d.ts +29 -6
  290. package/dist/portal/session/session-manager.js +42 -5
  291. package/dist/portal/session/session-reaper.d.ts +28 -0
  292. package/dist/portal/session/session-reaper.js +49 -1
  293. package/dist/portal/session/session-successor.d.ts +11 -0
  294. package/dist/portal/session/session-successor.js +14 -1
  295. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  296. package/dist/portal/session/session-verdict-facts.js +15 -0
  297. package/dist/portal/session/session.d.ts +10 -0
  298. package/dist/portal/session/session.js +34 -26
  299. package/dist/surface/http-server.d.ts +2 -1
  300. package/dist/surface/http-server.js +4 -2
  301. package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
  302. package/dist/surface/mcp/mcp-proxy.js +5 -5
  303. package/dist/surface/mcp/mcp.js +4 -2
  304. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
  305. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
  306. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  307. package/dist/surface/mcp/server-instructions.js +21 -8
  308. package/dist/surface/tools/act/after-match.d.ts +17 -0
  309. package/dist/surface/tools/act/after-match.js +30 -0
  310. package/dist/surface/tools/act/already-true.d.ts +40 -0
  311. package/dist/surface/tools/act/already-true.js +36 -0
  312. package/dist/surface/tools/act/durable.d.ts +69 -0
  313. package/dist/surface/tools/act/durable.js +139 -0
  314. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
  315. package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
  316. package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
  317. package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
  318. package/dist/surface/tools/act/proved-controls.d.ts +9 -0
  319. package/dist/surface/tools/act/proved-controls.js +11 -0
  320. package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
  321. package/dist/surface/tools/act/sequence-grade.js +32 -1
  322. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  323. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  324. package/dist/surface/tools/act-capsule.d.ts +7 -0
  325. package/dist/surface/tools/act-capsule.js +68 -8
  326. package/dist/surface/tools/act-sequence-tool.js +25 -8
  327. package/dist/surface/tools/act-tools.js +51 -74
  328. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  329. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  330. package/dist/surface/tools/assert/assert-grade.js +26 -3
  331. package/dist/surface/tools/assert/assert-verdict.js +32 -6
  332. package/dist/surface/tools/browser-tools.js +17 -4
  333. package/dist/surface/tools/coverage-tools.js +27 -1
  334. package/dist/surface/tools/dynamic-tools.js +6 -0
  335. package/dist/surface/tools/error-recovery.js +4 -4
  336. package/dist/surface/tools/feedback-invite.js +6 -4
  337. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  338. package/dist/surface/tools/feedback-tools.js +1 -1
  339. package/dist/surface/tools/harness-explore.d.ts +3 -2
  340. package/dist/surface/tools/harness-explore.js +7 -6
  341. package/dist/surface/tools/invoke-tool.js +17 -4
  342. package/dist/surface/tools/lease-hint.d.ts +8 -0
  343. package/dist/surface/tools/lease-hint.js +10 -0
  344. package/dist/surface/tools/lease-tools.d.ts +16 -28
  345. package/dist/surface/tools/lease-tools.js +68 -11
  346. package/dist/surface/tools/lineage-tools.js +1 -1
  347. package/dist/surface/tools/live-call-text.js +4 -1
  348. package/dist/surface/tools/observe-tools.js +23 -7
  349. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  350. package/dist/surface/tools/real-input-attempt.js +1 -1
  351. package/dist/surface/tools/tool-kit.d.ts +5 -0
  352. package/dist/surface/tools/tool-kit.js +6 -1
  353. package/dist/surface/tools/tool-surface.js +17 -5
  354. package/dist/surface/tools/tools.js +68 -29
  355. package/dist/telemetry/argument-shape.d.ts +0 -2
  356. package/dist/telemetry/argument-shape.js +0 -4
  357. package/dist/telemetry/error-class.d.ts +2 -3
  358. package/dist/telemetry/error-class.js +2 -3
  359. package/dist/telemetry/feedback-local.d.ts +1 -0
  360. package/dist/telemetry/feedback-local.js +1 -3
  361. package/dist/telemetry/feedback.d.ts +1 -1
  362. package/dist/telemetry/harness-drive.d.ts +0 -2
  363. package/dist/telemetry/harness-drive.js +0 -4
  364. package/dist/telemetry/hud-metrics.d.ts +32 -0
  365. package/dist/telemetry/hud-metrics.js +95 -0
  366. package/dist/telemetry/session-metrics.d.ts +5 -0
  367. package/dist/telemetry/session-metrics.js +15 -1
  368. package/dist/wire-journal.d.ts +34 -0
  369. package/dist/wire-journal.js +104 -0
  370. package/dist/workspace-packages.d.ts +0 -2
  371. package/dist/workspace-packages.js +1 -9
  372. package/docs/README.md +5 -2
  373. package/docs/actions.mdx +3 -3
  374. package/docs/agent-cheatsheet.md +4 -4
  375. package/docs/architecture.md +6 -6
  376. package/docs/best-practices.mdx +1 -1
  377. package/docs/capabilities.mdx +32 -1
  378. package/docs/cli/cloud.mdx +21 -9
  379. package/docs/cli/doctor.mdx +4 -0
  380. package/docs/cli/feedback.mdx +2 -2
  381. package/docs/cli/gate.mdx +9 -4
  382. package/docs/cli/init.mdx +1 -0
  383. package/docs/cli/report.mdx +44 -0
  384. package/docs/cli/update.mdx +10 -0
  385. package/docs/cli.mdx +9 -0
  386. package/docs/desktop.mdx +14 -10
  387. package/docs/environment.mdx +87 -0
  388. package/docs/faq.mdx +18 -16
  389. package/docs/first-drive.md +5 -13
  390. package/docs/flows.md +32 -2
  391. package/docs/frameworks.mdx +140 -9
  392. package/docs/getting-started.md +3 -3
  393. package/docs/http-transport.md +6 -3
  394. package/docs/human-control.md +2 -2
  395. package/docs/index.mdx +16 -6
  396. package/docs/install-agentic.mdx +37 -1
  397. package/docs/install-manual.mdx +1 -1
  398. package/docs/integration-patterns.md +3 -3
  399. package/docs/multi-agent-testing.md +1 -1
  400. package/docs/packages/babel-plugin.mdx +1 -1
  401. package/docs/packages/browser.mdx +2 -2
  402. package/docs/packages/react.mdx +2 -2
  403. package/docs/packages/tauri.mdx +1 -1
  404. package/docs/packages/vite-plugin.mdx +2 -2
  405. package/docs/packages.mdx +9 -9
  406. package/docs/predicates.mdx +176 -7
  407. package/docs/quickstart.mdx +2 -2
  408. package/docs/recipes.mdx +2 -2
  409. package/docs/state-management.mdx +2 -2
  410. package/docs/system-map.md +1 -1
  411. package/docs/telemetry.md +1 -1
  412. package/docs/token-efficiency.md +3 -3
  413. package/docs/tools/act-and-wait.mdx +1 -0
  414. package/docs/tools/act-sequence.mdx +1 -1
  415. package/docs/tools/console.mdx +1 -1
  416. package/docs/tools/inspect.mdx +1 -1
  417. package/docs/tools/network.mdx +1 -1
  418. package/docs/tools/query.mdx +11 -11
  419. package/docs/tools/sessions.mdx +1 -1
  420. package/docs/tools/snapshot.mdx +1 -1
  421. package/docs/tools/state.mdx +1 -1
  422. package/docs/tools/wait-for.mdx +1 -1
  423. package/docs/usage.md +8 -7
  424. package/docs/use-cases.mdx +157 -0
  425. package/docs/vs-screenshots.mdx +3 -3
  426. package/docs/what-is-recorded.md +62 -0
  427. package/docs/what-is-reticle.mdx +17 -20
  428. package/docs/why-reticle.mdx +14 -21
  429. package/package.json +11 -10
  430. package/dist/judgement/capsule/minimize.d.ts +0 -12
  431. package/dist/judgement/capsule/minimize.js +0 -22
  432. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  433. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
  434. package/dist/judgement/phenomena/phenomena.d.ts +0 -26
  435. package/dist/judgement/phenomena/phenomena.js +0 -101
  436. package/dist/language/flows/flow-report.d.ts +0 -22
  437. package/dist/language/flows/flow-report.js +0 -106
@@ -23,6 +23,13 @@ export declare const RETICLE_CONFIG_BASENAME = ".reticle.json";
23
23
  * Returns undefined when nothing is found, which keeps every caller's existing default intact.
24
24
  */
25
25
  export declare function findProjectConfig(cwd: string): Record<string, unknown> | undefined;
26
+ /**
27
+ * The directory of the project this invocation serves: where its `.reticle.json` is, else the one
28
+ * wired workspace app below a monorepo root, else `cwd` itself. What the CLI reads the installed SDK
29
+ * from, so it answers for the app the port above belongs to rather than for the directory it was
30
+ * started in.
31
+ */
32
+ export declare function projectDirOf(cwd: string): string;
26
33
  /**
27
34
  * The dev-server port heuristics live in `@reticlehq/init` — `existing-config.ts` is what diagnoses
28
35
  * a `.reticle.json` whose `port` is the app's own dev-server port, and the scaffolder may not import
@@ -33,14 +40,39 @@ export { DEV_SERVER_PORTS, isLikelyDevServerPort, devServerPortWarning } from '@
33
40
  /**
34
41
  * Read the port stored in the project's .reticle.json (written by `reticle init`).
35
42
  * Returns undefined if the file is absent, unreadable, or has no valid numeric port.
43
+ *
44
+ * With no config at or above `cwd`, it looks DOWN, the same way `projectIdsAt` does. Running from a
45
+ * monorepo root whose app was wired in `apps/web` used to find nothing and fall back to the default
46
+ * port, so `status`, `mcp` and `verify` quietly talked to another project's daemon. One wired app
47
+ * below, or several that agree, give their port; several that disagree give none, and
48
+ * `workspacePortConflict` is what says so rather than letting the default win in silence.
36
49
  */
37
50
  export declare function readProjectPort(cwd: string): number | undefined;
51
+ /**
52
+ * The sentence for a monorepo root whose wired apps name different ports, or undefined when there is
53
+ * nothing to choose between. `readProjectPort` refuses to pick one; this is what tells the person
54
+ * which ports exist and how to name the one they meant.
55
+ */
56
+ export declare function workspacePortConflict(cwd: string): string | undefined;
38
57
  /**
39
58
  * Read the stable projectId stored in the project's .reticle.json (written by `reticle init`). The daemon
40
59
  * uses it as the default resolve scope so auto-selection stays within the active app. Returns
41
60
  * undefined if the file is absent/unreadable or has no non-empty string projectId.
42
61
  */
43
62
  export declare function readProjectId(cwd: string): ProjectId | undefined;
63
+ /**
64
+ * Every project id this directory can speak for, for "has THIS project ever connected".
65
+ *
66
+ * `readProjectId` knows only what `init` wrote. The build plugins derive the same id from the package
67
+ * name and the app root WITHOUT writing `.reticle.json`, so a monorepo root (the app lives in
68
+ * `apps/web`) and an app wired by the plugin alone both read `undefined`, and the handshake told a
69
+ * working project nothing had ever connected. Deriving the plugin's own id cannot reopen the opposite
70
+ * lie: an id only counts once an app with exactly that id has dialled in.
71
+ *
72
+ * Workspace discovery is init's `findWorkspaceApps`, reused so the two cannot disagree about which
73
+ * directories are apps. Best-effort: a directory it cannot read contributes nothing.
74
+ */
75
+ export declare function projectIdsAt(cwd: string): ProjectId[];
44
76
  /**
45
77
  * The framework `reticle init` stamped into `.reticle.json`, when there is one.
46
78
  *
@@ -50,6 +82,12 @@ export declare function readProjectId(cwd: string): ProjectId | undefined;
50
82
  * time and the hint the agent reads hours later never mentioned it.
51
83
  */
52
84
  export declare function readProjectFramework(cwd: string): string | undefined;
85
+ /**
86
+ * Whether the project this directory serves is a desktop shell (Electron, Tauri) — the same question
87
+ * `doctor` asks, answered from the same files. Read so the no-session guidance stops sending a
88
+ * desktop user to a browser URL.
89
+ */
90
+ export declare function readProjectIsDesktop(cwd: string): boolean;
53
91
  /**
54
92
  * Whether the durable causal journal is enabled. On by default (the journal IS the loop); off only via
55
93
  * explicit opt-out — `.reticle.json` `"journal": false`, or `RETICLE_JOURNAL` set to `0`/`false`. The env
@@ -8,7 +8,8 @@
8
8
  * 4. RETICLE_DEFAULT_PORT (4400)
9
9
  */
10
10
  import { readFileSync } from 'node:fs';
11
- import { dirname, resolve } from 'node:path';
11
+ import { dirname, join, resolve } from 'node:path';
12
+ import { SILENT_HOST, buildNodeIo, deriveProjectId, findWorkspaceApps, isDesktopProject, packageName, } from '@reticlehq/init';
12
13
  import { asProjectId } from '@reticlehq/core';
13
14
  /** The project config `reticle init` writes. */
14
15
  export const RETICLE_CONFIG_BASENAME = '.reticle.json';
@@ -34,18 +35,15 @@ const MAX_CONFIG_SEARCH_DEPTH = 6;
34
35
  * Returns undefined when nothing is found, which keeps every caller's existing default intact.
35
36
  */
36
37
  export function findProjectConfig(cwd) {
38
+ const dir = findProjectConfigDir(cwd);
39
+ return dir === undefined ? undefined : readConfigAt(dir);
40
+ }
41
+ /** The directory holding the nearest `.reticle.json` at or above `cwd`, by the same walk. */
42
+ function findProjectConfigDir(cwd) {
37
43
  let dir = resolve(cwd);
38
44
  for (let depth = 0; depth <= MAX_CONFIG_SEARCH_DEPTH; depth += 1) {
39
- try {
40
- const raw = readFileSync(`${dir}/${RETICLE_CONFIG_BASENAME}`, 'utf8');
41
- const config = JSON.parse(raw);
42
- if ('object' === typeof config && config !== null && !Array.isArray(config)) {
43
- return config;
44
- }
45
- }
46
- catch {
47
- // Absent, unreadable, or not JSON at this level — keep walking.
48
- }
45
+ if (readConfigAt(dir) !== undefined)
46
+ return dir;
49
47
  const parent = dirname(dir);
50
48
  if (parent === dir)
51
49
  break;
@@ -53,6 +51,48 @@ export function findProjectConfig(cwd) {
53
51
  }
54
52
  return undefined;
55
53
  }
54
+ /**
55
+ * The directory of the project this invocation serves: where its `.reticle.json` is, else the one
56
+ * wired workspace app below a monorepo root, else `cwd` itself. What the CLI reads the installed SDK
57
+ * from, so it answers for the app the port above belongs to rather than for the directory it was
58
+ * started in.
59
+ */
60
+ export function projectDirOf(cwd) {
61
+ const configDir = findProjectConfigDir(cwd);
62
+ if (configDir !== undefined)
63
+ return appPointedAtBy(configDir) ?? configDir;
64
+ const apps = workspaceAppPorts(cwd);
65
+ const only = 1 === apps.length ? apps[0] : undefined;
66
+ return only === undefined ? resolve(cwd) : join(resolve(cwd), only.app);
67
+ }
68
+ /**
69
+ * The one workspace app below `dir` whose own config names the project `dir`'s does, or undefined.
70
+ *
71
+ * `init` writes a copy of the app's `.reticle.json` at the root the agent runs from, so the root's
72
+ * config is a pointer to that app rather than a project of its own. The projectId is the link — no
73
+ * path is stored — and a root whose id no app shares, or several do, is its own project.
74
+ */
75
+ function appPointedAtBy(dir) {
76
+ const id = readConfigAt(dir)?.['projectId'];
77
+ if ('string' !== typeof id || 0 === id.length)
78
+ return undefined;
79
+ const named = workspaceApps(dir).filter((app) => id === readConfigAt(join(dir, app))?.['projectId']);
80
+ const only = 1 === named.length ? named[0] : undefined;
81
+ return only === undefined ? undefined : join(dir, only);
82
+ }
83
+ /** The `.reticle.json` in exactly `dir` — no walk — or undefined when absent or not an object. */
84
+ function readConfigAt(dir) {
85
+ try {
86
+ const config = JSON.parse(readFileSync(join(dir, RETICLE_CONFIG_BASENAME), 'utf8'));
87
+ if ('object' === typeof config && config !== null && !Array.isArray(config)) {
88
+ return config;
89
+ }
90
+ }
91
+ catch {
92
+ // Absent, unreadable, or not JSON at this level.
93
+ }
94
+ return undefined;
95
+ }
56
96
  /**
57
97
  * The dev-server port heuristics live in `@reticlehq/init` — `existing-config.ts` is what diagnoses
58
98
  * a `.reticle.json` whose `port` is the app's own dev-server port, and the scaffolder may not import
@@ -60,15 +100,70 @@ export function findProjectConfig(cwd) {
60
100
  * diagnosis, and `cli.ts`) are unchanged.
61
101
  */
62
102
  export { DEV_SERVER_PORTS, isLikelyDevServerPort, devServerPortWarning } from '@reticlehq/init';
103
+ /** A config's `port`, when it is a usable TCP port. */
104
+ function configPort(config) {
105
+ const p = config?.['port'];
106
+ if ('number' === typeof p && Number.isInteger(p) && p > 0 && p < 65536)
107
+ return p;
108
+ return undefined;
109
+ }
63
110
  /**
64
111
  * Read the port stored in the project's .reticle.json (written by `reticle init`).
65
112
  * Returns undefined if the file is absent, unreadable, or has no valid numeric port.
113
+ *
114
+ * With no config at or above `cwd`, it looks DOWN, the same way `projectIdsAt` does. Running from a
115
+ * monorepo root whose app was wired in `apps/web` used to find nothing and fall back to the default
116
+ * port, so `status`, `mcp` and `verify` quietly talked to another project's daemon. One wired app
117
+ * below, or several that agree, give their port; several that disagree give none, and
118
+ * `workspacePortConflict` is what says so rather than letting the default win in silence.
66
119
  */
67
120
  export function readProjectPort(cwd) {
68
- const p = findProjectConfig(cwd)?.['port'];
69
- if ('number' === typeof p && Number.isInteger(p) && p > 0 && p < 65536)
70
- return p;
71
- return undefined;
121
+ const config = findProjectConfig(cwd);
122
+ if (config !== undefined)
123
+ return configPort(config);
124
+ const ports = new Set(workspaceAppPorts(cwd).map((a) => a.port));
125
+ return 1 === ports.size ? [...ports][0] : undefined;
126
+ }
127
+ /** Each workspace app under `cwd` whose own `.reticle.json` records a port. */
128
+ function workspaceAppPorts(cwd) {
129
+ const found = [];
130
+ for (const app of workspaceApps(cwd)) {
131
+ // The app's OWN file only — walking up from an unwired sibling would reach the root, or past it.
132
+ const port = configPort(readConfigAt(join(cwd, app)));
133
+ if (port !== undefined)
134
+ found.push({ app, port });
135
+ }
136
+ return found;
137
+ }
138
+ /** init's workspace discovery under `cwd`, relative app directories; empty when `cwd` is no package. */
139
+ function workspaceApps(cwd) {
140
+ // Only from a directory that is itself a package: a root with no package.json is not a workspace,
141
+ // and scanning, say, a home directory would adopt the port of whichever checkout happened to sit
142
+ // there.
143
+ if (packageNameAt(cwd) === undefined)
144
+ return [];
145
+ try {
146
+ return findWorkspaceApps(buildNodeIo(cwd, SILENT_HOST));
147
+ }
148
+ catch {
149
+ // Discovery touches the filesystem; an unreadable tree is simply no further evidence.
150
+ return [];
151
+ }
152
+ }
153
+ /**
154
+ * The sentence for a monorepo root whose wired apps name different ports, or undefined when there is
155
+ * nothing to choose between. `readProjectPort` refuses to pick one; this is what tells the person
156
+ * which ports exist and how to name the one they meant.
157
+ */
158
+ export function workspacePortConflict(cwd) {
159
+ if (findProjectConfig(cwd) !== undefined)
160
+ return undefined;
161
+ const apps = workspaceAppPorts(cwd);
162
+ if (new Set(apps.map((a) => a.port)).size < 2)
163
+ return undefined;
164
+ const listed = apps.map((a) => `${a.app} (:${String(a.port)})`).join(', ');
165
+ return (`This workspace has more than one app wired for Reticle, on different ports: ${listed}. ` +
166
+ 'Not guessing which one you meant — run the command from inside that app, or pass --port.');
72
167
  }
73
168
  /**
74
169
  * Read the stable projectId stored in the project's .reticle.json (written by `reticle init`). The daemon
@@ -84,6 +179,49 @@ export function readProjectId(cwd) {
84
179
  return asProjectId(id);
85
180
  return undefined;
86
181
  }
182
+ const PACKAGE_JSON = 'package.json';
183
+ /** The package name in `dir/package.json`, or undefined when there is no readable one. */
184
+ function packageNameAt(dir) {
185
+ try {
186
+ return packageName(JSON.parse(readFileSync(join(dir, PACKAGE_JSON), 'utf8')));
187
+ }
188
+ catch {
189
+ return undefined;
190
+ }
191
+ }
192
+ /** The id an app at `dir` carries: the one `init` recorded, else the one the build plugin derives. */
193
+ function projectIdFor(dir) {
194
+ return readProjectId(dir) ?? asProjectId(deriveProjectId(packageNameAt(dir), dir));
195
+ }
196
+ /**
197
+ * Every project id this directory can speak for, for "has THIS project ever connected".
198
+ *
199
+ * `readProjectId` knows only what `init` wrote. The build plugins derive the same id from the package
200
+ * name and the app root WITHOUT writing `.reticle.json`, so a monorepo root (the app lives in
201
+ * `apps/web`) and an app wired by the plugin alone both read `undefined`, and the handshake told a
202
+ * working project nothing had ever connected. Deriving the plugin's own id cannot reopen the opposite
203
+ * lie: an id only counts once an app with exactly that id has dialled in.
204
+ *
205
+ * Workspace discovery is init's `findWorkspaceApps`, reused so the two cannot disagree about which
206
+ * directories are apps. Best-effort: a directory it cannot read contributes nothing.
207
+ */
208
+ export function projectIdsAt(cwd) {
209
+ const recorded = readProjectId(cwd);
210
+ if (recorded !== undefined)
211
+ return [recorded];
212
+ const ids = [];
213
+ if (packageNameAt(cwd) !== undefined)
214
+ ids.push(projectIdFor(cwd));
215
+ try {
216
+ for (const app of findWorkspaceApps(buildNodeIo(cwd, SILENT_HOST))) {
217
+ ids.push(projectIdFor(join(cwd, app)));
218
+ }
219
+ }
220
+ catch {
221
+ // Discovery touches the filesystem; an unreadable tree is simply no further evidence.
222
+ }
223
+ return [...new Set(ids)];
224
+ }
87
225
  /**
88
226
  * The framework `reticle init` stamped into `.reticle.json`, when there is one.
89
227
  *
@@ -98,6 +236,22 @@ export function readProjectFramework(cwd) {
98
236
  return framework;
99
237
  return undefined;
100
238
  }
239
+ /**
240
+ * Whether the project this directory serves is a desktop shell (Electron, Tauri) — the same question
241
+ * `doctor` asks, answered from the same files. Read so the no-session guidance stops sending a
242
+ * desktop user to a browser URL.
243
+ */
244
+ export function readProjectIsDesktop(cwd) {
245
+ const dir = projectDirOf(cwd);
246
+ return isDesktopProject((relative) => {
247
+ try {
248
+ return readFileSync(join(dir, relative), 'utf8');
249
+ }
250
+ catch {
251
+ return undefined;
252
+ }
253
+ });
254
+ }
101
255
  /**
102
256
  * Whether the durable causal journal is enabled. On by default (the journal IS the loop); off only via
103
257
  * explicit opt-out — `.reticle.json` `"journal": false`, or `RETICLE_JOURNAL` set to `0`/`false`. The env
@@ -0,0 +1,16 @@
1
+ export interface ReportInput {
2
+ cwd: string;
3
+ now: number;
4
+ /** Did the working tree change? The hook stays silent on a turn that edited nothing. */
5
+ treeChanged: boolean;
6
+ session?: string;
7
+ hook?: boolean;
8
+ }
9
+ export declare function reportFor(input: ReportInput): Promise<{
10
+ lines: string[];
11
+ }>;
12
+ /**
13
+ * The command. As a hook it prints Claude Code's `systemMessage` shape and always exits 0: it is
14
+ * print-only by design, so the human sees the gap and the agent is never blocked by it.
15
+ */
16
+ export declare function handleReport(session: string | undefined, hook: boolean): Promise<void>;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * `reticle report [--session <id>] [--hook]` — what this project's latest session claimed, and what held.
3
+ *
4
+ * Read from disk, with no daemon: the journal is on disk, and a Stop hook has to answer in the second
5
+ * after the agent stops, when there may be nothing running to ask. The fold is `gapSummary`, the same
6
+ * one `reticle_context` serves, so the terminal and the agent cannot be told two different stories.
7
+ */
8
+ import { execFileSync } from 'node:child_process';
9
+ import { existsSync, readdirSync, statSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { DiscoveryInvite, ReticleDir } from '@reticlehq/core';
12
+ import { gapSummary } from '../../judgement/runs/artifact/gap-summary.js';
13
+ import { SessionJournal } from '../../memory/journal/session-journal.js';
14
+ import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
15
+ import { gapHookLine, gapReportLines } from '../../judgement/runs/artifact/gap-report.js';
16
+ /**
17
+ * A session last written longer ago than this is not the turn a hook is asking about.
18
+ *
19
+ * ponytail: a fixed window, not a turn boundary — the Stop hook is not told when the turn began. A
20
+ * drive older than an hour reads as "no claim this session", which errs toward saying so.
21
+ */
22
+ const HOOK_WINDOW_MS = 60 * 60 * 1000;
23
+ /** The session whose action ledger was written most recently, if any. */
24
+ function newestSession(root) {
25
+ const sessionsDir = join(root, ReticleDir.SESSIONS_SUBDIR);
26
+ if (!existsSync(sessionsDir))
27
+ return undefined;
28
+ let newest;
29
+ for (const id of readdirSync(sessionsDir)) {
30
+ const ledger = join(sessionsDir, id, ReticleDir.JOURNAL_ACTIONS_FILE);
31
+ if (!existsSync(ledger))
32
+ continue;
33
+ const writtenAt = statSync(ledger).mtimeMs;
34
+ if (newest === undefined || writtenAt > newest.writtenAt)
35
+ newest = { id, writtenAt };
36
+ }
37
+ return newest;
38
+ }
39
+ export async function reportFor(input) {
40
+ if (true === input.hook && !input.treeChanged)
41
+ return { lines: [] };
42
+ const root = join(input.cwd, ReticleDir.ROOT);
43
+ const found = input.session === undefined ? newestSession(root) : { id: input.session, writtenAt: input.now };
44
+ const current = found !== undefined && (true !== input.hook || input.now - found.writtenAt <= HOOK_WINDOW_MS)
45
+ ? found
46
+ : undefined;
47
+ const actions = current === undefined
48
+ ? []
49
+ : await new SessionJournal(createNodeFileSystem(), root, current.id).readActions();
50
+ const gap = gapSummary(actions);
51
+ if (true === input.hook) {
52
+ const line = gapHookLine(gap);
53
+ // A finish with nothing proved is the moment Reticle let somebody down: say who to tell.
54
+ return { lines: line === undefined ? [] : [line, DiscoveryInvite.HUMAN] };
55
+ }
56
+ const header = current === undefined ? [] : [`session ${current.id}`];
57
+ return { lines: [...header, ...gapReportLines(gap), DiscoveryInvite.HUMAN] };
58
+ }
59
+ /** Uncommitted changes in `cwd`. Outside a git repository nothing can say, so it answers yes. */
60
+ function treeChanged(cwd) {
61
+ try {
62
+ return '' !== execFileSync('git', ['status', '--porcelain'], { cwd, encoding: 'utf8' }).trim();
63
+ }
64
+ catch {
65
+ return true;
66
+ }
67
+ }
68
+ /**
69
+ * The command. As a hook it prints Claude Code's `systemMessage` shape and always exits 0: it is
70
+ * print-only by design, so the human sees the gap and the agent is never blocked by it.
71
+ */
72
+ export async function handleReport(session, hook) {
73
+ const cwd = process.cwd();
74
+ let lines;
75
+ try {
76
+ ({ lines } = await reportFor({
77
+ cwd,
78
+ now: Date.now(),
79
+ treeChanged: hook ? treeChanged(cwd) : true,
80
+ ...(session === undefined ? {} : { session }),
81
+ hook,
82
+ }));
83
+ }
84
+ catch (error) {
85
+ // A hook that throws turns the agent's stop into an error the user did not cause; it says nothing
86
+ // instead. Run by hand, the reason is the answer (an id that is not a session, a journal it
87
+ // could not read), so it is printed and the exit is non-zero.
88
+ if (hook)
89
+ return;
90
+ process.stderr.write(`reticle report: ${error instanceof Error ? error.message : String(error)}\n`);
91
+ process.exitCode = 1;
92
+ return;
93
+ }
94
+ if (0 === lines.length)
95
+ return;
96
+ process.stdout.write(hook ? `${JSON.stringify({ systemMessage: lines.join('\n') })}\n` : `${lines.join('\n')}\n`);
97
+ }
@@ -1,7 +1,7 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
- import { probeCli } from '@reticlehq/init';
4
+ import { probeCli, terminalWidth, wrapForTerminal } from '@reticlehq/init';
5
5
  import { installClosing, tutorialShownSteps } from './tutorial.js';
6
6
  import { setupMcp, knownClientLabels } from '../setup/setup-mcp.js';
7
7
  import { reportInstallSteps } from '../setup/setup-install.js';
@@ -22,7 +22,7 @@ export function handleSetupMcp(reportStep, standalone = true) {
22
22
  writeFileSync(p, contents);
23
23
  },
24
24
  homeDir: () => homedir(),
25
- print: (line) => process.stdout.write(`${line}\n`),
25
+ print: (line) => process.stdout.write(`${wrapForTerminal(line, terminalWidth())}\n`),
26
26
  reportStep,
27
27
  // `probeCli`, not a bare `execFileSync`: on Windows `claude` is a `.cmd` shim that cannot be
28
28
  // spawned without a shell, so the plain call threw ENOENT for every Windows user and the
@@ -46,16 +46,16 @@ export function handleSetupMcp(reportStep, standalone = true) {
46
46
  return;
47
47
  }
48
48
  for (const id of result.registered)
49
- io.print(` registered ${id}`);
49
+ io.print(` ✓ ${id}`);
50
50
  for (const id of result.alreadyThere)
51
- io.print(` already ${id}`);
51
+ io.print(` ✓ ${id} (already set up)`);
52
52
  // Said, not skipped. These are the clients whose format we will not rewrite, and they used to be
53
53
  // counted as registered: the line below is the difference between a user who adds four lines to
54
54
  // one file and a user who believes they are set up and has no tools.
55
55
  for (const client of result.manual) {
56
- io.print(` BY HAND ${client.id}: add the reticle entry to ${client.configPath}`);
56
+ io.print(` ⚠ ${client.id}: add the reticle entry to ${client.configPath} by hand`);
57
57
  if (client.docs !== undefined)
58
- io.print(` see ${client.docs}`);
58
+ io.print(` see ${client.docs}`);
59
59
  }
60
60
  /*
61
61
  * The OTHER agents, which `init` already reaches and this did not.
@@ -75,13 +75,13 @@ export function handleSetupMcp(reportStep, standalone = true) {
75
75
  });
76
76
  // Said on every run, attended or not: a registration only takes effect when the agent re-reads
77
77
  // its config, and an agent that was already open is the commonest reason "it did not work".
78
- io.print('');
79
- io.print('Restart your agent for it to pick up the new server.');
80
- // Only when this IS the whole command. Inside the installer the tour follows, and its own closing
81
- // already names `reticle init` — printing it here too put the same instruction twice, ten lines
82
- // apart, with the tour sandwiched between them.
83
- if (standalone)
78
+ // Only when this IS the whole command. Inside the installer the restart is the first line of the
79
+ // closing's Next list, where it belongs with the other things to do, not between the stages.
80
+ if (standalone) {
81
+ io.print('');
82
+ io.print('Restart your agent for it to pick up the new server.');
84
83
  io.print('Then: cd <your project> && reticle init');
84
+ }
85
85
  }
86
86
  /**
87
87
  * `reticle setup install` — the Node half of the one-line installer.
@@ -100,7 +100,7 @@ export function handleSetupInstall(opts, reportStep) {
100
100
  }
101
101
  // Installation and onboarding are one script, so the tour prints here and is not gated on
102
102
  // anything — see installClosing for the heuristic this replaced and why it reached nobody.
103
- process.stdout.write(`${installClosing()}\n`);
103
+ process.stdout.write(`${wrapForTerminal(installClosing(opts.mcp), terminalWidth())}\n`);
104
104
  // Shown, so the ONBOARD steps are a fact rather than a guess.
105
105
  for (const step of tutorialShownSteps())
106
106
  reportStep(step);
@@ -76,7 +76,7 @@ export declare function tutorialScript(audience: TutorialAudience): TutorialStep
76
76
  * Split from `renderTutorial` so the closing block is a value a caller can assert on, rather than a
77
77
  * string only findable by matching rendered prose.
78
78
  */
79
- export declare function tutorialNextSteps(audience: TutorialAudience): string;
79
+ export declare function tutorialNextSteps(audience: TutorialAudience, restartAgent?: boolean): string;
80
80
  /**
81
81
  * What the installer prints when it has finished.
82
82
  *
@@ -87,7 +87,7 @@ export declare function tutorialNextSteps(audience: TutorialAudience): string;
87
87
  * It ends with the tour's OWN closing, which already names `reticle init`. Adding a second "Next:"
88
88
  * under it would be the same instruction twice in ten lines.
89
89
  */
90
- export declare function installClosing(): string;
90
+ export declare function installClosing(registered?: boolean): string;
91
91
  export declare function renderTutorial(audience: TutorialAudience): string;
92
92
  export type DemoPlan = {
93
93
  ok: true;
@@ -91,7 +91,7 @@ export function tutorialScript(audience) {
91
91
  * Split from `renderTutorial` so the closing block is a value a caller can assert on, rather than a
92
92
  * string only findable by matching rendered prose.
93
93
  */
94
- export function tutorialNextSteps(audience) {
94
+ export function tutorialNextSteps(audience, restartAgent = false) {
95
95
  const lines = TutorialAudience.AGENT === audience
96
96
  ? [
97
97
  'Next:',
@@ -101,12 +101,15 @@ export function tutorialNextSteps(audience) {
101
101
  ]
102
102
  : [
103
103
  'Next:',
104
- ' cd <your project> && reticle init # wire Reticle into the app',
104
+ ...(restartAgent
105
+ ? [' restart your agent # it loads new tools only when it starts']
106
+ : []),
107
+ ' cd <your project> && reticle init # wire Reticle into the app',
105
108
  ' npm run dev # then load it in a browser',
106
109
  ' reticle status # confirms the app connected, or says why not',
107
110
  '',
108
- 'Then ask your agent to drive one real flow and report the verdict. That is the install',
109
- 'proving itself, and it is the agent’s job rather than a command you run.',
111
+ // One line: the terminal wraps it at the reader's width, not ours.
112
+ 'Then ask your agent to drive one real flow and report the verdict. That is the install proving itself, and it is the agent’s job rather than a command you run.',
110
113
  ];
111
114
  return lines.join('\n');
112
115
  }
@@ -120,14 +123,25 @@ export function tutorialNextSteps(audience) {
120
123
  * It ends with the tour's OWN closing, which already names `reticle init`. Adding a second "Next:"
121
124
  * under it would be the same instruction twice in ten lines.
122
125
  */
123
- export function installClosing() {
126
+ export function installClosing(registered = true) {
127
+ // One line a step. The reasons are for `reticle tutorial`; right after an install they turned a
128
+ // four-step idea into twenty-five lines of prose between the reader and the next command.
129
+ const steps = tutorialScript(TutorialAudience.HUMAN).map((step, index) => ` ${String(index + 1)}. ${INSTALL_SAYS[step.id] ?? step.say}`);
124
130
  return [
125
131
  '',
126
- 'Reticle is installed. Here is what it does, in four steps:',
132
+ '✓ Reticle is installed. How it works:',
133
+ ...steps,
127
134
  '',
128
- renderTutorial(TutorialAudience.HUMAN),
135
+ tutorialNextSteps(TutorialAudience.HUMAN, registered),
129
136
  ].join('\n');
130
137
  }
138
+ /**
139
+ * Tour steps reworded for a reader who has no app wired yet. The in-app tour's "That panel is
140
+ * Reticle" points at a panel on screen; straight after an install there is none to point at.
141
+ */
142
+ const INSTALL_SAYS = {
143
+ connect: 'Once `reticle init` wires your app, a Reticle panel appears in it: your proof the SDK is connected.',
144
+ };
131
145
  export function renderTutorial(audience) {
132
146
  const steps = tutorialScript(audience)
133
147
  .map((step, index) => {