@reticlehq/server 2.13.0 → 2.14.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 (451) hide show
  1. package/SKILL.md +8 -18
  2. package/bin/reticle.js +3 -0
  3. package/dist/bridge/auth-failure-reason.js +12 -1
  4. package/dist/bridge/bridge-security.d.ts +8 -0
  5. package/dist/bridge/bridge-security.js +6 -1
  6. package/dist/bridge/bridge.d.ts +3 -0
  7. package/dist/bridge/bridge.js +23 -1
  8. package/dist/bridge/bridge.test-harness.d.ts +10 -1
  9. package/dist/bridge/bridge.test-harness.js +7 -1
  10. package/dist/bridge/pairing-token.d.ts +17 -0
  11. package/dist/bridge/pairing-token.js +26 -0
  12. package/dist/bridge/token-auth.d.ts +7 -0
  13. package/dist/bridge/token-auth.js +7 -1
  14. package/dist/capsule/capsule-store.d.ts +4 -4
  15. package/dist/capsule/capsule.d.ts +1 -1
  16. package/dist/capsule/capsule.js +3 -3
  17. package/dist/capsule/causal-summary.d.ts +21 -1
  18. package/dist/capsule/causal-summary.js +8 -6
  19. package/dist/capsule/divergence.d.ts +1 -1
  20. package/dist/capsule/divergence.js +26 -10
  21. package/dist/chromium-launch-options.d.ts +2 -1
  22. package/dist/cli/adhoc-verdict.d.ts +58 -0
  23. package/dist/cli/adhoc-verdict.js +115 -0
  24. package/dist/cli/chromium-hint.d.ts +18 -4
  25. package/dist/cli/chromium-hint.js +54 -6
  26. package/dist/cli/cli-doctor.js +1 -2
  27. package/dist/cli/cli-flow-commands.d.ts +16 -2
  28. package/dist/cli/cli-flow-commands.js +28 -9
  29. package/dist/cli/cli-parse-feedback.js +1 -1
  30. package/dist/cli/cli-parse.d.ts +2 -1
  31. package/dist/cli/cli-parse.js +38 -0
  32. package/dist/cli/cli-port.d.ts +5 -13
  33. package/dist/cli/cli-port.js +5 -38
  34. package/dist/cli/cli-update-commands.js +4 -4
  35. package/dist/cli/cli-verify.d.ts +24 -7
  36. package/dist/cli/cli-verify.js +87 -13
  37. package/dist/cli/cloud-keystore.d.ts +2 -1
  38. package/dist/cli/cloud-login.d.ts +2 -1
  39. package/dist/cli/cloud-session.d.ts +2 -1
  40. package/dist/cli/cloud-session.js +1 -1
  41. package/dist/cli/daemon-start-options.d.ts +2 -1
  42. package/dist/cli/device-flow.d.ts +2 -2
  43. package/dist/cli/doctor-daemon-line.d.ts +2 -1
  44. package/dist/cli/doctor-project-line.d.ts +2 -1
  45. package/dist/cli/doctor-rows.d.ts +2 -1
  46. package/dist/cli/drive-attach.d.ts +4 -3
  47. package/dist/cli/gate-hook-message.d.ts +2 -1
  48. package/dist/cli/status-next-action.js +10 -11
  49. package/dist/cli.d.ts +1 -0
  50. package/dist/cli.js +21 -9
  51. package/dist/cloud/account-state.d.ts +20 -0
  52. package/dist/cloud/account-state.js +65 -0
  53. package/dist/cloud/cloud-sync.d.ts +46 -3
  54. package/dist/cloud/cloud-sync.js +116 -0
  55. package/dist/cloud/sync-cycle.d.ts +5 -4
  56. package/dist/cloud/sync-cycle.js +1 -1
  57. package/dist/cloud/sync-daemon.d.ts +3 -19
  58. package/dist/cloud/sync-daemon.js +2 -2
  59. package/dist/crawl/crawl-tools.js +1 -1
  60. package/dist/crawl/crawl.d.ts +5 -5
  61. package/dist/crawl/crawl.js +138 -4
  62. package/dist/daemon/daemon-resilience.d.ts +3 -2
  63. package/dist/daemon/daemon-resilience.js +43 -4
  64. package/dist/daemon/daemon-resolve.d.ts +0 -9
  65. package/dist/daemon/daemon-resolve.js +2 -2
  66. package/dist/daemon/dev-servers.d.ts +1 -1
  67. package/dist/daemon/dev-servers.js +1 -1
  68. package/dist/daemon/loopback-alias.d.ts +2 -1
  69. package/dist/daemon/startup-failure.d.ts +11 -0
  70. package/dist/daemon/startup-failure.js +46 -0
  71. package/dist/events/contradictions.d.ts +10 -16
  72. package/dist/events/contradictions.js +149 -17
  73. package/dist/events/declared.d.ts +13 -1
  74. package/dist/events/declared.js +59 -3
  75. package/dist/events/echo-mismatch.js +75 -6
  76. package/dist/events/lineage.d.ts +52 -0
  77. package/dist/events/lineage.js +122 -0
  78. package/dist/events/net-evidence.d.ts +21 -0
  79. package/dist/events/net-evidence.js +81 -0
  80. package/dist/events/predicate-console.d.ts +13 -0
  81. package/dist/events/predicate-console.js +138 -0
  82. package/dist/events/predicate-element.d.ts +13 -0
  83. package/dist/events/predicate-element.js +214 -0
  84. package/dist/events/predicate-eval.d.ts +15 -3
  85. package/dist/events/predicate-eval.js +128 -110
  86. package/dist/events/predicate-parse.js +34 -1
  87. package/dist/events/predicate-request-body.d.ts +50 -0
  88. package/dist/events/predicate-request-body.js +120 -0
  89. package/dist/events/predicate-route.d.ts +21 -1
  90. package/dist/events/predicate-route.js +149 -21
  91. package/dist/events/predicate-schema.d.ts +8 -1
  92. package/dist/events/predicate-schema.js +34 -0
  93. package/dist/events/predicate.d.ts +2 -0
  94. package/dist/events/predicate.js +52 -159
  95. package/dist/events/split-text-miss.d.ts +6 -4
  96. package/dist/events/split-text-miss.js +12 -5
  97. package/dist/flows/affected-tools.js +22 -9
  98. package/dist/flows/annotate.d.ts +2 -1
  99. package/dist/flows/annotate.js +19 -1
  100. package/dist/flows/coverage.d.ts +2 -2
  101. package/dist/flows/flake.d.ts +3 -3
  102. package/dist/flows/flow-expect-grammar.d.ts +33 -0
  103. package/dist/flows/flow-expect-grammar.js +155 -0
  104. package/dist/flows/flow-replay-run.d.ts +1 -1
  105. package/dist/flows/flow-replay-run.js +28 -15
  106. package/dist/flows/flow-replay.d.ts +10 -0
  107. package/dist/flows/flow-replay.js +57 -22
  108. package/dist/flows/flow-secret-field.d.ts +14 -0
  109. package/dist/flows/flow-secret-field.js +22 -0
  110. package/dist/flows/flow-step-runners.d.ts +1 -0
  111. package/dist/flows/flow-step-runners.js +91 -34
  112. package/dist/flows/flow-success.js +22 -0
  113. package/dist/flows/flow-tools.js +27 -8
  114. package/dist/flows/flow-upload-resolve.d.ts +23 -0
  115. package/dist/flows/flow-upload-resolve.js +46 -0
  116. package/dist/flows/flows.d.ts +15 -0
  117. package/dist/flows/flows.js +17 -14
  118. package/dist/flows/git-changed.d.ts +23 -4
  119. package/dist/flows/git-changed.js +32 -6
  120. package/dist/flows/heal-run.js +2 -2
  121. package/dist/flows/predicate-to-expect.d.ts +3 -2
  122. package/dist/flows/predicate-to-expect.js +11 -5
  123. package/dist/flows/recording-backtrack.d.ts +24 -0
  124. package/dist/flows/recording-backtrack.js +73 -0
  125. package/dist/flows/recordings.d.ts +6 -0
  126. package/dist/flows/replay-halt.d.ts +26 -0
  127. package/dist/flows/replay-halt.js +30 -0
  128. package/dist/flows/replay.d.ts +0 -8
  129. package/dist/flows/replay.js +15 -3
  130. package/dist/flows/suite-flakes.d.ts +2 -1
  131. package/dist/flows/verify-change-tools.js +16 -4
  132. package/dist/honesty/already-true.d.ts +14 -0
  133. package/dist/honesty/already-true.js +47 -4
  134. package/dist/honesty/blind-spots.d.ts +3 -1
  135. package/dist/honesty/blind-spots.js +24 -1
  136. package/dist/honesty/body-capture-remedy.d.ts +42 -0
  137. package/dist/honesty/body-capture-remedy.js +95 -0
  138. package/dist/honesty/feature-capture.d.ts +3 -2
  139. package/dist/honesty/feature-capture.js +1 -1
  140. package/dist/honesty/gap-ledger.d.ts +1 -1
  141. package/dist/honesty/gap-ledger.js +1 -1
  142. package/dist/honesty/instrumentation-gaps.d.ts +8 -1
  143. package/dist/honesty/instrumentation-gaps.js +12 -2
  144. package/dist/honesty/observability.d.ts +4 -3
  145. package/dist/honesty/tool-hit-rate.d.ts +3 -2
  146. package/dist/honesty/uncaptured-bodies.d.ts +3 -1
  147. package/dist/honesty/uncaptured-bodies.js +6 -2
  148. package/dist/honesty/unsettled.d.ts +9 -0
  149. package/dist/honesty/unsettled.js +45 -0
  150. package/dist/honesty/verified.d.ts +32 -1
  151. package/dist/honesty/verified.js +37 -10
  152. package/dist/impact/impact-store.d.ts +5 -14
  153. package/dist/impact/impact-store.js +49 -6
  154. package/dist/index.js +1 -1
  155. package/dist/input/network-detail.d.ts +26 -1
  156. package/dist/input/network-detail.js +44 -12
  157. package/dist/input/network-mock-tools.js +24 -17
  158. package/dist/input/real-input.js +1 -1
  159. package/dist/input/viewport-tools.js +25 -13
  160. package/dist/intent/inline-intent.d.ts +0 -10
  161. package/dist/intent/inline-intent.js +1 -1
  162. package/dist/intent/intent-shard-store.d.ts +3 -2
  163. package/dist/intent/intent-shard-store.js +1 -1
  164. package/dist/intent/intent-shard.d.ts +14 -14
  165. package/dist/intent/intent-shard.js +4 -4
  166. package/dist/intent/intent-store.d.ts +1 -1
  167. package/dist/intent/intent-store.js +1 -1
  168. package/dist/intent/intent-subject.d.ts +2 -1
  169. package/dist/intent/open-intents.d.ts +3 -2
  170. package/dist/license/license.d.ts +4 -4
  171. package/dist/license/license.js +1 -1
  172. package/dist/mcp/attach-memory.d.ts +2 -1
  173. package/dist/mcp/client-identity.d.ts +2 -1
  174. package/dist/mcp/mcp-outage.d.ts +1 -1
  175. package/dist/mcp/mcp-outage.js +1 -1
  176. package/dist/mcp/mcp-proxy.d.ts +3 -1
  177. package/dist/mcp/mcp-proxy.js +32 -7
  178. package/dist/mcp/mcp.js +3 -1
  179. package/dist/mcp/proxy-handshake.d.ts +2 -1
  180. package/dist/mcp/proxy-idle-exit.d.ts +45 -0
  181. package/dist/mcp/proxy-idle-exit.js +94 -0
  182. package/dist/mcp/server-instructions.d.ts +2 -1
  183. package/dist/memory/project-memory.d.ts +2 -3
  184. package/dist/memory/project-memory.js +1 -1
  185. package/dist/oracles/propose-consequences.js +5 -5
  186. package/dist/oracles/self-instrument.d.ts +2 -2
  187. package/dist/oracles/self-instrument.js +1 -1
  188. package/dist/platform.d.ts +3 -5
  189. package/dist/platform.js +3 -5
  190. package/dist/pool/browser-pool.d.ts +92 -0
  191. package/dist/pool/browser-pool.js +119 -5
  192. package/dist/pool/playwright-launcher.js +29 -2
  193. package/dist/pool/storage-seed.d.ts +23 -0
  194. package/dist/pool/storage-seed.js +198 -0
  195. package/dist/project/artifact-root.d.ts +2 -1
  196. package/dist/project/memory-fs.d.ts +2 -1
  197. package/dist/project/reticle-dir.js +1 -1
  198. package/dist/project/session-root.d.ts +8 -0
  199. package/dist/project/session-root.js +9 -2
  200. package/dist/runs/reticle-runner.d.ts +14 -1
  201. package/dist/runs/reticle-runner.js +39 -2
  202. package/dist/session/attachment-history.d.ts +2 -1
  203. package/dist/session/fake-session.d.ts +37 -0
  204. package/dist/session/fake-session.js +81 -0
  205. package/dist/session/lease-visibility.d.ts +2 -1
  206. package/dist/session/live-control-tools.js +6 -0
  207. package/dist/session/no-session-diagnosis.d.ts +17 -1
  208. package/dist/session/no-session-diagnosis.js +32 -6
  209. package/dist/session/no-session-next-action.d.ts +14 -0
  210. package/dist/session/no-session-next-action.js +18 -0
  211. package/dist/session/no-session-watch.js +46 -3
  212. package/dist/session/registered-projects.d.ts +54 -0
  213. package/dist/session/registered-projects.js +73 -0
  214. package/dist/session/review-store.d.ts +2 -1
  215. package/dist/session/session-health.d.ts +62 -1
  216. package/dist/session/session-health.js +82 -2
  217. package/dist/session/session-manager.d.ts +11 -1
  218. package/dist/session/session-manager.js +18 -3
  219. package/dist/session/session-replaced.d.ts +24 -0
  220. package/dist/session/session-replaced.js +29 -0
  221. package/dist/session/session-successor.js +20 -4
  222. package/dist/session/session.d.ts +13 -5
  223. package/dist/session/session.js +31 -23
  224. package/dist/setup/agent-configs.d.ts +3 -2
  225. package/dist/setup/agent-writer.d.ts +3 -2
  226. package/dist/setup/approval-migration.d.ts +2 -1
  227. package/dist/setup/approval-migration.js +1 -1
  228. package/dist/setup/auto-approve.d.ts +11 -19
  229. package/dist/setup/auto-approve.js +15 -12
  230. package/dist/{init → setup}/confirm.js +1 -1
  231. package/dist/setup/desktop-shape.d.ts +3 -2
  232. package/dist/setup/dev-server-wait.d.ts +8 -0
  233. package/dist/setup/dev-server-wait.js +3 -1
  234. package/dist/setup/drive-agent.d.ts +2 -3
  235. package/dist/setup/drive-agent.js +1 -1
  236. package/dist/setup/drive-plan.d.ts +3 -2
  237. package/dist/setup/ensure-daemon.d.ts +2 -1
  238. package/dist/setup/existing-app.d.ts +12 -0
  239. package/dist/setup/existing-app.js +13 -0
  240. package/dist/setup/init-host.d.ts +11 -0
  241. package/dist/setup/init-host.js +26 -0
  242. package/dist/setup/init-runtime.d.ts +4 -10
  243. package/dist/setup/init-runtime.js +23 -16
  244. package/dist/setup/license-key.d.ts +2 -1
  245. package/dist/setup/listeners.d.ts +2 -1
  246. package/dist/setup/loopback-probe-urls.d.ts +18 -0
  247. package/dist/setup/loopback-probe-urls.js +52 -0
  248. package/dist/setup/node-effects.d.ts +3 -0
  249. package/dist/setup/node-effects.js +26 -11
  250. package/dist/setup/page-probe.d.ts +5 -0
  251. package/dist/setup/relaunch.d.ts +2 -1
  252. package/dist/setup/run-setup.d.ts +5 -1
  253. package/dist/setup/run-setup.js +155 -48
  254. package/dist/setup/setup-command.d.ts +3 -2
  255. package/dist/setup/setup-command.js +8 -0
  256. package/dist/setup/setup-options.d.ts +5 -3
  257. package/dist/setup/setup-options.js +3 -2
  258. package/dist/setup/wait-progress.d.ts +28 -0
  259. package/dist/setup/wait-progress.js +43 -0
  260. package/dist/telemetry/app-instrumented.d.ts +2 -1
  261. package/dist/telemetry/app-instrumented.js +1 -1
  262. package/dist/telemetry/automation-hint.d.ts +1 -1
  263. package/dist/telemetry/automation-hint.js +1 -1
  264. package/dist/telemetry/cli-telemetry.js +1 -1
  265. package/dist/telemetry/connect-failure.d.ts +1 -1
  266. package/dist/telemetry/connect-failure.js +1 -1
  267. package/dist/telemetry/crash-cause.d.ts +3 -2
  268. package/dist/telemetry/crash-cause.js +1 -1
  269. package/dist/telemetry/daemon-telemetry.d.ts +3 -2
  270. package/dist/telemetry/daemon-telemetry.js +1 -1
  271. package/dist/telemetry/error-class.d.ts +3 -2
  272. package/dist/telemetry/error-class.js +1 -1
  273. package/dist/telemetry/feedback-cli.js +1 -1
  274. package/dist/telemetry/feedback-context.d.ts +3 -2
  275. package/dist/telemetry/feedback-context.js +5 -4
  276. package/dist/telemetry/feedback-local.d.ts +3 -2
  277. package/dist/telemetry/feedback.d.ts +4 -3
  278. package/dist/telemetry/feedback.js +1 -1
  279. package/dist/telemetry/git-facts.d.ts +2 -2
  280. package/dist/telemetry/git-facts.js +1 -1
  281. package/dist/telemetry/identify.d.ts +1 -1
  282. package/dist/telemetry/identify.js +1 -1
  283. package/dist/telemetry/init-telemetry.d.ts +2 -14
  284. package/dist/telemetry/init-telemetry.js +4 -13
  285. package/dist/telemetry/install-source.d.ts +7 -13
  286. package/dist/telemetry/install-source.js +7 -29
  287. package/dist/telemetry/license-activation.d.ts +3 -2
  288. package/dist/telemetry/license-activation.js +1 -1
  289. package/dist/telemetry/machine-snapshot.d.ts +1 -1
  290. package/dist/telemetry/mcp-connection.js +1 -1
  291. package/dist/telemetry/project-profile.d.ts +0 -14
  292. package/dist/telemetry/project-profile.js +1 -1
  293. package/dist/telemetry/proxy-telemetry.js +1 -1
  294. package/dist/telemetry/session-metrics.d.ts +1 -1
  295. package/dist/telemetry/session-metrics.js +1 -1
  296. package/dist/telemetry/telemetry.d.ts +1 -17
  297. package/dist/telemetry/telemetry.js +4 -4
  298. package/dist/telemetry/tool-refused.d.ts +1 -1
  299. package/dist/telemetry/tool-refused.js +1 -1
  300. package/dist/tools/act-observation.d.ts +3 -2
  301. package/dist/tools/act-preflight.js +8 -3
  302. package/dist/tools/act-target.d.ts +4 -0
  303. package/dist/tools/act-target.js +14 -5
  304. package/dist/tools/act-tools.d.ts +0 -2
  305. package/dist/tools/act-tools.js +45 -15
  306. package/dist/tools/assert-source.d.ts +30 -0
  307. package/dist/tools/assert-source.js +21 -0
  308. package/dist/tools/assert-verdict.d.ts +1 -1
  309. package/dist/tools/assert-verdict.js +14 -4
  310. package/dist/tools/browser-tools.js +28 -8
  311. package/dist/tools/complete-snapshot.d.ts +3 -2
  312. package/dist/tools/dynamic-tools.js +8 -0
  313. package/dist/tools/error-recovery.d.ts +10 -0
  314. package/dist/tools/error-recovery.js +23 -0
  315. package/dist/tools/feedback-tools.js +1 -1
  316. package/dist/tools/invoke-tool.js +2 -0
  317. package/dist/tools/lease-tools.d.ts +48 -20
  318. package/dist/tools/lease-tools.js +311 -76
  319. package/dist/tools/lineage-tools.d.ts +14 -0
  320. package/dist/tools/lineage-tools.js +64 -0
  321. package/dist/tools/merge-tools.js +1 -3
  322. package/dist/tools/navigate-arrival.d.ts +45 -1
  323. package/dist/tools/navigate-arrival.js +39 -6
  324. package/dist/tools/navigate-result.d.ts +8 -1
  325. package/dist/tools/navigate-result.js +14 -4
  326. package/dist/tools/numeric-bounds.d.ts +0 -11
  327. package/dist/tools/numeric-bounds.js +4 -4
  328. package/dist/tools/observe-tools.js +22 -26
  329. package/dist/tools/observed-nothing.d.ts +9 -0
  330. package/dist/tools/observed-nothing.js +2 -1
  331. package/dist/tools/read-tools.js +12 -17
  332. package/dist/tools/real-input-attempt.d.ts +14 -6
  333. package/dist/tools/real-input-attempt.js +75 -18
  334. package/dist/tools/reconcile-tools.js +2 -1
  335. package/dist/tools/reload-result.d.ts +6 -1
  336. package/dist/tools/reload-result.js +7 -2
  337. package/dist/tools/resolve-target.d.ts +7 -1
  338. package/dist/tools/resolve-target.js +72 -9
  339. package/dist/tools/settle-in-flight.d.ts +1 -1
  340. package/dist/tools/settle-in-flight.js +9 -2
  341. package/dist/tools/snapshot-delta.d.ts +24 -1
  342. package/dist/tools/snapshot-delta.js +66 -7
  343. package/dist/tools/tool-names.d.ts +1 -0
  344. package/dist/tools/tool-names.js +1 -0
  345. package/dist/tools/tool-surface.js +20 -2
  346. package/dist/tools/tools.js +120 -11
  347. package/dist/tools/verify-next-baton.d.ts +2 -1
  348. package/dist/update/sdk-sync.d.ts +1 -1
  349. package/dist/update/sdk-sync.js +1 -1
  350. package/dist/update/updater.js +1 -1
  351. package/dist/version/sdk-fix.d.ts +2 -1
  352. package/dist/version/version-skew.d.ts +0 -8
  353. package/dist/version/version-skew.js +1 -1
  354. package/docs/README.md +8 -6
  355. package/docs/actions.mdx +1 -1
  356. package/docs/agent-cheatsheet.md +4 -2
  357. package/docs/architecture.md +1 -1
  358. package/docs/cli/mcp.mdx +3 -1
  359. package/docs/cli/watch.mdx +1 -1
  360. package/docs/cli.mdx +1 -1
  361. package/docs/desktop.mdx +1 -1
  362. package/docs/docs.json +8 -3
  363. package/docs/faq.mdx +9 -0
  364. package/docs/first-drive.md +136 -0
  365. package/docs/frameworks.mdx +29 -7
  366. package/docs/gate-plan.md +2 -2
  367. package/docs/gates.md +19 -11
  368. package/docs/getting-started.md +7 -1
  369. package/docs/http-transport.md +164 -0
  370. package/docs/index.mdx +5 -3
  371. package/docs/install-manual.mdx +1 -1
  372. package/docs/packages/tauri.mdx +1 -1
  373. package/docs/packages.mdx +15 -3
  374. package/docs/platform-integration.md +1 -1
  375. package/docs/predicates.mdx +2 -0
  376. package/docs/system-map.md +2 -2
  377. package/docs/telemetry-contract.md +4 -4
  378. package/docs/telemetry-events.mdx +1 -1
  379. package/docs/telemetry.md +3 -3
  380. package/docs/tools-navigate.mdx +14 -6
  381. package/docs/usage.md +4 -4
  382. package/package.json +7 -4
  383. package/dist/init/agent-rules.d.ts +0 -116
  384. package/dist/init/agent-rules.js +0 -279
  385. package/dist/init/app-choice.d.ts +0 -20
  386. package/dist/init/app-choice.js +0 -25
  387. package/dist/init/astro-host.d.ts +0 -21
  388. package/dist/init/astro-host.js +0 -27
  389. package/dist/init/astro-patch.d.ts +0 -33
  390. package/dist/init/astro-patch.js +0 -300
  391. package/dist/init/capabilities.d.ts +0 -40
  392. package/dist/init/capabilities.js +0 -150
  393. package/dist/init/closing-hint.d.ts +0 -36
  394. package/dist/init/closing-hint.js +0 -120
  395. package/dist/init/connect-steps.d.ts +0 -2
  396. package/dist/init/connect-steps.js +0 -50
  397. package/dist/init/cra.d.ts +0 -79
  398. package/dist/init/cra.js +0 -178
  399. package/dist/init/csp-check.d.ts +0 -38
  400. package/dist/init/csp-check.js +0 -107
  401. package/dist/init/csp-doctor.d.ts +0 -32
  402. package/dist/init/csp-doctor.js +0 -54
  403. package/dist/init/desktop-doctor.d.ts +0 -41
  404. package/dist/init/desktop-doctor.js +0 -198
  405. package/dist/init/detect.d.ts +0 -96
  406. package/dist/init/detect.js +0 -209
  407. package/dist/init/dev-script.d.ts +0 -50
  408. package/dist/init/dev-script.js +0 -66
  409. package/dist/init/format-generated.d.ts +0 -18
  410. package/dist/init/format-generated.js +0 -39
  411. package/dist/init/install-hint.d.ts +0 -9
  412. package/dist/init/install-hint.js +0 -29
  413. package/dist/init/mcp-clients.d.ts +0 -89
  414. package/dist/init/mcp-clients.js +0 -299
  415. package/dist/init/mcp-registered.d.ts +0 -12
  416. package/dist/init/mcp-registered.js +0 -14
  417. package/dist/init/mcp.d.ts +0 -89
  418. package/dist/init/mcp.js +0 -129
  419. package/dist/init/next-patch.d.ts +0 -39
  420. package/dist/init/next-patch.js +0 -196
  421. package/dist/init/node-io.d.ts +0 -7
  422. package/dist/init/node-io.js +0 -117
  423. package/dist/init/non-js-project.d.ts +0 -27
  424. package/dist/init/non-js-project.js +0 -84
  425. package/dist/init/patch-kind.d.ts +0 -20
  426. package/dist/init/patch-kind.js +0 -10
  427. package/dist/init/plan-framework.d.ts +0 -64
  428. package/dist/init/plan-framework.js +0 -565
  429. package/dist/init/plan.d.ts +0 -242
  430. package/dist/init/plan.js +0 -703
  431. package/dist/init/preflight.d.ts +0 -28
  432. package/dist/init/preflight.js +0 -38
  433. package/dist/init/project-id.d.ts +0 -12
  434. package/dist/init/project-id.js +0 -25
  435. package/dist/init/refresh-rules.d.ts +0 -39
  436. package/dist/init/refresh-rules.js +0 -51
  437. package/dist/init/run.d.ts +0 -117
  438. package/dist/init/run.js +0 -806
  439. package/dist/init/slash-command.d.ts +0 -27
  440. package/dist/init/slash-command.js +0 -132
  441. package/dist/init/snippets.d.ts +0 -134
  442. package/dist/init/snippets.js +0 -572
  443. package/dist/init/vite-config.d.ts +0 -18
  444. package/dist/init/vite-config.js +0 -114
  445. package/dist/init/windows-quote.d.ts +0 -38
  446. package/dist/init/windows-quote.js +0 -70
  447. package/dist/init/workspace-apps.d.ts +0 -30
  448. package/dist/init/workspace-apps.js +0 -178
  449. package/dist/project/remember-project.d.ts +0 -24
  450. package/dist/project/remember-project.js +0 -40
  451. /package/dist/{init → setup}/confirm.d.ts +0 -0
@@ -10,12 +10,17 @@
10
10
  * — is unit-tested without launching a real browser.
11
11
  */
12
12
  import { type ReticleVerificationRun } from '@reticlehq/core';
13
+ import { type VerifyProgressListener } from '../runs/reticle-runner.js';
13
14
  /** The live capabilities runVerify needs — faked in tests so the logic runs without a browser. */
14
15
  export interface VerifyConnection {
15
16
  /** Resolve true once a browser session has connected, or false at timeout. */
16
17
  sessionReady(timeoutMs: number): Promise<boolean>;
17
18
  listFlows(): Promise<string[]>;
18
- verify(): Promise<ReticleVerificationRun>;
19
+ /**
20
+ * `onProgress` is narration for a run in flight — see `verify-progress.ts` in core. Optional at
21
+ * every layer: a connection that ignores it behaves exactly as it did before.
22
+ */
23
+ verify(onProgress?: VerifyProgressListener): Promise<ReticleVerificationRun>;
19
24
  close(): Promise<void>;
20
25
  }
21
26
  export interface VerifyPorts {
@@ -48,17 +53,29 @@ export declare function urlParts(url: string): {
48
53
  * worst answer available, and reached most often by the people with the fewest other options, since
49
54
  * the skill offers this command as the way to a verdict with no MCP at all.
50
55
  *
51
- * Three ways out, in the order they are worth trying, and the message says all three rather than
52
- * picking one: an agent that already has the tools should ask the daemon that is running instead of
53
- * starting a second one; somebody who wants this command specifically can stop the daemon; and a
54
- * second port works when the app is configured for it.
56
+ * The message says every way out rather than picking one, and it says FIRST that a busy port is the
57
+ * normal state rather than a fault — an install that worked leaves a daemon on it, so a reader who
58
+ * arrives here has done nothing wrong and should not go looking for what they broke (#689).
55
59
  *
56
- * Attaching to the running daemon the way `reticle drive` now does is the better answer and is not
57
- * this change — see cli/drive-attach.ts for the shape it should take.
60
+ * `reticle drive` leads, because it is the only option that works in the state most people are in
61
+ * when they reach this message: the client exposes no `reticle_*` tools (Codex, Cursor Cloud,
62
+ * Antigravity, a session whose MCP link dropped), which is exactly when the CLI is reached for. It
63
+ * ATTACHES to the running daemon rather than binding — see cli/drive-attach.ts — so there is nothing
64
+ * to stop, nothing to race, and it hands back a sessionId the daemon owns. The advice that used to
65
+ * lead, "ask the daemon through the tools", is the one thing that reader by construction cannot do.
66
+ *
67
+ * Stopping the daemon stays on the list and stays LAST of the working options, with the reason: the
68
+ * MCP proxy respawns one into the gap, so `stop` is a race the caller usually loses, and it kills
69
+ * the agent's own link on the way past.
70
+ *
71
+ * `verify` itself attaching, rather than needing the port at all, is the real fix and is #689's
72
+ * first bullet — not this change.
58
73
  */
59
74
  export declare function portBusyMessage(port: number): string;
60
75
  export declare function handleVerify(parsed: {
61
76
  url: string;
77
+ /** A parsed predicate for a flow-free, one-shot verdict against the running daemon. */
78
+ expect?: unknown;
62
79
  headless: boolean;
63
80
  timeoutMs?: number;
64
81
  storageState?: string;
@@ -10,13 +10,15 @@
10
10
  * — is unit-tested without launching a real browser.
11
11
  */
12
12
  import { join, basename } from 'node:path';
13
+ import { runAdhocVerdict } from './adhoc-verdict.js';
14
+ import { readOrCreatePairingTokenSync, defaultPairingTokenDir } from '../bridge/pairing-token.js';
13
15
  import { randomUUID } from 'node:crypto';
14
- import { RETICLE_DEFAULT_PORT, ReticleEnv, bridgeWsUrl, isLoopbackHostname, ReticleDir, RunAgentKind, RunFramework, RunProfile, RunTrigger, VerdictStatus, } from '@reticlehq/core';
16
+ import { RETICLE_DEFAULT_PORT, ReticleEnv, bridgeWsUrl, isLoopbackHostname, ReticleDir, RunAgentKind, RunFramework, RunProfile, RunTrigger, VerdictStatus, VerifyPhase, } from '@reticlehq/core';
15
17
  import { start } from '../index.js';
16
18
  import { probePresence, PortPresence } from '../daemon/port-presence.js';
17
19
  import { probeDaemon } from '../mcp/mcp-proxy.js';
18
20
  import { fetchStatus } from './cli-launch.js';
19
- import { cloudFetch, resolveCloudConfig, syncRunToCloud, SyncOutcome, } from '../cloud/cloud-sync.js';
21
+ import { cloudFetch, createProgressReporter, resolveCloudConfig, syncProgressToCloud, syncRunToCloud, SyncOutcome, } from '../cloud/cloud-sync.js';
20
22
  import { ReticleRunner } from '../runs/reticle-runner.js';
21
23
  import { createRunnerPort } from '../runs/runner-port.js';
22
24
  import { RunStore } from '../runs/run-store.js';
@@ -71,8 +73,44 @@ export async function runVerify(args, ports) {
71
73
  ports.exit(EXIT_FAIL);
72
74
  return;
73
75
  }
74
- const run = await conn.verify();
76
+ /*
77
+ * Narrate the run while it happens.
78
+ *
79
+ * Everything else the CLI reports is a finished artifact, which is the right shape for evidence
80
+ * and the wrong shape for the minutes a verification actually takes. Without this the dashboard
81
+ * has nothing to show between "linked" and "done", and a run that is working looks exactly like
82
+ * one that has died — the ambiguity somebody spent fifteen minutes inside.
83
+ *
84
+ * Opt-in and best-effort: no cloud credentials means nothing is buffered and nothing is sent.
85
+ */
86
+ /*
87
+ * A correlation id for the STREAM, minted before the run exists.
88
+ *
89
+ * The artifact's own `runId` is only assigned once verification finishes, and these events have
90
+ * to be attributable from the first one — so the stream gets its own id, and the dashboard keys
91
+ * live progress by it until the finished run replaces the whole picture.
92
+ */
93
+ const streamId = randomUUID();
94
+ const cloud = resolveCloudConfig(process.env);
95
+ const progress = createProgressReporter(streamId, cloud, cloudFetch);
96
+ let run;
97
+ try {
98
+ run = await conn.verify(progress.onProgress);
99
+ }
100
+ finally {
101
+ // Stopped before the last flush so the timer cannot fire mid-send, and flushed after it so the
102
+ // events from the final flow are not thrown away with the interval that would have sent them.
103
+ progress.stop();
104
+ await progress.flush().catch(() => undefined);
105
+ }
75
106
  await pushRunToCloud(run, ports); // best-effort; opt-in; never changes the verdict or exit code
107
+ /*
108
+ * The last event anybody watching is waiting for, sent after the artifact has actually landed —
109
+ * so "pushed" on a dashboard means the run is really there, not that we were about to try.
110
+ */
111
+ await syncProgressToCloud(streamId,
112
+ // The run's OWN injected timestamp — no wall clock is read in this path (rule 7).
113
+ [{ phase: VerifyPhase.PUSHED, at: run.createdAt }], cloud, cloudFetch).catch(() => undefined);
76
114
  ports.out(renderRunReport(run));
77
115
  ports.exit(run.verdict.status === VerdictStatus.PASS ? EXIT_PASS : EXIT_FAIL);
78
116
  }
@@ -179,12 +217,13 @@ async function openLiveConnection(opts) {
179
217
  return {
180
218
  sessionReady: (timeoutMs) => waitForSession(deps.sessions, timeoutMs, opts.now),
181
219
  listFlows: () => deps.flows.list(),
182
- verify: async () => {
220
+ verify: async (onProgress) => {
183
221
  const run = await runner.verify({
184
222
  project: { name: opts.projectName, framework: RunFramework.OTHER, previewUrl: opts.url },
185
223
  agent: { id: VERIFY_AGENT_ID, kind: RunAgentKind.OEM_PIPELINE },
186
224
  trigger: { kind: RunTrigger.OEM },
187
225
  profile: RunProfile.PROD_PREVIEW,
226
+ ...(onProgress === undefined ? {} : { onProgress }),
188
227
  });
189
228
  // Persist the artifact. `reticle gate` decides from RunStore.latest, so without this the
190
229
  // documented CI loop is broken end to end: `reticle verify` could pass and the gate would still
@@ -214,22 +253,38 @@ async function openLiveConnection(opts) {
214
253
  * worst answer available, and reached most often by the people with the fewest other options, since
215
254
  * the skill offers this command as the way to a verdict with no MCP at all.
216
255
  *
217
- * Three ways out, in the order they are worth trying, and the message says all three rather than
218
- * picking one: an agent that already has the tools should ask the daemon that is running instead of
219
- * starting a second one; somebody who wants this command specifically can stop the daemon; and a
220
- * second port works when the app is configured for it.
256
+ * The message says every way out rather than picking one, and it says FIRST that a busy port is the
257
+ * normal state rather than a fault — an install that worked leaves a daemon on it, so a reader who
258
+ * arrives here has done nothing wrong and should not go looking for what they broke (#689).
259
+ *
260
+ * `reticle drive` leads, because it is the only option that works in the state most people are in
261
+ * when they reach this message: the client exposes no `reticle_*` tools (Codex, Cursor Cloud,
262
+ * Antigravity, a session whose MCP link dropped), which is exactly when the CLI is reached for. It
263
+ * ATTACHES to the running daemon rather than binding — see cli/drive-attach.ts — so there is nothing
264
+ * to stop, nothing to race, and it hands back a sessionId the daemon owns. The advice that used to
265
+ * lead, "ask the daemon through the tools", is the one thing that reader by construction cannot do.
221
266
  *
222
- * Attaching to the running daemon the way `reticle drive` now does is the better answer and is not
223
- * this change — see cli/drive-attach.ts for the shape it should take.
267
+ * Stopping the daemon stays on the list and stays LAST of the working options, with the reason: the
268
+ * MCP proxy respawns one into the gap, so `stop` is a race the caller usually loses, and it kills
269
+ * the agent's own link on the way past.
270
+ *
271
+ * `verify` itself attaching, rather than needing the port at all, is the real fix and is #689's
272
+ * first bullet — not this change.
224
273
  */
225
274
  export function portBusyMessage(port) {
226
275
  return (`reticle verify needs port ${String(port)} — the port your app dials — and a Reticle daemon is ` +
227
276
  'already listening on it. It did not start a second one.\n\n' +
228
- ' • If you have the Reticle tools, ask the daemon that is already running instead: ' +
277
+ ' This is the NORMAL state after a working install, not a fault: the daemon your MCP client ' +
278
+ 'started owns that port.\n\n' +
279
+ ` • Drive the app through the daemon that is already there — this needs no tools and stops ` +
280
+ `nothing: npx @reticlehq/server drive <url>\n` +
281
+ ' • If your client HAS the Reticle tools, ask that daemon directly: ' +
229
282
  'reticle_run { tool: "reticle_verify", args: { action: "change", files: ["..."] } }\n' +
230
- ` • Or stop it and re-run: npx @reticlehq/server stop --port ${String(port)}\n` +
231
283
  ` • Or run both on another port, if your app is configured for it: RETICLE_PORT=<port> ` +
232
- 'npx @reticlehq/server verify <url>');
284
+ 'npx @reticlehq/server verify <url>\n' +
285
+ ` • Stopping the daemon (npx @reticlehq/server stop --port ${String(port)}) works, but it cuts ` +
286
+ "your agent's MCP link and the proxy usually respawns a daemon into the gap before verify can " +
287
+ 'bind — prefer one of the above.');
233
288
  }
234
289
  export function handleVerify(parsed) {
235
290
  const now = () => Date.now();
@@ -257,6 +312,25 @@ export function handleVerify(parsed) {
257
312
  const port = parsed.port ?? RETICLE_DEFAULT_PORT;
258
313
  if ((await probePresence(port, { tcpOpen: probeDaemon, status: fetchStatus })) ===
259
314
  PortPresence.DAEMON) {
315
+ // A daemon owning the port is the NORMAL state after a working install, and it used to be the
316
+ // end of the road: `verify` refused, the other verdict paths need saved flows a first-install
317
+ // project does not have, and stopping the daemon cuts the agent's own MCP link. An agent could
318
+ // hold a live, correctly-wired app and have no way to reach a verdict at all.
319
+ //
320
+ // With `--expect` there is now a way, and it does not need the port: ask the daemon that
321
+ // already owns it. See runAdhocVerdict.
322
+ if (parsed.expect !== undefined) {
323
+ const verdict = await runAdhocVerdict({
324
+ port,
325
+ ...(parsed.url !== undefined && '' !== parsed.url ? { url: parsed.url } : {}),
326
+ predicate: parsed.expect,
327
+ ...((t) => (t === undefined || 0 === t.length ? {} : { token: t }))(readOrCreatePairingTokenSync(defaultPairingTokenDir())),
328
+ });
329
+ for (const line of verdict.lines)
330
+ ports.out(line);
331
+ ports.exit(verdict.code);
332
+ return;
333
+ }
260
334
  ports.fail(portBusyMessage(port));
261
335
  ports.exit(1);
262
336
  return;
@@ -5,7 +5,7 @@
5
5
  * caller is expected to establish the tenant before trusting what comes back.
6
6
  */
7
7
  export declare const findCredential: (raw: unknown, projectId: string, url: string, orgId: string | undefined) => string | undefined;
8
- export interface CredentialWrite {
8
+ interface CredentialWrite {
9
9
  projectId: string;
10
10
  url: string;
11
11
  key: string;
@@ -35,3 +35,4 @@ export interface CredentialWrite {
35
35
  export declare const applyCredential: (store: Record<string, unknown>, write: CredentialWrite) => Record<string, unknown>;
36
36
  /** Where the store lives, given the reticle home directory. */
37
37
  export declare const credentialsPath: (homeDir: string, file: string) => string;
38
+ export {};
@@ -1,5 +1,5 @@
1
1
  /** Run `reticle link` with these arguments. Injected; see the note at the top of this file. */
2
- export type Linker = (argv: readonly string[]) => Promise<number>;
2
+ type Linker = (argv: readonly string[]) => Promise<number>;
3
3
  /**
4
4
  * `reticle login` — browser device flow by default; `--email <e>` (or a positional email) keeps the
5
5
  * headless two-step code path for CI/servers where opening a browser makes no sense.
@@ -15,3 +15,4 @@ export declare const cmdLogin: (argv: readonly string[], link: Linker) => Promis
15
15
  * one you did not mean.
16
16
  */
17
17
  export declare const cmdLogout: (argv?: readonly string[]) => Promise<number>;
18
+ export {};
@@ -8,7 +8,7 @@
8
8
  import { z } from 'zod';
9
9
  /** Where per-host sessions live under the reticle home directory. */
10
10
  export declare const SESSIONS_DIR = "sessions";
11
- export declare const SessionSchema: z.ZodObject<{
11
+ declare const SessionSchema: z.ZodObject<{
12
12
  url: z.ZodString;
13
13
  token: z.ZodString;
14
14
  orgName: z.ZodString;
@@ -46,3 +46,4 @@ export declare const readSessionFrom: (raw: Promise<unknown>) => Promise<Session
46
46
  * sessions existed keeps working and is not silently signed out by an upgrade.
47
47
  */
48
48
  export declare const resolveSessionFor: (url: string, perHost: Session | null, active: Session | null) => Session | null;
49
+ export {};
@@ -9,7 +9,7 @@ import { z } from 'zod';
9
9
  import { join } from 'node:path';
10
10
  /** Where per-host sessions live under the reticle home directory. */
11
11
  export const SESSIONS_DIR = 'sessions';
12
- export const SessionSchema = z.object({
12
+ const SessionSchema = z.object({
13
13
  url: z.string(),
14
14
  token: z.string(),
15
15
  orgName: z.string(),
@@ -12,7 +12,7 @@
12
12
  * replay, the spec runner), which exists whether or not a drive URL was named.
13
13
  */
14
14
  import type { StartOptions } from '../index.js';
15
- export type DaemonFlags = {
15
+ type DaemonFlags = {
16
16
  port: number;
17
17
  driveUrl?: string;
18
18
  headless: boolean;
@@ -30,3 +30,4 @@ export declare function daemonStartOptions(parsed: DaemonFlags): StartOptions;
30
30
  * idea: that headless belongs to the drive URL. It belongs to the pool, which exists either way.
31
31
  */
32
32
  export declare function daemonSpawnArgs(parsed: DaemonFlags): string[];
33
+ export {};
@@ -53,18 +53,18 @@ export declare const DevicePollSchema: z.ZodObject<{
53
53
  }>>;
54
54
  }, "strip", z.ZodTypeAny, {
55
55
  status: string;
56
+ token?: string | undefined;
56
57
  org?: {
57
58
  name: string;
58
59
  id?: string | undefined;
59
60
  } | undefined;
60
- token?: string | undefined;
61
61
  }, {
62
62
  status: string;
63
+ token?: string | undefined;
63
64
  org?: {
64
65
  name: string;
65
66
  id?: string | undefined;
66
67
  } | undefined;
67
- token?: string | undefined;
68
68
  }>;
69
69
  /**
70
70
  * Best-effort open the approval page in the default browser.
@@ -18,7 +18,7 @@ export interface DaemonIdentity {
18
18
  version?: string;
19
19
  contract?: string;
20
20
  }
21
- export interface DaemonLine {
21
+ interface DaemonLine {
22
22
  /** The `daemon ✓ …` line itself. */
23
23
  text: string;
24
24
  /** A skew sentence to print underneath, when this CLI and that daemon disagree. */
@@ -35,3 +35,4 @@ export declare function daemonLine(port: number, pid: number | null, peer: Daemo
35
35
  version: string;
36
36
  contract: string;
37
37
  }): DaemonLine;
38
+ export {};
@@ -10,7 +10,7 @@
10
10
  * Registering the MCP server and instrumenting the app are two different halves of the install, and
11
11
  * more than one route does the first without the second.
12
12
  */
13
- export interface ProjectWiringFacts {
13
+ interface ProjectWiringFacts {
14
14
  /** The id from `.reticle.json`, or undefined when there is no config here. */
15
15
  projectId: string | undefined;
16
16
  /** Has an app for this project ever connected on this port? Durable across daemon restarts. */
@@ -35,3 +35,4 @@ export interface ProjectWiringFacts {
35
35
  * other way — and `init` is the one action that can overwrite a setup that already works.
36
36
  */
37
37
  export declare function projectWiringLine(facts: ProjectWiringFacts): string;
38
+ export {};
@@ -47,7 +47,7 @@ export declare const DoctorRow: {
47
47
  readonly TRACING: "tracing";
48
48
  readonly DESKTOP: "desktop";
49
49
  };
50
- export type DoctorRowLabel = (typeof DoctorRow)[keyof typeof DoctorRow];
50
+ type DoctorRowLabel = (typeof DoctorRow)[keyof typeof DoctorRow];
51
51
  export declare const DOCTOR_ROW_LABELS: readonly DoctorRowLabel[];
52
52
  /**
53
53
  * Width the label column pads to.
@@ -60,3 +60,4 @@ export declare const DOCTOR_ROW_LABELS: readonly DoctorRowLabel[];
60
60
  export declare const LABEL_COLUMN: number;
61
61
  /** Build one `doctor` row: the standard indent, the label padded to the column, then `rest`. */
62
62
  export declare function doctorRow(label: DoctorRowLabel, rest: string): string;
63
+ export {};
@@ -42,7 +42,7 @@ export type DriveMode = (typeof DriveMode)[keyof typeof DriveMode];
42
42
  /** Pure. Exhaustive by switch, so a fourth presence has to decide what driving means for it. */
43
43
  export declare function decideDriveMode(presence: PortPresence): DriveMode;
44
44
  /** A driveable session the daemon opened on our behalf. */
45
- export interface DriveSession {
45
+ interface DriveSession {
46
46
  sessionId: string;
47
47
  /** Whether the tab's SDK actually registered — false ⇒ the app may not embed @reticlehq/core. */
48
48
  ready: boolean;
@@ -51,7 +51,7 @@ export interface DriveSession {
51
51
  /** The daemon's own diagnosis when the tab did not connect. */
52
52
  hint?: string;
53
53
  }
54
- export type DriveAttachResult = {
54
+ type DriveAttachResult = {
55
55
  ok: true;
56
56
  session: DriveSession;
57
57
  } | {
@@ -59,7 +59,7 @@ export type DriveAttachResult = {
59
59
  reason: string;
60
60
  };
61
61
  /** POST the drive request. Injected so the decision logic is tested without a socket. */
62
- export type DrivePost = (port: number, path: string, body: string) => Promise<{
62
+ type DrivePost = (port: number, path: string, body: string) => Promise<{
63
63
  status: number;
64
64
  body: string;
65
65
  }>;
@@ -110,3 +110,4 @@ export declare function driveForeignHolder(description: string): string;
110
110
  * and that sentence is "run it again", because the second run attaches instead of binding.
111
111
  */
112
112
  export declare function driveRaceLost(port: number, url: string): string;
113
+ export {};
@@ -12,7 +12,7 @@
12
12
  */
13
13
  /** Named so a reader of the hook output knows the flag is real and not a suggestion. */
14
14
  export declare const GATE_SKIP_ENV = "RETICLE_SKIP_GATE";
15
- export interface GateHookInput {
15
+ interface GateHookInput {
16
16
  /** Flows the changed files touch that have no passing artifact. */
17
17
  uncovered: readonly string[];
18
18
  /** Flows held back as flaky — reported, never counted as a pass. */
@@ -31,3 +31,4 @@ export interface GateHookInput {
31
31
  * interrupted.
32
32
  */
33
33
  export declare function gateHookMessage(exit: number, input: GateHookInput): string | undefined;
34
+ export {};
@@ -21,17 +21,6 @@ import { nextActionFor } from '../session/no-session-next-action.js';
21
21
  export function statusNextAction(facts) {
22
22
  if (facts.sessionCount > 0)
23
23
  return undefined;
24
- // Ahead of everything else, because it dominates: an app that was never wired cannot connect, and
25
- // no advice about dev servers or ports applies until it is. `previouslyConnected` overrides it —
26
- // an app CAN be wired by the Vite or Babel plugin with no `.reticle.json` at all, so a project
27
- // that has connected here before is wired whatever this file says, and sending it back to `init`
28
- // would be the same wrong answer in the other direction.
29
- if (!facts.initialized && !facts.previouslyConnected) {
30
- return ('no app has ever connected for this project, and there is no Reticle config here — so the ' +
31
- 'tools are registered and the app itself is not instrumented. Those are two different halves ' +
32
- 'of the install. Run `npx @reticlehq/server init` in the app directory, then start the dev ' +
33
- 'server and load the page.');
34
- }
35
24
  if (!facts.running) {
36
25
  // `running: false` reads as "Reticle is broken", and it usually means the opposite: the daemon is
37
26
  // started by an agent, on demand, and idles out when nobody is driving. A user who has not
@@ -43,6 +32,16 @@ export function statusNextAction(facts) {
43
32
  `Reticle tool, and it exits again when idle. ${wiring} Ask your agent to verify something, then ` +
44
33
  `run status again.`).replace(/\s+/g, ' ');
45
34
  }
35
+ // Only diagnose instrumentation after a live daemon makes that diagnosis possible. When the
36
+ // daemon is absent, claiming the app is unwired confuses missing evidence with evidence of a
37
+ // missing install. `previouslyConnected` overrides this branch because plugin-based wiring may
38
+ // connect without creating `.reticle.json`.
39
+ if (!facts.initialized && !facts.previouslyConnected) {
40
+ return ('no app has ever connected for this project, and there is no Reticle config here — so the ' +
41
+ 'tools are registered and the app itself is not instrumented. Those are two different halves ' +
42
+ 'of the install. Run `npx @reticlehq/server init` in the app directory, then start the dev ' +
43
+ 'server and load the page.');
44
+ }
46
45
  // The daemon is up and no page has connected. `nextActionFor` owns the ranking; this passes what
47
46
  // it has and lets that function say what is missing rather than guessing at it. It CAN see
48
47
  // listening ports now — the announced ones — which is what the empty list here used to cost.
package/dist/cli.d.ts CHANGED
@@ -3,3 +3,4 @@ import { parseCliArgs, CLI_USAGE } from './cli/cli-parse.js';
3
3
  export { parseCliArgs, CLI_USAGE };
4
4
  export type { CliResult } from './cli/cli-parse.js';
5
5
  export declare function handleStatus(port: number): Promise<void>;
6
+ export declare function main(): void;
package/dist/cli.js CHANGED
@@ -33,15 +33,16 @@ import { installDaemonResilience, recordExitReason, DaemonExitReason, } from './
33
33
  import { IdleShutdown, resolveIdleShutdownMs, resolveIdleCheckMs } from './daemon/idle-shutdown.js';
34
34
  import { DaemonHeartbeat, resolveHeartbeatMs } from './daemon/heartbeat.js';
35
35
  import { everServedToolCall } from './daemon/daemon-usefulness.js';
36
+ import { DAEMON_START_FAILED_EVENT, readDaemonStartupCause } from './daemon/startup-failure.js';
36
37
  import { fetchStatus, summarizeStatus, warnOnDaemonSkew, decideOpen, openInBrowser, openCommand, } from './cli/cli-launch.js';
37
38
  import { handleDrive } from './cli/drive-command.js';
38
39
  import { handleVerify } from './cli/cli-verify.js';
39
40
  import { runKill } from './cli/cli-kill.js';
40
41
  import { summarizeHunt } from './hunt/hunt-report.js';
41
- import { runInit } from './init/run.js';
42
+ import { runInit, buildNodeIo } from '@reticlehq/init';
42
43
  import { continueAfterInit } from './setup/init-runtime.js';
43
44
  import { handleDoctor } from './cli/cli-doctor.js';
44
- import { buildNodeIo } from './init/node-io.js';
45
+ import { serverInitHost } from './setup/init-host.js';
45
46
  import { describeLicense } from './license/license.js';
46
47
  import { isLikelyDevServerPort, devServerPortWarning, readProjectPort, readProjectId, } from './cli/cli-port.js';
47
48
  import { DAEMON_INNER_COMMAND, PORT_FLAG, parseCliArgs, CLI_USAGE } from './cli/cli-parse.js';
@@ -52,7 +53,7 @@ import { reportCliRun } from './telemetry/cli-telemetry.js';
52
53
  export { parseCliArgs, CLI_USAGE };
53
54
  function handleInit(parsed) {
54
55
  const cwd = process.cwd();
55
- const io = buildNodeIo(cwd);
56
+ const io = buildNodeIo(cwd, serverInitHost());
56
57
  const result = runInit({
57
58
  cwd,
58
59
  port: parsed.port,
@@ -60,6 +61,9 @@ function handleInit(parsed) {
60
61
  dryRun: parsed.dryRun,
61
62
  install: parsed.install,
62
63
  ...(parsed.app === undefined ? {} : { app: parsed.app }),
64
+ // Handed to init, not only to the drive phase below: the preflight names `--url` as the way
65
+ // past a missing package manager, and could not honour that while never being told about it.
66
+ ...(parsed.url === undefined ? {} : { url: parsed.url }),
63
67
  captureBodies: true === parsed.captureBodies,
64
68
  // The outcome is reported by confirmInstall instead, once it knows whether an app connected —
65
69
  // `init` writing files was never the same thing as `init` working (#269).
@@ -122,6 +126,7 @@ async function serveWithHonestExit(parsed) {
122
126
  return;
123
127
  }
124
128
  const daemonArgs = daemonSpawnArgs(parsed);
129
+ const startupStartedAt = Date.now();
125
130
  spawnDaemon(process.execPath, scriptPath, daemonArgs, parsed.port);
126
131
  // The child binds asynchronously and, when it cannot, exits 1 long after this process would have
127
132
  // reported success. Wait for it to ANSWER — `/status` responding is the only evidence a daemon
@@ -129,12 +134,14 @@ async function serveWithHonestExit(parsed) {
129
134
  const bound = await waitForPresence(parsed.port, PortPresence.DAEMON, SERVE_BIND_TIMEOUT_MS);
130
135
  if (!bound) {
131
136
  const settled = await probePresence(parsed.port, { tcpOpen: probeDaemon, status: fetchStatus });
137
+ const startupCause = readDaemonStartupCause(logPath(parsed.port), startupStartedAt);
132
138
  log('reticle_daemon_start_failed_parent', {
133
139
  port: parsed.port,
134
140
  presence: settled,
135
141
  reason: describePresence(settled, parsed.port),
136
142
  log: logPath(parsed.port),
137
143
  stateDir: stateDirProblem(reticleStateHome()) === undefined ? 'writable' : 'unwritable',
144
+ ...(startupCause === undefined ? {} : { cause: startupCause }),
138
145
  });
139
146
  // Name the CAUSE when we can see it. An unwritable state directory is a first-run failure mode
140
147
  // (locked-down home, read-only container mount, managed profile) that produced only "nothing is
@@ -142,8 +149,11 @@ async function serveWithHonestExit(parsed) {
142
149
  // cannot exist. Found by stress-testing 2.6.0 with `chmod 555 ~/.reticle`.
143
150
  const dirProblem = stateDirProblem(reticleStateHome());
144
151
  process.stderr.write(dirProblem === undefined
145
- ? `the daemon did not come up on :${String(parsed.port)} — ${describePresence(settled, parsed.port)}\n` +
146
- `see ${logPath(parsed.port)}\n`
152
+ ? startupCause === undefined
153
+ ? `the daemon did not come up on :${String(parsed.port)} — ${describePresence(settled, parsed.port)}\n` +
154
+ `see ${logPath(parsed.port)}\n`
155
+ : `the daemon did not come up on :${String(parsed.port)}.\n${startupCause}\n` +
156
+ `see ${logPath(parsed.port)}\n`
147
157
  : `the daemon did not come up on :${String(parsed.port)}.\n${dirProblem}\n`);
148
158
  process.exit(1);
149
159
  return;
@@ -367,8 +377,10 @@ async function handleAffected(files, since) {
367
377
  try {
368
378
  const fs = createNodeFileSystem();
369
379
  const reticleRoot = join(process.cwd(), ReticleDir.ROOT);
370
- const changed = await resolveChangedFiles(files, since);
371
- const result = affectedSavedFlows(await loadNamedFlows(fs, reticleRoot), changed);
380
+ // The CLI gate still degrades to "no changes" rather than crash CI over a bad ref — the
381
+ // original reasoning, now opted into explicitly instead of handed a clean-looking empty list.
382
+ const changed = (await resolveChangedFiles(files, since, process.cwd())).files;
383
+ const result = affectedSavedFlows(await loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd())), changed);
372
384
  log('reticle_affected', {
373
385
  changedFiles: changed,
374
386
  affected: result.affected,
@@ -644,12 +656,12 @@ function handleDaemonInner(parsed) {
644
656
  })
645
657
  .catch((error) => {
646
658
  const message = error instanceof Error ? error.message : String(error);
647
- log('reticle_daemon_start_failed', { error: message });
659
+ log(DAEMON_START_FAILED_EVENT, { error: message });
648
660
  removePid(parsed.port);
649
661
  process.exit(1);
650
662
  });
651
663
  }
652
- function main() {
664
+ export function main() {
653
665
  // Before anything reads process.env — notably the telemetry gate and the bridge's security
654
666
  // options — fold in a project-local `.env`. Values already in the environment always win.
655
667
  loadDotEnv(process.cwd());
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Is this machine signed in to a Reticle workspace?
3
+ *
4
+ * Asked by the HUD, and there are two sources that must not be reimplemented per caller: the session
5
+ * file `reticle login` writes to `~/.reticle/session.json`, and `RETICLE_CLOUD_KEY` for an agent that
6
+ * was handed a key instead. Everything that gates on login — the defect sync button, the prompt to sign
7
+ * in — resolves through here.
8
+ *
9
+ * Node-only by design: it reads the filesystem and the environment, so it lives in the server and
10
+ * only the SHAPE (`AccountState`) is in core, where the contract belongs.
11
+ */
12
+ import { type AccountState } from '@reticlehq/core';
13
+ /**
14
+ * Read the account state for this machine.
15
+ *
16
+ * The env key WINS over the session file: an agent handed a key is authenticating as that key,
17
+ * whatever a human left on disk, and reporting the human's org there would be a lie about who is
18
+ * acting.
19
+ */
20
+ export declare function readAccountState(home: string, env: NodeJS.ProcessEnv): AccountState;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Is this machine signed in to a Reticle workspace?
3
+ *
4
+ * Asked by the HUD, and there are two sources that must not be reimplemented per caller: the session
5
+ * file `reticle login` writes to `~/.reticle/session.json`, and `RETICLE_CLOUD_KEY` for an agent that
6
+ * was handed a key instead. Everything that gates on login — the defect sync button, the prompt to sign
7
+ * in — resolves through here.
8
+ *
9
+ * Node-only by design: it reads the filesystem and the environment, so it lives in the server and
10
+ * only the SHAPE (`AccountState`) is in core, where the contract belongs.
11
+ */
12
+ import { readFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+ import { ReticleDir } from '@reticlehq/core';
15
+ import { CloudEnv } from './cloud-sync.js';
16
+ import { SESSION_FILE } from '../cli/cloud-kit.js';
17
+ /** Signed OUT is the safe answer: it shows the way in, where a wrong "signed in" hides it. */
18
+ const SIGNED_OUT = { signedIn: false };
19
+ /**
20
+ * The fields we read off the session file, and nothing else.
21
+ *
22
+ * Narrowed by hand rather than parsed with the login schema on purpose: this function must be unable
23
+ * to carry a token even if the file grows one, and the surest way to guarantee that is never to bind
24
+ * it to a name here.
25
+ */
26
+ function fromSessionFile(home) {
27
+ try {
28
+ const raw = JSON.parse(readFileSync(join(home, ReticleDir.ROOT, SESSION_FILE), 'utf8'));
29
+ if ('object' !== typeof raw || null === raw)
30
+ return undefined;
31
+ const record = raw;
32
+ // A half-written or hand-edited file must not read as authenticated. `signedIn: true` is the
33
+ // claim that costs something when wrong, because it hides the way in.
34
+ if ('string' !== typeof record['token'] || 0 === record['token'].length)
35
+ return undefined;
36
+ const org = record['orgName'];
37
+ const host = record['url'];
38
+ return {
39
+ signedIn: true,
40
+ ...('string' === typeof org && org.length > 0 ? { org } : {}),
41
+ ...('string' === typeof host && host.length > 0 ? { host } : {}),
42
+ };
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ /**
49
+ * Read the account state for this machine.
50
+ *
51
+ * The env key WINS over the session file: an agent handed a key is authenticating as that key,
52
+ * whatever a human left on disk, and reporting the human's org there would be a lie about who is
53
+ * acting.
54
+ */
55
+ export function readAccountState(home, env) {
56
+ const key = env[CloudEnv.KEY];
57
+ const url = env[CloudEnv.URL];
58
+ if ('string' === typeof key && key.length > 0) {
59
+ return {
60
+ signedIn: true,
61
+ ...('string' === typeof url && url.length > 0 ? { host: url.replace(/\/+$/, '') } : {}),
62
+ };
63
+ }
64
+ return fromSessionFile(home) ?? SIGNED_OUT;
65
+ }