@reticlehq/server 3.7.0 → 3.8.1

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 (578) hide show
  1. package/SKILL.md +59 -68
  2. package/bin/reticle.js +9 -2
  3. package/dist/command/cli/adhoc-suite.js +1 -1
  4. package/dist/command/cli/adhoc-verdict.d.ts +12 -0
  5. package/dist/command/cli/adhoc-verdict.js +62 -4
  6. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  7. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  8. package/dist/command/cli/auth/cloud-session.d.ts +11 -19
  9. package/dist/command/cli/auth/cloud-session.js +23 -0
  10. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  11. package/dist/command/cli/cli-doctor.js +66 -21
  12. package/dist/command/cli/cli-flow-commands.js +53 -11
  13. package/dist/command/cli/cli-kill.d.ts +8 -0
  14. package/dist/command/cli/cli-kill.js +43 -3
  15. package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
  16. package/dist/command/cli/cli-parse-feedback.js +13 -1
  17. package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
  18. package/dist/command/cli/cli-parse-grammar.js +1 -6
  19. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  20. package/dist/command/cli/cli-parse-serve.js +124 -0
  21. package/dist/command/cli/cli-parse.d.ts +12 -11
  22. package/dist/command/cli/cli-parse.js +100 -123
  23. package/dist/command/cli/cli-usage.d.ts +0 -11
  24. package/dist/command/cli/cli-usage.js +43 -16
  25. package/dist/command/cli/cli-verify.d.ts +1 -1
  26. package/dist/command/cli/cli-verify.js +29 -14
  27. package/dist/command/cli/cloud-cli.js +27 -9
  28. package/dist/command/cli/cloud-kit.js +3 -3
  29. package/dist/command/cli/cloud-link.d.ts +1 -20
  30. package/dist/command/cli/cloud-link.js +2 -0
  31. package/dist/command/cli/cloud-login.d.ts +6 -2
  32. package/dist/command/cli/cloud-login.js +13 -41
  33. package/dist/command/cli/config/checkout.d.ts +10 -0
  34. package/dist/command/cli/config/checkout.js +78 -0
  35. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  36. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  37. package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
  38. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  39. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  40. package/dist/command/cli/drive/drive-attach.d.ts +5 -0
  41. package/dist/command/cli/drive/drive-attach.js +21 -1
  42. package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
  43. package/dist/command/cli/hook/codex-transcript.js +224 -0
  44. package/dist/command/cli/hook/episode-structure.d.ts +24 -0
  45. package/dist/command/cli/hook/episode-structure.js +138 -0
  46. package/dist/command/cli/hook/hook-command.d.ts +9 -0
  47. package/dist/command/cli/hook/hook-command.js +211 -0
  48. package/dist/command/cli/hook/hook-fast.d.ts +31 -0
  49. package/dist/command/cli/hook/hook-fast.js +136 -0
  50. package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
  51. package/dist/command/cli/hook/prompt-hook.js +199 -0
  52. package/dist/command/cli/hook/tool-hook.d.ts +21 -0
  53. package/dist/command/cli/hook/tool-hook.js +259 -0
  54. package/dist/command/cli/launch/cli-launch.d.ts +2 -0
  55. package/dist/command/cli/launch/cli-launch.js +22 -2
  56. package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
  57. package/dist/command/cli/mcp-command.d.ts +9 -0
  58. package/dist/command/cli/mcp-command.js +127 -41
  59. package/dist/command/cli/open-navigate.d.ts +43 -0
  60. package/dist/command/cli/open-navigate.js +85 -0
  61. package/dist/command/cli/ports/port-holder.d.ts +16 -4
  62. package/dist/command/cli/ports/port-holder.js +58 -12
  63. package/dist/command/cli/ports/resolve/cli-port.js +18 -2
  64. package/dist/command/cli/project-name.d.ts +1 -7
  65. package/dist/command/cli/project-name.js +1 -0
  66. package/dist/command/cli/report-command.d.ts +8 -2
  67. package/dist/command/cli/report-command.js +95 -18
  68. package/dist/command/cli/status-fields.d.ts +9 -2
  69. package/dist/command/cli/status-fields.js +148 -4
  70. package/dist/command/cli/try-command.d.ts +3 -4
  71. package/dist/command/cli/try-command.js +6 -11
  72. package/dist/command/cli/verify-results.d.ts +4 -1
  73. package/dist/command/cli/verify-results.js +3 -1
  74. package/dist/command/cli.d.ts +1 -7
  75. package/dist/command/cli.js +79 -160
  76. package/dist/command/daemon/daemon-resilience.d.ts +6 -1
  77. package/dist/command/daemon/daemon-resilience.js +31 -18
  78. package/dist/command/daemon/daemon.d.ts +11 -0
  79. package/dist/command/daemon/daemon.js +70 -2
  80. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
  81. package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
  82. package/dist/command/daemon/wake-decision.js +4 -2
  83. package/dist/command/daemon/win32-escape.d.ts +32 -0
  84. package/dist/command/daemon/win32-escape.js +119 -0
  85. package/dist/command/setup/agent-configs.d.ts +9 -0
  86. package/dist/command/setup/agent-configs.js +9 -0
  87. package/dist/command/setup/auto-approve.d.ts +10 -3
  88. package/dist/command/setup/auto-approve.js +51 -3
  89. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  90. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  91. package/dist/command/setup/bringup/ensure-daemon.js +4 -7
  92. package/dist/command/setup/init/init-host.js +6 -0
  93. package/dist/command/setup/init/init-port.js +5 -4
  94. package/dist/command/setup/init/init-runtime.js +7 -1
  95. package/dist/command/setup/node-effects.d.ts +8 -0
  96. package/dist/command/setup/node-effects.js +36 -4
  97. package/dist/command/setup/probe/dev-port.d.ts +26 -0
  98. package/dist/command/setup/probe/dev-port.js +117 -0
  99. package/dist/command/setup/probe/page-probe.d.ts +1 -1
  100. package/dist/command/setup/probe/page-probe.js +11 -3
  101. package/dist/command/setup/remaining-steps.d.ts +0 -7
  102. package/dist/command/setup/remaining-steps.js +3 -2
  103. package/dist/command/setup/run-setup.d.ts +11 -0
  104. package/dist/command/setup/run-setup.js +33 -5
  105. package/dist/command/setup/setup-command.d.ts +2 -0
  106. package/dist/command/setup/setup-command.js +22 -4
  107. package/dist/command/update/updater.d.ts +1 -6
  108. package/dist/command/update/updater.js +4 -5
  109. package/dist/command/update/version-seen.d.ts +24 -0
  110. package/dist/command/update/version-seen.js +65 -0
  111. package/dist/command/version/peer-announce.d.ts +9 -1
  112. package/dist/command/version/peer-announce.js +25 -2
  113. package/dist/command/version/sdk-fix.d.ts +5 -6
  114. package/dist/command/version/sdk-fix.js +17 -32
  115. package/dist/command/version/version-skew.d.ts +16 -1
  116. package/dist/command/version/version-skew.js +84 -10
  117. package/dist/features/crawl/crawl-tools.js +2 -2
  118. package/dist/features/crawl/crawl.js +2 -0
  119. package/dist/features/exhaust/ledger.d.ts +15 -96
  120. package/dist/features/exhaust/ledger.js +3 -3
  121. package/dist/features/harness/drive-runs.d.ts +28 -4
  122. package/dist/features/harness/drive-runs.js +99 -7
  123. package/dist/features/harness/drivers.d.ts +1 -1
  124. package/dist/features/harness/drivers.js +1 -1
  125. package/dist/features/harness/harness.d.ts +5 -0
  126. package/dist/features/harness/harness.js +24 -12
  127. package/dist/features/harness/platform/platform-drives.d.ts +7 -1
  128. package/dist/features/harness/platform/platform-drives.js +12 -7
  129. package/dist/features/harness/platform/refusal.d.ts +1 -1
  130. package/dist/features/harness/platform/refusal.js +4 -4
  131. package/dist/features/harness/platform/remote-drive.js +70 -28
  132. package/dist/features/harness/platform/server-driver.js +22 -1
  133. package/dist/features/harness/platform-config.d.ts +1 -10
  134. package/dist/features/harness/platform-config.js +0 -20
  135. package/dist/features/license/license.d.ts +2 -14
  136. package/dist/features/visual/step-shots.d.ts +33 -1
  137. package/dist/features/visual/step-shots.js +155 -1
  138. package/dist/features/visual/visual-tools.js +12 -4
  139. package/dist/hooks/coding-agents.d.ts +6 -0
  140. package/dist/hooks/coding-agents.js +24 -3
  141. package/dist/hooks/episode-stamp.d.ts +32 -0
  142. package/dist/hooks/episode-stamp.js +61 -0
  143. package/dist/hooks/hook-commands.js +19 -9
  144. package/dist/index.d.ts +5 -1
  145. package/dist/index.js +66 -24
  146. package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
  147. package/dist/judgement/app-graph/journal-steps.js +92 -0
  148. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  149. package/dist/judgement/domain/domain-model.js +1 -10
  150. package/dist/judgement/domain/domain-tools.js +4 -2
  151. package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
  152. package/dist/judgement/runs/artifact/run-store.js +153 -28
  153. package/dist/judgement/runs/default-run-id.d.ts +3 -1
  154. package/dist/judgement/runs/default-run-id.js +15 -3
  155. package/dist/judgement/runs/drive-run.d.ts +3 -3
  156. package/dist/judgement/runs/drive-run.js +11 -7
  157. package/dist/judgement/runs/run-ledger.d.ts +21 -0
  158. package/dist/judgement/runs/run-ledger.js +143 -0
  159. package/dist/judgement/runs/runner-port.d.ts +1 -1
  160. package/dist/judgement/runs/runner-port.js +8 -2
  161. package/dist/judgement/runs/verification-sync.d.ts +4 -3
  162. package/dist/judgement/runs/verification-sync.js +27 -5
  163. package/dist/language/flows/affected-tools.js +2 -1
  164. package/dist/language/flows/annotate-notes/annotate.js +8 -3
  165. package/dist/language/flows/annotate-tools.js +1 -1
  166. package/dist/language/flows/change/affected.d.ts +8 -0
  167. package/dist/language/flows/change/affected.js +20 -7
  168. package/dist/language/flows/decision.js +19 -4
  169. package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
  170. package/dist/language/flows/fields/flow-secret-field.js +67 -5
  171. package/dist/language/flows/flow-anchor.d.ts +5 -0
  172. package/dist/language/flows/flow-anchor.js +4 -0
  173. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  174. package/dist/language/flows/flow-cross-step.js +9 -0
  175. package/dist/language/flows/flow-expect-grammar.js +15 -10
  176. package/dist/language/flows/flow-intent.js +6 -1
  177. package/dist/language/flows/flow-journey.d.ts +8 -0
  178. package/dist/language/flows/flow-journey.js +13 -0
  179. package/dist/language/flows/flow-lease.d.ts +27 -0
  180. package/dist/language/flows/flow-lease.js +59 -0
  181. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  182. package/dist/language/flows/flow-replay-run.js +111 -310
  183. package/dist/language/flows/flow-replay.js +21 -19
  184. package/dist/language/flows/flow-replayable.d.ts +38 -0
  185. package/dist/language/flows/flow-replayable.js +179 -0
  186. package/dist/language/flows/flow-start-path.d.ts +108 -0
  187. package/dist/language/flows/flow-start-path.js +313 -0
  188. package/dist/language/flows/flow-step-runners.d.ts +23 -2
  189. package/dist/language/flows/flow-step-runners.js +191 -32
  190. package/dist/language/flows/flow-store-for-session.d.ts +8 -1
  191. package/dist/language/flows/flow-store-for-session.js +6 -0
  192. package/dist/language/flows/flow-tools.d.ts +2 -23
  193. package/dist/language/flows/flow-tools.js +63 -113
  194. package/dist/language/flows/flows.d.ts +4 -6
  195. package/dist/language/flows/flows.js +90 -15
  196. package/dist/language/flows/heal-run.d.ts +10 -4
  197. package/dist/language/flows/heal-run.js +26 -9
  198. package/dist/language/flows/recording/flake.d.ts +3 -27
  199. package/dist/language/flows/recording/flake.js +1 -1
  200. package/dist/language/flows/recording/recording-backtrack.js +1 -4
  201. package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
  202. package/dist/language/flows/recording/tape/recordings.js +9 -3
  203. package/dist/language/flows/replay.d.ts +25 -5
  204. package/dist/language/flows/replay.js +83 -16
  205. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  206. package/dist/language/flows/suite/coverage.d.ts +9 -0
  207. package/dist/language/flows/suite/coverage.js +12 -1
  208. package/dist/language/flows/suite-selection.d.ts +25 -0
  209. package/dist/language/flows/suite-selection.js +41 -9
  210. package/dist/machine/git-tracks.d.ts +6 -0
  211. package/dist/machine/git-tracks.js +36 -0
  212. package/dist/memory/cloud/background-sync.d.ts +25 -0
  213. package/dist/memory/cloud/background-sync.js +79 -0
  214. package/dist/memory/cloud/cloud-config.d.ts +12 -1
  215. package/dist/memory/cloud/cloud-config.js +39 -13
  216. package/dist/memory/cloud/cloud-sync.d.ts +3 -24
  217. package/dist/memory/cloud/cloud-sync.js +5 -2
  218. package/dist/memory/cloud/harness-config.d.ts +0 -7
  219. package/dist/memory/cloud/memory-scope.d.ts +19 -0
  220. package/dist/memory/cloud/memory-scope.js +48 -0
  221. package/dist/memory/cloud/sync-answer.d.ts +43 -0
  222. package/dist/memory/cloud/sync-answer.js +42 -0
  223. package/dist/memory/cloud/sync-cycle.d.ts +40 -10
  224. package/dist/memory/cloud/sync-cycle.js +97 -144
  225. package/dist/memory/cloud/sync-daemon.d.ts +50 -3
  226. package/dist/memory/cloud/sync-daemon.js +473 -83
  227. package/dist/memory/cloud/sync-describe.d.ts +28 -0
  228. package/dist/memory/cloud/sync-describe.js +92 -0
  229. package/dist/memory/cloud/sync-disk.d.ts +9 -1
  230. package/dist/memory/cloud/sync-disk.js +137 -33
  231. package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
  232. package/dist/memory/cloud/sync-flow-versions.js +42 -0
  233. package/dist/memory/impact/impact-store.js +32 -15
  234. package/dist/memory/intent/intent-shard.d.ts +41 -266
  235. package/dist/memory/intent/intent-tools.js +20 -61
  236. package/dist/memory/intent/record-request.d.ts +27 -0
  237. package/dist/memory/intent/record-request.js +88 -0
  238. package/dist/memory/intent/settled-words.js +9 -1
  239. package/dist/memory/journal/drive-flow.d.ts +3 -0
  240. package/dist/memory/journal/drive-flow.js +11 -41
  241. package/dist/memory/journal/envelope-store.js +1 -1
  242. package/dist/memory/journal/envelope.d.ts +6 -154
  243. package/dist/memory/journal/episode-log.d.ts +107 -0
  244. package/dist/memory/journal/episode-log.js +302 -0
  245. package/dist/memory/journal/journal-recorder.d.ts +7 -0
  246. package/dist/memory/journal/journal-recorder.js +22 -9
  247. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  248. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  249. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
  250. package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
  251. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
  252. package/dist/memory/journal/self-observation.js +3 -1
  253. package/dist/memory/journal/session-end.js +23 -9
  254. package/dist/memory/journal/session-journal.js +39 -20
  255. package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
  256. package/dist/memory/project/artifact-root-resolver.js +68 -23
  257. package/dist/memory/project/artifact-root.d.ts +17 -3
  258. package/dist/memory/project/artifact-root.js +47 -9
  259. package/dist/memory/project/fs/fs-port.d.ts +5 -0
  260. package/dist/memory/project/fs/fs-port.js +13 -0
  261. package/dist/memory/project/learned-routes.d.ts +3 -4
  262. package/dist/memory/project/learned-routes.js +3 -11
  263. package/dist/memory/project/link-directory.js +5 -2
  264. package/dist/memory/project/root-claims.d.ts +3 -1
  265. package/dist/memory/project/root-claims.js +41 -7
  266. package/dist/memory/project/session-root.d.ts +1 -1
  267. package/dist/memory/project/session-root.js +1 -15
  268. package/dist/memory/project/sync-status.js +5 -6
  269. package/dist/memory/recall/memory-tools.js +2 -2
  270. package/dist/memory/recall/platform-memory.d.ts +3 -1
  271. package/dist/memory/recall/platform-memory.js +9 -1
  272. package/dist/memory/recall/project-memory.js +15 -19
  273. package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
  274. package/dist/portal/bridge/auth-failure-reason.js +19 -0
  275. package/dist/portal/bridge/bridge.d.ts +19 -4
  276. package/dist/portal/bridge/bridge.js +150 -177
  277. package/dist/portal/bridge/harness-request.d.ts +15 -0
  278. package/dist/portal/bridge/harness-request.js +19 -0
  279. package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
  280. package/dist/portal/bridge/origin/origin-follow.js +110 -0
  281. package/dist/portal/bridge/pairing-token.d.ts +6 -0
  282. package/dist/portal/bridge/pairing-token.js +47 -16
  283. package/dist/portal/bridge/protocol-skew.d.ts +27 -2
  284. package/dist/portal/bridge/protocol-skew.js +66 -2
  285. package/dist/portal/bridge/session-nonces.d.ts +46 -0
  286. package/dist/portal/bridge/session-nonces.js +72 -0
  287. package/dist/portal/input/viewport-tools.d.ts +31 -0
  288. package/dist/portal/input/viewport-tools.js +106 -15
  289. package/dist/portal/pool/bounded-close.d.ts +23 -0
  290. package/dist/portal/pool/bounded-close.js +38 -0
  291. package/dist/portal/pool/browser-pool.d.ts +44 -39
  292. package/dist/portal/pool/browser-pool.js +247 -95
  293. package/dist/portal/pool/context-permissions.d.ts +9 -1
  294. package/dist/portal/pool/context-permissions.js +26 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +37 -0
  296. package/dist/portal/pool/lease-emulation.js +29 -0
  297. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  298. package/dist/portal/pool/playwright-launcher.js +74 -7
  299. package/dist/portal/pool/pool-contract.d.ts +23 -1
  300. package/dist/portal/pool/pool-lease.d.ts +128 -0
  301. package/dist/portal/pool/pool-lease.js +49 -0
  302. package/dist/portal/pool/zero-install.d.ts +8 -1
  303. package/dist/portal/pool/zero-install.js +24 -2
  304. package/dist/portal/production/production-activation.d.ts +136 -0
  305. package/dist/portal/production/production-activation.js +173 -0
  306. package/dist/portal/production/production-drive.d.ts +52 -0
  307. package/dist/portal/production/production-drive.js +301 -0
  308. package/dist/portal/production/production-hello.d.ts +23 -0
  309. package/dist/portal/production/production-hello.js +23 -0
  310. package/dist/portal/realm/web-realm.js +42 -15
  311. package/dist/portal/session/control-envelope.d.ts +1 -1
  312. package/dist/portal/session/dev-server/served-document.d.ts +0 -5
  313. package/dist/portal/session/dev-server/served-document.js +6 -8
  314. package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
  315. package/dist/portal/session/first-run-wiring.d.ts +3 -36
  316. package/dist/portal/session/first-run-wiring.js +10 -103
  317. package/dist/portal/session/live-control-tools.js +61 -19
  318. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  319. package/dist/portal/session/no-session-next-action.js +40 -15
  320. package/dist/portal/session/no-session-watch.d.ts +7 -0
  321. package/dist/portal/session/no-session-watch.js +67 -23
  322. package/dist/portal/session/output-budget.d.ts +10 -0
  323. package/dist/portal/session/output-budget.js +16 -0
  324. package/dist/portal/session/presence/session-lease.d.ts +2 -0
  325. package/dist/portal/session/presence/session-lease.js +8 -0
  326. package/dist/portal/session/recorded-gaps.d.ts +15 -11
  327. package/dist/portal/session/recorded-gaps.js +39 -18
  328. package/dist/portal/session/serving-directory.d.ts +24 -2
  329. package/dist/portal/session/serving-directory.js +93 -5
  330. package/dist/portal/session/session-info.d.ts +26 -0
  331. package/dist/portal/session/session-info.js +20 -0
  332. package/dist/portal/session/session-manager.d.ts +35 -3
  333. package/dist/portal/session/session-manager.js +69 -14
  334. package/dist/portal/session/session-successor.js +1 -9
  335. package/dist/portal/session/session-tools.js +22 -4
  336. package/dist/portal/session/session.d.ts +10 -10
  337. package/dist/portal/session/session.js +37 -29
  338. package/dist/portal/session/zero-install-first-call.d.ts +7 -2
  339. package/dist/portal/session/zero-install-first-call.js +43 -20
  340. package/dist/start-wiring.d.ts +2 -2
  341. package/dist/start-wiring.js +17 -3
  342. package/dist/status-payload.d.ts +11 -1
  343. package/dist/status-payload.js +7 -1
  344. package/dist/surface/agent-presence-grace.d.ts +11 -0
  345. package/dist/surface/agent-presence-grace.js +34 -0
  346. package/dist/surface/http-server.d.ts +12 -1
  347. package/dist/surface/http-server.js +64 -15
  348. package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
  349. package/dist/surface/mcp/faults/mcp-outage.js +19 -1
  350. package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
  351. package/dist/surface/mcp/mcp-proxy.js +194 -267
  352. package/dist/surface/mcp/mcp.d.ts +20 -3
  353. package/dist/surface/mcp/mcp.js +88 -25
  354. package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
  355. package/dist/surface/mcp/proxy/drive-calls.js +114 -5
  356. package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
  357. package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
  358. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
  359. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
  360. package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
  361. package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
  362. package/dist/surface/mcp/server-instructions.js +35 -16
  363. package/dist/surface/mcp/shared-params.d.ts +8 -0
  364. package/dist/surface/mcp/shared-params.js +15 -1
  365. package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
  366. package/dist/surface/mcp/sse-frame-parser.js +18 -0
  367. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  368. package/dist/surface/mcp/surface-vocabulary.js +13 -0
  369. package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
  370. package/dist/surface/mcp/tool-catalog-cache.js +14 -4
  371. package/dist/surface/tools/account-tool.d.ts +4 -3
  372. package/dist/surface/tools/account-tool.js +20 -31
  373. package/dist/surface/tools/act/act-danger.d.ts +2 -0
  374. package/dist/surface/tools/act/act-danger.js +41 -14
  375. package/dist/surface/tools/act/act-observation.d.ts +11 -0
  376. package/dist/surface/tools/act/act-observation.js +33 -0
  377. package/dist/surface/tools/act/act-preflight.js +10 -3
  378. package/dist/surface/tools/act/act-sequence-retry.js +2 -1
  379. package/dist/surface/tools/act/act-target.js +19 -5
  380. package/dist/surface/tools/act/durable.js +1 -1
  381. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
  382. package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
  383. package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
  384. package/dist/surface/tools/act/unsettled-find.js +71 -0
  385. package/dist/surface/tools/act-sequence-tool.js +53 -24
  386. package/dist/surface/tools/act-tools.d.ts +2 -3
  387. package/dist/surface/tools/act-tools.js +49 -47
  388. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  389. package/dist/surface/tools/agent/for-the-agent.js +41 -3
  390. package/dist/surface/tools/assert/assert-grade.js +8 -3
  391. package/dist/surface/tools/assert/assert-verdict.js +4 -2
  392. package/dist/surface/tools/browser-tools.js +7 -4
  393. package/dist/surface/tools/chat-drives.js +50 -25
  394. package/dist/surface/tools/coverage-tools.js +1 -1
  395. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  396. package/dist/surface/tools/dynamic-tools.js +89 -34
  397. package/dist/surface/tools/empty-session-list.d.ts +18 -25
  398. package/dist/surface/tools/empty-session-list.js +67 -38
  399. package/dist/surface/tools/error-recovery.d.ts +17 -7
  400. package/dist/surface/tools/error-recovery.js +53 -20
  401. package/dist/surface/tools/explore-tools.d.ts +10 -0
  402. package/dist/surface/tools/explore-tools.js +72 -19
  403. package/dist/surface/tools/feedback-tools.js +23 -2
  404. package/dist/surface/tools/gap-novelty.d.ts +6 -0
  405. package/dist/surface/tools/gap-novelty.js +9 -0
  406. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  407. package/dist/surface/tools/harness-explore.d.ts +1 -1
  408. package/dist/surface/tools/harness-explore.js +6 -4
  409. package/dist/surface/tools/harness-gate.d.ts +43 -21
  410. package/dist/surface/tools/harness-gate.js +55 -81
  411. package/dist/surface/tools/harness-script.d.ts +2 -0
  412. package/dist/surface/tools/harness-script.js +11 -6
  413. package/dist/surface/tools/harness-toolset.js +3 -4
  414. package/dist/surface/tools/invoke-tool.d.ts +0 -8
  415. package/dist/surface/tools/invoke-tool.js +164 -178
  416. package/dist/surface/tools/lease-hint.d.ts +9 -0
  417. package/dist/surface/tools/lease-hint.js +22 -3
  418. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  419. package/dist/surface/tools/lease-readiness.d.ts +55 -0
  420. package/dist/surface/tools/lease-readiness.js +150 -2
  421. package/dist/surface/tools/lease-tools.d.ts +3 -75
  422. package/dist/surface/tools/lease-tools.js +124 -188
  423. package/dist/surface/tools/map-tools.d.ts +20 -0
  424. package/dist/surface/tools/map-tools.js +145 -0
  425. package/dist/surface/tools/merge-tools.js +11 -7
  426. package/dist/surface/tools/next-step.js +6 -3
  427. package/dist/surface/tools/observe-tools.js +46 -35
  428. package/dist/surface/tools/platform-moment.d.ts +3 -12
  429. package/dist/surface/tools/platform-moment.js +12 -24
  430. package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
  431. package/dist/surface/tools/read/complete-snapshot.js +13 -2
  432. package/dist/surface/tools/read/query-paginate.js +6 -0
  433. package/dist/surface/tools/read/query-shape.d.ts +9 -0
  434. package/dist/surface/tools/read/query-shape.js +15 -0
  435. package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
  436. package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
  437. package/dist/surface/tools/read-tools.js +5 -5
  438. package/dist/surface/tools/real-input-attempt.d.ts +11 -0
  439. package/dist/surface/tools/real-input-attempt.js +206 -38
  440. package/dist/surface/tools/reconcile-tools.js +21 -8
  441. package/dist/surface/tools/reticle-result.d.ts +3 -0
  442. package/dist/surface/tools/reticle-result.js +8 -1
  443. package/dist/surface/tools/run-report.d.ts +22 -0
  444. package/dist/surface/tools/run-report.js +141 -0
  445. package/dist/surface/tools/session-ports.d.ts +57 -0
  446. package/dist/surface/tools/session-ports.js +102 -0
  447. package/dist/surface/tools/tool-kit.d.ts +58 -4
  448. package/dist/surface/tools/tool-kit.js +140 -6
  449. package/dist/surface/tools/tool-surface.d.ts +2 -0
  450. package/dist/surface/tools/tool-surface.js +45 -0
  451. package/dist/surface/tools/tools.js +49 -87
  452. package/dist/telemetry/automation-hint.d.ts +5 -0
  453. package/dist/telemetry/automation-hint.js +7 -0
  454. package/dist/telemetry/cli-telemetry.d.ts +22 -0
  455. package/dist/telemetry/cli-telemetry.js +80 -11
  456. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  457. package/dist/telemetry/daemon-telemetry.js +9 -2
  458. package/dist/telemetry/feedback-cli.d.ts +1 -1
  459. package/dist/telemetry/feedback-cli.js +8 -3
  460. package/dist/telemetry/feedback.d.ts +1 -1
  461. package/dist/telemetry/feedback.js +51 -4
  462. package/dist/telemetry/harness-run.d.ts +3 -3
  463. package/dist/telemetry/harness-run.js +18 -7
  464. package/dist/telemetry/hud-events.d.ts +1 -1
  465. package/dist/telemetry/hud-metrics.d.ts +6 -3
  466. package/dist/telemetry/hud-metrics.js +20 -8
  467. package/dist/telemetry/install-source.js +1 -1
  468. package/dist/telemetry/mcp-connection.d.ts +1 -1
  469. package/dist/telemetry/mcp-connection.js +21 -2
  470. package/dist/telemetry/onboarding-firsts.d.ts +6 -1
  471. package/dist/telemetry/onboarding-firsts.js +41 -1
  472. package/dist/telemetry/proxy-telemetry.d.ts +42 -0
  473. package/dist/telemetry/proxy-telemetry.js +70 -1
  474. package/dist/telemetry/session-metrics.d.ts +1 -3
  475. package/dist/telemetry/session-metrics.js +16 -12
  476. package/dist/telemetry/telemetry.d.ts +9 -1
  477. package/dist/telemetry/telemetry.js +16 -1
  478. package/dist/telemetry/verification-of.d.ts +3 -1
  479. package/dist/telemetry/verification-of.js +7 -1
  480. package/dist/wire-journal.js +12 -2
  481. package/docs/README.md +4 -2
  482. package/docs/actions.mdx +7 -6
  483. package/docs/adapters.md +2 -1
  484. package/docs/agent-cheatsheet.md +19 -5
  485. package/docs/architecture.md +13 -10
  486. package/docs/autodrive.md +6 -5
  487. package/docs/benchmarks.md +2 -2
  488. package/docs/capabilities.mdx +1 -1
  489. package/docs/cli/affected.mdx +1 -1
  490. package/docs/cli/cloud.mdx +6 -6
  491. package/docs/cli/doctor.mdx +3 -1
  492. package/docs/cli/feedback.mdx +11 -7
  493. package/docs/cli/gate.mdx +1 -1
  494. package/docs/cli/help.mdx +1 -1
  495. package/docs/cli/init.mdx +20 -16
  496. package/docs/cli/mcp.mdx +5 -2
  497. package/docs/cli/open.mdx +5 -2
  498. package/docs/cli/report.mdx +1 -1
  499. package/docs/cli/restart.mdx +1 -1
  500. package/docs/cli/rollback.mdx +4 -4
  501. package/docs/cli/serve.mdx +7 -5
  502. package/docs/cli/setup.mdx +1 -1
  503. package/docs/cli/status.mdx +6 -2
  504. package/docs/cli/stop.mdx +3 -3
  505. package/docs/cli/telemetry.mdx +5 -1
  506. package/docs/cli/try.mdx +8 -8
  507. package/docs/cli/update.mdx +8 -5
  508. package/docs/cli/verify.mdx +12 -5
  509. package/docs/cli/version.mdx +1 -1
  510. package/docs/cli.mdx +10 -6
  511. package/docs/debugging.md +1 -1
  512. package/docs/deploy-checks.md +8 -6
  513. package/docs/desktop.mdx +14 -18
  514. package/docs/enterprise.md +6 -6
  515. package/docs/environment.mdx +5 -3
  516. package/docs/faq.mdx +9 -6
  517. package/docs/first-drive.md +19 -9
  518. package/docs/flows.md +3 -4
  519. package/docs/for-agents.md +1 -1
  520. package/docs/frameworks.mdx +34 -11
  521. package/docs/getting-started.md +46 -29
  522. package/docs/http-transport.md +2 -2
  523. package/docs/human-control.md +8 -8
  524. package/docs/index.mdx +2 -2
  525. package/docs/install-agentic.mdx +18 -19
  526. package/docs/install-manual.mdx +8 -4
  527. package/docs/integration-patterns.md +5 -5
  528. package/docs/multi-agent-testing.md +7 -5
  529. package/docs/packages/browser.mdx +34 -2
  530. package/docs/packages/core.mdx +2 -1
  531. package/docs/packages/electron.mdx +15 -3
  532. package/docs/packages/eslint-plugin.mdx +1 -1
  533. package/docs/packages/next.mdx +17 -5
  534. package/docs/packages/react.mdx +8 -1
  535. package/docs/packages/server.mdx +3 -3
  536. package/docs/packages/tauri.mdx +3 -3
  537. package/docs/packages/vite-plugin.mdx +1 -1
  538. package/docs/packages.mdx +19 -6
  539. package/docs/platform-integration.md +12 -4
  540. package/docs/predicates.mdx +18 -7
  541. package/docs/production-mode.md +108 -0
  542. package/docs/prompt-capture.md +99 -0
  543. package/docs/quickstart.mdx +14 -12
  544. package/docs/recipes.mdx +9 -8
  545. package/docs/required-checks.md +3 -2
  546. package/docs/skill-file.mdx +4 -3
  547. package/docs/skill-setup.md +2 -2
  548. package/docs/skill.md +62 -70
  549. package/docs/state-files.md +1 -0
  550. package/docs/state-management.mdx +11 -9
  551. package/docs/system-map.md +14 -13
  552. package/docs/telemetry.md +32 -24
  553. package/docs/testing.md +9 -5
  554. package/docs/tools/act-and-wait.mdx +17 -13
  555. package/docs/tools/act-sequence.mdx +40 -66
  556. package/docs/tools/act.mdx +7 -5
  557. package/docs/tools/assert.mdx +1 -1
  558. package/docs/tools/look.mdx +1 -1
  559. package/docs/tools/navigate.mdx +1 -1
  560. package/docs/tools/network.mdx +13 -11
  561. package/docs/tools/overview.mdx +3 -3
  562. package/docs/tools/query.mdx +3 -3
  563. package/docs/tools/session-and-feedback.mdx +9 -6
  564. package/docs/tools/sessions.mdx +7 -0
  565. package/docs/tools/snapshot.mdx +9 -7
  566. package/docs/tools/tools-and-run.mdx +11 -10
  567. package/docs/tools/verify.mdx +1 -1
  568. package/docs/troubleshooting.mdx +21 -9
  569. package/docs/usage.md +58 -43
  570. package/docs/use-cases.mdx +2 -2
  571. package/docs/vs-chrome-devtools-mcp.mdx +5 -5
  572. package/docs/vs-playwright-mcp.mdx +5 -4
  573. package/docs/what-is-recorded.md +12 -7
  574. package/docs/what-is-reticle.mdx +2 -2
  575. package/docs/why-reticle.mdx +1 -1
  576. package/package.json +9 -12
  577. package/dist/command/dev/stale-issue-guard.d.ts +0 -34
  578. package/dist/command/dev/stale-issue-guard.js +0 -69
@@ -8,34 +8,32 @@ import { openFailureNote, openLaunchFailureNote } from './cli/answers/open-note.
8
8
  import { realpathSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
10
  import { installCrashGuard } from './setup/setup-command.js';
11
- import { readDevServers } from './daemon/dev-servers.js';
12
- import { hasAnyAppConnectedBefore, hasProjectConnectedBefore, } from '../memory/recall/prior/connection-memory.js';
13
- import { attachStatusFields } from '../surface/mcp/attach-memory.js';
14
- import { splitBrainFields, withNextAction } from './cli/status-fields.js';
11
+ import { handleStatus } from './cli/status-fields.js';
12
+ export { handleStatus, reportStatus } from './cli/status-fields.js';
15
13
  import { reticleStateHome } from './daemon/daemon.js';
16
14
  import { handleMcp } from './cli/mcp-command.js';
17
15
  import { handleReport } from './cli/report-command.js';
18
16
  import { handleContext } from './cli/context-command.js';
17
+ import { handleHook } from './cli/hook/hook-command.js';
18
+ import { HOOK_COMMAND } from './cli/cli-parse.js';
19
19
  import { daemonProjectAt, readDaemonRegistry, resolveDaemonForProject, } from './daemon/daemon-resolve.js';
20
20
  import { pickDaemonPortToBind } from './daemon/binding/free-port.js';
21
21
  import { isSameOrAbove, portForInit, portFromEnv } from './setup/init/init-port.js';
22
22
  import { daemonStartOptions } from './cli/daemon-start-options.js';
23
23
  import { handleGate, loadNamedFlows, resolveChangedFiles } from './cli/cli-flow-commands.js';
24
- import { RETICLE_DEFAULT_PORT, ReticleDir, ReticleEnv, devServersForProject, } from '@reticlehq/core';
24
+ import { RETICLE_DEFAULT_PORT, ReticleDir, ReticleEnv } from '@reticlehq/core';
25
25
  import { loadDotEnv } from '../telemetry/dev-repo.js';
26
26
  import { licenseKeyFromEnvFiles } from '../features/license/license-env.js';
27
27
  import { LICENSE_KEY_ENV } from '../features/license/license.js';
28
28
  import { createNodeFileSystem } from '../memory/project/fs/fs-port.js';
29
- import { localLinkOf, workspaceAppLinks } from './cli/status/workspace-links.js';
30
29
  import { affectedSavedFlows } from '../language/flows/change/flow-sources.js';
31
- import { availableUpdate } from './update/update-nudge.js';
32
30
  import { handleUpdate, handleRollback } from './cli/cli-update-commands.js';
33
31
  import { headlessByDefault } from './cli/daemon-start-options.js';
34
32
  import { startDaemon } from '../index.js';
35
- import { accountStatusFields, cmdLink, connectInstalls, isCloudCommand, runCloudCommand, } from './cli/cloud-cli.js';
33
+ import { cmdLink, connectInstalls, isCloudCommand, runCloudCommand } from './cli/cloud-cli.js';
36
34
  import { SERVER_VERSION } from './version/identity/server-version.js';
37
35
  import { log } from '../log.js';
38
- import { readPid, isAlive, removePid, spawnDaemon, discoverDaemonPort, writeDaemonRegistry, } from './daemon/daemon.js';
36
+ import { isAlive, removePid, spawnDaemon, discoverDaemonPort, writeDaemonRegistry, } from './daemon/daemon.js';
39
37
  import { PortPresence, probePresence, presenceIsUsable, describePresence, } from './daemon/binding/port-presence.js';
40
38
  import { waitForDaemon, probeDaemon } from '../surface/mcp/mcp-proxy.js';
41
39
  import { installDaemonResilience, recordExitReason, DaemonExitReason, } from './daemon/daemon-resilience.js';
@@ -44,6 +42,7 @@ import { DaemonHeartbeat, resolveHeartbeatMs } from './daemon/lifetime/heartbeat
44
42
  import { everServedToolCall } from './daemon/lifetime/daemon-usefulness.js';
45
43
  import { DAEMON_START_FAILED_EVENT } from './daemon/lifetime/startup-failure.js';
46
44
  import { summarizeStatus, warnOnDaemonSkew, decideOpen, openInBrowser, openCommand, } from './cli/launch/cli-launch.js';
45
+ import { NAVIGATE_NO_SESSION_ID, navigateLeftTab, openCandidates } from './cli/open-navigate.js';
47
46
  import { fetchStatus } from './daemon/binding/daemon-status-probe.js';
48
47
  import { handleDrive } from './cli/drive/drive-command.js';
49
48
  import { handleVerify } from './cli/cli-verify.js';
@@ -79,10 +78,12 @@ export const MSG_CONNECTED_DEPS_PENDING = '⚠ Connected, but the dependency ins
79
78
  * else. `initUnfinished` is why init's setup did not finish, or undefined when it did.
80
79
  */
81
80
  export function connectExit(cloudCode, initUnfinished) {
82
- if (0 !== cloudCode)
81
+ if (0 !== cloudCode) {
83
82
  return { code: cloudCode };
84
- if (initUnfinished === undefined)
83
+ }
84
+ if (initUnfinished === undefined) {
85
85
  return { code: 0 };
86
+ }
86
87
  if (InitFailure.DEPENDENCY_INSTALL === initUnfinished) {
87
88
  return { code: 0, note: MSG_CONNECTED_DEPS_PENDING };
88
89
  }
@@ -98,8 +99,9 @@ async function handleInit(parsed) {
98
99
  // projects its connected pages announced.
99
100
  daemonProjects: async (p) => {
100
101
  const claimed = daemonProjectAt(p, reticleStateHome());
101
- if (claimed !== undefined && claimed.length > 0)
102
+ if (claimed !== undefined && claimed.length > 0) {
102
103
  return [claimed];
104
+ }
103
105
  const { sessions } = summarizeStatus(await fetchStatus(p));
104
106
  return [
105
107
  ...new Set(sessions.flatMap((s) => (s.projectId === undefined ? [] : [s.projectId]))),
@@ -125,6 +127,8 @@ async function handleInit(parsed) {
125
127
  ...(parsed.url === undefined ? {} : { url: parsed.url }),
126
128
  captureBodies: true === parsed.captureBodies,
127
129
  hooks: true === parsed.hooks,
130
+ newId: true === parsed.newId,
131
+ promptCapture: false !== parsed.promptCapture,
128
132
  // The outcome is reported by confirmInstall instead, once it knows whether an app connected —
129
133
  // `init` writing files was never the same thing as `init` working (#269).
130
134
  deferOutcome: true,
@@ -136,138 +140,6 @@ async function handleInit(parsed) {
136
140
  // `serve`, `stop` and `restart` live in `cli/lifecycle/daemon-lifecycle.ts`: one idea, and the
137
141
  // largest group this file could give up without splitting something that belongs together.
138
142
  import { handleServe, handleStop, handleRestart } from './cli/lifecycle/daemon-lifecycle.js';
139
- import { statusLines } from './cli/status/status-lines.js';
140
- /**
141
- * Report status to the terminal. `--json` writes one structured line to STDOUT so it can be piped
142
- * into `jq`; the human-readable block goes to stdout too. `log()` stays on stderr (the MCP
143
- * transport lives on stdout), so `--json` must not go through it.
144
- */
145
- export function reportStatus(fields, json) {
146
- if (json) {
147
- const line = JSON.stringify({
148
- t: new Date().toISOString(),
149
- event: 'reticle_status',
150
- ...fields,
151
- });
152
- process.stdout.write(`${line}\n`);
153
- return;
154
- }
155
- process.stdout.write(`${statusLines(fields).join('\n')}\n`);
156
- }
157
- export async function handleStatus(port, json = false) {
158
- // A broken session file must not cost the reader the rest of the status.
159
- const account = await accountStatusFields().catch(() => ({}));
160
- // At a workspace root that is no app of its own, each app and its link: "not linked" named none.
161
- const linked = account.linkedProject;
162
- if ('string' !== typeof linked && readProjectId(process.cwd()) === undefined)
163
- Object.assign(account, {
164
- workspaceApps: await workspaceAppLinks(process.cwd(), localLinkOf).catch(() => []),
165
- });
166
- const report = (fields) => reportStatus({ ...fields, ...account }, json);
167
- const pid = readPid(port);
168
- // Durable, so it survives the daemon idling out — which is the state `status` is most often run in.
169
- const projectId = readProjectId(process.cwd());
170
- const previouslyConnected = hasAnyAppConnectedBefore(reticleStateHome(), port, projectId);
171
- // The narrow twin. Every sentence that says "this project", and the decision about whether THIS
172
- // app is instrumented, needs the question the wide one cannot answer without a project id.
173
- const projectPreviouslyConnected = hasProjectConnectedBefore(reticleStateHome(), port, projectId);
174
- // Whether `init` has run HERE. Registering the MCP server does not wire the app, and more than one
175
- // path does the first without the second — so this is the commonest reason `status` has nothing to
176
- // report, and it was not among the facts this command could state.
177
- const initialized = projectId !== undefined;
178
- // The OTHER half of the install, and the half this command could not see. A host that registers
179
- // Reticle and never lists its tools looks exactly like an abandoned install from here — same idle
180
- // daemon, same zero sessions — and the user sees a tool that does nothing. See attach-memory.ts.
181
- const client = attachStatusFields(reticleStateHome(), port);
182
- // What the dev servers themselves said. The reason this command could previously only guess at
183
- // whether the app was running is that it had no way to see one; now the ones carrying Reticle
184
- // announce, and the advice below stops contradicting the terminal the reader is looking at.
185
- // Scoped to THIS project: the registry is machine-wide, and an unrelated app's dev server must
186
- // not make this project look like it is running.
187
- const devServerPorts = devServersForProject(readDevServers(reticleStateHome()), {
188
- projectId,
189
- root: process.cwd(),
190
- }).map((d) => d.port);
191
- // The failure where every individual check is green and the chain is broken: the agent's proxy and
192
- // the app resolved their ports independently and landed on two different daemons. Reported from
193
- // BOTH stances, because neither one can see it alone.
194
- const split = splitBrainFields(port, projectId);
195
- // Doctor and status must answer the same liveness question. A live pid only says that some
196
- // process exists; a Reticle daemon is running only when the shared port probe reaches /status.
197
- const presence = await probePresence(port, { tcpOpen: probeDaemon, status: fetchStatus });
198
- if (!presenceIsUsable(presence)) {
199
- report({
200
- port,
201
- running: false,
202
- presence,
203
- ...(presence === PortPresence.FOREIGN ? { reason: describePresence(presence, port) } : {}),
204
- // `init` promises this command says why the app has not connected. Without it the answer was
205
- // `running: false` and nothing else, which reads as "Reticle is broken" for what is usually
206
- // just a daemon that has not been asked to do anything yet.
207
- ...withNextAction({
208
- running: false,
209
- sessionCount: 0,
210
- previouslyConnected,
211
- projectPreviouslyConnected,
212
- initialized,
213
- devServerPorts,
214
- }),
215
- ...client,
216
- ...split,
217
- });
218
- return;
219
- }
220
- // The daemon answered the same probe doctor trusts — ask it for live sessions + health.
221
- const payload = await fetchStatus(port);
222
- // `status` is the second-most-run command and the one a HUMAN types. The update nudge otherwise
223
- // only rides a tool result, which the majority of daemons never produce — so the people most in
224
- // need of an upgrade were the ones with no path to hearing about it.
225
- const update = availableUpdate();
226
- const nudge = update === undefined ? {} : { updateAvailable: update };
227
- if (payload === undefined) {
228
- report({
229
- port,
230
- running: true,
231
- pid,
232
- ...nudge,
233
- ...withNextAction({
234
- running: true,
235
- sessionCount: 0,
236
- previouslyConnected,
237
- projectPreviouslyConnected,
238
- initialized,
239
- devServerPorts,
240
- }),
241
- ...client,
242
- ...split,
243
- });
244
- return;
245
- }
246
- const summary = summarizeStatus(payload);
247
- // Only when the daemon did NOT already explain itself. It has the whole diagnosis in-process and
248
- // puts it on the wire as `why`; printing a second, thinner opinion beside it risks two confident
249
- // answers pointing different ways, which is worse than one.
250
- const next = summary.why === undefined
251
- ? withNextAction({
252
- running: true,
253
- ...summary,
254
- previouslyConnected,
255
- projectPreviouslyConnected,
256
- initialized,
257
- devServerPorts,
258
- })
259
- : {};
260
- report({
261
- port,
262
- running: true,
263
- pid,
264
- ...summary,
265
- ...next,
266
- ...client,
267
- ...split,
268
- ...nudge,
269
- });
270
- }
271
143
  /**
272
144
  * Print the running package version (resolved once in server-version.ts), and nothing else.
273
145
  *
@@ -313,18 +185,21 @@ function ensureDaemon(port) {
313
185
  // upgrade does NOT take effect until that daemon dies, and nothing used to say so. Say it here,
314
186
  // where both versions are in hand, and keep attaching: killing another agent's daemon on a
315
187
  // version bump is worse than a loud warning.
316
- if (presenceIsUsable(presence))
188
+ if (presenceIsUsable(presence)) {
317
189
  return warnOnDaemonSkew(port);
190
+ }
318
191
  // Not free, not a daemon: a stranger holds the port. Spawning here is guaranteed to fail —
319
192
  // the child cannot bind — and `waitForDaemon` would then report READY anyway, because its
320
193
  // probe is the same bare TCP connect and the stranger accepts. That is the "serve reports
321
194
  // success for a daemon that never bound" shape. Refuse instead, with the sentence `doctor`
322
195
  // says.
323
- if (PortPresence.FREE !== presence)
196
+ if (PortPresence.FREE !== presence) {
324
197
  throw new Error(describePresence(presence, port));
198
+ }
325
199
  const scriptPath = process.argv[1];
326
- if (scriptPath === undefined)
200
+ if (scriptPath === undefined) {
327
201
  throw new Error('cannot locate the reticle daemon script');
202
+ }
328
203
  spawnDaemon(process.execPath, scriptPath, [DAEMON_INNER_COMMAND, PORT_FLAG, String(port)], port);
329
204
  return waitForDaemon(port);
330
205
  });
@@ -348,12 +223,15 @@ async function waitForNewSession(port, before) {
348
223
  while (Date.now() < deadline) {
349
224
  await new Promise((resolve) => setTimeout(resolve, 400));
350
225
  const { sessions } = summarizeStatus(await fetchStatus(port));
351
- if (sessions.length > before)
226
+ if (sessions.length > before) {
352
227
  return true;
228
+ }
353
229
  }
354
230
  return false;
355
231
  }
356
- function handleOpen(requestedPort, url) {
232
+ /** What to do about a same-origin tab `open` left where it was. */
233
+ const OPEN_LEFT_AS_IS_REMEDY = 'Pass --navigate to move it, drive it with reticle_navigate, or open the url in the browser yourself.';
234
+ function handleOpen(requestedPort, url, navigate = false) {
357
235
  // Our project's daemon first: `discoverDaemonPort` returns the LOWEST live daemon on the machine,
358
236
  // whoever it belongs to, so on a machine running two projects `reticle open` could drive the other
359
237
  // one's browser. It stays as the last resort for a caller with no project id, where any daemon is
@@ -368,7 +246,10 @@ function handleOpen(requestedPort, url) {
368
246
  .then(async (port) => {
369
247
  await ensureDaemon(port);
370
248
  const { sessions } = summarizeStatus(await fetchStatus(port));
371
- const decision = decideOpen(sessions, url);
249
+ // `--navigate` MOVES a tab, so it may only pick one of ours: on a daemon serving two projects,
250
+ // the origin match alone could hand it the other project's tab. Reuse and the note are read-only.
251
+ const candidates = openCandidates(sessions, navigate, myProject);
252
+ const decision = decideOpen(candidates, url);
372
253
  if ('need-url' === decision.action) {
373
254
  log('reticle_open', {
374
255
  port,
@@ -384,15 +265,33 @@ function handleOpen(requestedPort, url) {
384
265
  // A tab on the right origin, on the WRONG page. Kept (that is what stops a tab piling up per
385
266
  // run) but never reported as done: `reusing` here read as "your url is open" for a page nobody
386
267
  // had opened.
268
+ if ('left-as-is' === decision.action && navigate && decision.sessionId !== undefined) {
269
+ const moved = await navigateLeftTab({
270
+ port,
271
+ sessionId: decision.sessionId,
272
+ url: decision.requested,
273
+ });
274
+ log('reticle_open', { port, ...moved });
275
+ // A loop or CI step reads the exit code, so a failed move must not exit 0.
276
+ if (moved['error'] !== undefined) {
277
+ process.exit(1);
278
+ }
279
+ return;
280
+ }
387
281
  if ('left-as-is' === decision.action) {
282
+ // `--navigate` was asked for and could not be honoured: the tab never reported a session id
283
+ // to move. Suggesting `--navigate` back to someone who just passed it reads as being ignored.
284
+ const remedy = navigate ? NAVIGATE_NO_SESSION_ID : OPEN_LEFT_AS_IS_REMEDY;
388
285
  log('reticle_open', {
389
286
  port,
390
287
  reusing: decision.url,
391
288
  requested: decision.requested,
392
289
  note: `a tab is connected on this origin but sitting on ${decision.url} — it was LEFT THERE, ` +
393
- `not navigated to ${decision.requested}. Drive it with reticle_navigate, or open the url ` +
394
- 'in the browser yourself.',
290
+ `not navigated to ${decision.requested}. ${remedy}`,
395
291
  });
292
+ if (navigate) {
293
+ process.exit(1);
294
+ }
396
295
  return;
397
296
  }
398
297
  const launchError = await openInBrowser(decision.url);
@@ -500,6 +399,8 @@ function handleDaemonInner(parsed) {
500
399
  // argument, which would otherwise arrive as the reason.
501
400
  process.on('SIGTERM', () => shutdown(DaemonExitReason.SIGNAL));
502
401
  process.on('SIGINT', () => shutdown(DaemonExitReason.SIGNAL));
402
+ // `reticle stop` asks here first: on Windows a signal ends the process with no shutdown path.
403
+ server.onShutdownRequest?.(() => shutdown(DaemonExitReason.SIGNAL));
503
404
  // Self-shut-down when idle so a detached daemon (and any headless Chromium it launched) never
504
405
  // lingers on the user's machine after the editor closes. Reuses the same clean shutdown path.
505
406
  const attachedGraceEnv = process.env[ReticleEnv.IDLE_ATTACHED];
@@ -553,9 +454,22 @@ export function main() {
553
454
  // run then reported the licence as `missing`, which is indistinguishable from having none at all.
554
455
  // Only the key is taken; see license-env.ts for why nothing else is.
555
456
  const licenseKey = licenseKeyFromEnvFiles(process.cwd());
556
- if (licenseKey !== undefined)
457
+ if (licenseKey !== undefined) {
557
458
  process.env[LICENSE_KEY_ENV] = licenseKey;
459
+ }
558
460
  const argv = process.argv.slice(2);
461
+ // The agent's prompt hook, FIRST: before the version re-exec (it must not start a second CLI on
462
+ // every prompt) and before telemetry, which must never see that a prompt existed, let alone it.
463
+ // `--help` falls through to the parser, which prints what `hook` does.
464
+ if (HOOK_COMMAND === argv[0] && !argv.some((arg) => '--help' === arg || '-h' === arg)) {
465
+ // `tool` too: a hook that fails must never be reported to the agent as its tool failing.
466
+ const agentHook = ['prompt', 'prompt-write', 'tool', 'tool-write'].includes(argv[1] ?? '');
467
+ void handleHook(argv.slice(1))
468
+ .then((code) => process.exit(code))
469
+ // A hook that fails must still let the prompt through, so `prompt` exits 0 whatever happens.
470
+ .catch(() => process.exit(agentHook ? 0 : 1));
471
+ return;
472
+ }
559
473
  // Before anything reports or writes: a CLI a major away from the project's SDK makes every verdict
560
474
  // `version_skew`, and the unpinned `npx @reticlehq/server` every agent entry uses resolves the
561
475
  // LATEST major whatever the project installed. Hand the same arguments to the matching release and
@@ -639,8 +553,9 @@ export function main() {
639
553
  }
640
554
  }
641
555
  const exit = connectExit(await runCloudCommand(argv), unfinished);
642
- if (exit.note !== undefined)
556
+ if (exit.note !== undefined) {
643
557
  process.stderr.write(`${exit.note}\n`);
558
+ }
644
559
  return exit.code;
645
560
  })()
646
561
  .then((code) => process.exit(code))
@@ -665,8 +580,9 @@ export function main() {
665
580
  const portConflict = projectPort === undefined && envPort === undefined && !argv.includes(PORT_FLAG)
666
581
  ? workspacePortConflict(process.cwd())
667
582
  : undefined;
668
- if (portConflict !== undefined)
583
+ if (portConflict !== undefined) {
669
584
  process.stderr.write(`${portConflict}\n`);
585
+ }
670
586
  // Registry BEFORE the default, and after both explicit sources.
671
587
  //
672
588
  // This is the line that ends the split brain. Build plugins have always asked the registry which
@@ -708,8 +624,9 @@ export function main() {
708
624
  break;
709
625
  case 'kill':
710
626
  void runKill(parsed.port, parsed.force).then((freed) => {
711
- if (!freed)
627
+ if (!freed) {
712
628
  process.exit(1);
629
+ }
713
630
  });
714
631
  break;
715
632
  case 'restart':
@@ -725,7 +642,7 @@ export function main() {
725
642
  handleTelemetry(parsed.action);
726
643
  break;
727
644
  case 'feedback':
728
- void handleFeedback(parsed.text, parsed.rating, parsed.bug, parsed.feedbackKind, parsed.agent);
645
+ void handleFeedback(parsed.text, parsed.rating, parsed.bug, parsed.feedbackKind, parsed.agent, parsed.contact);
729
646
  break;
730
647
  case 'version':
731
648
  handleVersion();
@@ -751,7 +668,7 @@ export function main() {
751
668
  }, reportStepFromCli);
752
669
  break;
753
670
  case 'open':
754
- handleOpen(parsed.port, parsed.url);
671
+ handleOpen(parsed.port, parsed.url, parsed.navigate);
755
672
  break;
756
673
  case 'drive':
757
674
  handleDrive(parsed, readProjectId(process.cwd()));
@@ -793,10 +710,12 @@ export function main() {
793
710
  */
794
711
  function isEntryPoint() {
795
712
  const argv1 = process.argv[1];
796
- if (argv1 === undefined)
713
+ if (argv1 === undefined) {
797
714
  return false;
798
- if (import.meta.url === pathToFileURL(argv1).href)
715
+ }
716
+ if (import.meta.url === pathToFileURL(argv1).href) {
799
717
  return true;
718
+ }
800
719
  try {
801
720
  return import.meta.url === pathToFileURL(realpathSync(argv1)).href;
802
721
  }
@@ -82,5 +82,10 @@ export interface ProxyResilience {
82
82
  * `onCrash` is for reporting only — it must not end the process. `onGone` is the ONE exception, and
83
83
  * it is the subject of DISCONNECT_STORM below.
84
84
  */
85
- export declare function installProxyResilience(proc: ProcessLike, log: LogFn, onCrash?: (kind: CrashKind, cause: unknown) => void, onGone?: () => void): ProxyResilience;
85
+ export declare function installProxyResilience(proc: ProcessLike, log: LogFn, onCrash?: (kind: CrashKind, cause: unknown) => void, onGone?: () => void,
86
+ /**
87
+ * The pipes to the client (stdin and stdout). Only THEIR errors count toward DISCONNECT_STORM.
88
+ * Empty by default, so a test that wires a fake process never touches the real stdio.
89
+ */
90
+ clientPipes?: readonly ProcessLike[]): ProxyResilience;
86
91
  export {};
@@ -284,34 +284,47 @@ export function installDaemonResilience(proc, log, onFatal) {
284
284
  * `onCrash` is for reporting only — it must not end the process. `onGone` is the ONE exception, and
285
285
  * it is the subject of DISCONNECT_STORM below.
286
286
  */
287
- export function installProxyResilience(proc, log, onCrash = reportCrash, onGone = () => process.exit(0)) {
287
+ export function installProxyResilience(proc, log, onCrash = reportCrash, onGone = () => process.exit(0),
288
+ /**
289
+ * The pipes to the client (stdin and stdout). Only THEIR errors count toward DISCONNECT_STORM.
290
+ * Empty by default, so a test that wires a fake process never touches the real stdio.
291
+ */
292
+ clientPipes = []) {
288
293
  const expected = {
289
294
  disconnected: 'reticle_mcp_proxy_client_disconnected',
290
295
  unreachable: 'reticle_mcp_proxy_daemon_unreachable',
291
296
  };
292
297
  // "Absorb the disconnect and keep serving" is right for ONE disconnect and catastrophic for a
293
298
  // stream of them — see DISCONNECT_STORM. Counted since the last USABLE SESSION rather than since
294
- // this process started: a lifetime tally reaches the threshold on a working week, because the
295
- // classifier reads `ECONNRESET` as "the peer vanished" and on this leg the peer is the DAEMON,
296
- // which restarts routinely and is the thing the proxy exists to survive.
299
+ // this process started, and counted ONLY on the client pipes. An error that reaches the process
300
+ // comes from a socket with no listener, and in this process those are the sockets to the DAEMON,
301
+ // which restarts routinely and is the thing the proxy exists to survive. Counting them made the
302
+ // proxy leave a healthy daemon, and the agent lost its tools.
297
303
  let disconnects = 0;
298
304
  let gone = false;
299
- const absorb = (value) => {
300
- if (!absorbExpected(value, log, expected))
301
- return false;
302
- if (false === expectedCode(value)?.unreachable) {
303
- disconnects += 1;
304
- if (disconnects >= DISCONNECT_STORM && !gone) {
305
- gone = true;
306
- log('reticle_mcp_proxy_client_gone', {
307
- disconnects,
308
- note: 'the client end is gone for good, not between reconnects — exiting instead of retrying forever',
309
- });
310
- onGone();
311
- }
305
+ const absorb = (value) => absorbExpected(value, log, expected);
306
+ const onClientPipeError = (err) => {
307
+ if (!absorb(err)) {
308
+ log('reticle_mcp_proxy_client_pipe_error', { error: describe(err) });
309
+ onCrash(CrashKind.UNCAUGHT_EXCEPTION, err);
310
+ return;
311
+ }
312
+ if (true === expectedCode(err)?.unreachable) {
313
+ return;
314
+ }
315
+ disconnects += 1;
316
+ if (disconnects >= DISCONNECT_STORM && !gone) {
317
+ gone = true;
318
+ log('reticle_mcp_proxy_client_gone', {
319
+ disconnects,
320
+ note: 'the client end is gone for good, not between reconnects — exiting instead of retrying forever',
321
+ });
322
+ onGone();
312
323
  }
313
- return true;
314
324
  };
325
+ for (const pipe of clientPipes) {
326
+ pipe.on('error', onClientPipeError);
327
+ }
315
328
  const noteUsableSession = () => {
316
329
  // Not after `gone`: the process is already leaving, and a late frame must not look like a
317
330
  // reason to stay. Nothing brings the proxy back from `onGone` by design.
@@ -1,3 +1,4 @@
1
+ import { type EscapeRequest, type EscapeResult } from './win32-escape.js';
1
2
  export { MAX_DAEMON_LOG_BYTES, recoverOversizedLog } from './lifetime/log-cap.js';
2
3
  /** Env override for the whole state directory — see ReticleEnv.STATE_DIR. */
3
4
  export declare const STATE_DIR_ENV: "RETICLE_STATE_DIR";
@@ -72,8 +73,18 @@ export interface SpawnDaemonDeps {
72
73
  spawnChild(command: string, args: readonly string[], options: {
73
74
  detached: boolean;
74
75
  stdio: readonly ('ignore' | number)[];
76
+ env?: Record<string, string | undefined>;
75
77
  }): SpawnedChild;
76
78
  pidAlive(pid: number): boolean;
79
+ /** `process.platform`. Optional so a test that does not care runs the detached start. */
80
+ readonly platform?: string;
81
+ /** Windows only: start the daemon outside the Job Object of this process. See win32-escape.ts. */
82
+ readonly escapeJob?: (request: EscapeRequest) => EscapeResult;
83
+ /**
84
+ * A predecessor died without a clean stop; `ageMs` is how long it had run. Optional so a test that
85
+ * does not care reports nothing. The default sends `daemon_died_unclean`.
86
+ */
87
+ onUncleanDeath?(ageMs: number): void;
77
88
  }
78
89
  /**
79
90
  * Spawn the reticle daemon as a detached background process, redirecting output to the log file.
@@ -2,10 +2,12 @@ import { join } from 'node:path';
2
2
  import { homedir } from 'node:os';
3
3
  import { mkdirSync, readFileSync, writeFileSync, existsSync, unlinkSync, openSync, closeSync, readdirSync, statSync, renameSync, writeSync, } from 'node:fs';
4
4
  import { spawn } from 'node:child_process';
5
- import { daemonRegistryFileName, ReticleEnv } from '@reticlehq/core';
5
+ import { daemonRegistryFileName, DaemonSpawnMethod, ReticleEnv, } from '@reticlehq/core';
6
6
  import { log } from '../../log.js';
7
7
  import { uncleanPredecessor } from './lifetime/unclean-predecessor.js';
8
+ import { reportDaemonDiedUnclean } from '../../telemetry/proxy-telemetry.js';
8
9
  import { MAX_DAEMON_LOG_BYTES, pruneOldDaemonLogs } from './lifetime/log-cap.js';
10
+ import { escapeJobViaWmi } from './win32-escape.js';
9
11
  // Re-exported from their owner so callers outside this directory — the proxy log, the rotation
10
12
  // tests — keep reaching `daemon` rather than `lifetime`, which is a sink. See lifetime/log-cap.ts.
11
13
  export { MAX_DAEMON_LOG_BYTES, recoverOversizedLog } from './lifetime/log-cap.js';
@@ -196,10 +198,48 @@ function defaultSpawnDaemonDeps() {
196
198
  closeFile: closeSync,
197
199
  fileSize: (path) => (existsSync(path) ? statSync(path).size : 0),
198
200
  renameFile: renameSync,
199
- spawnChild: (command, args, options) => spawn(command, [...args], { detached: options.detached, stdio: [...options.stdio] }),
201
+ spawnChild: (command, args, options) => spawn(command, [...args], {
202
+ detached: options.detached,
203
+ stdio: [...options.stdio],
204
+ ...(options.env === undefined ? {} : { env: options.env }),
205
+ }),
200
206
  pidAlive: isAlive,
207
+ platform: process.platform,
208
+ escapeJob: escapeJobViaWmi,
209
+ onUncleanDeath: (ageMs) => void reportDaemonDiedUnclean(ageMs),
201
210
  };
202
211
  }
212
+ /**
213
+ * Report a dead predecessor, aged from its pidfile: the parent writes that file at spawn time.
214
+ * Read before the unlink, because after it nothing is left to age. A report must never stop a start.
215
+ */
216
+ function reportUncleanAge(pidFilePath, deps) {
217
+ try {
218
+ // The clock is read at this I/O boundary, the same as the log timestamps in this file.
219
+ deps.onUncleanDeath?.(Math.max(0, Date.now() - statSync(pidFilePath).mtimeMs));
220
+ }
221
+ catch {
222
+ // An unreadable pidfile has no age to report.
223
+ }
224
+ }
225
+ const WINDOWS = 'win32';
226
+ /** The WMI start must never stop a daemon start: a throw reads as "nothing launched". */
227
+ function tryEscapeJob(escape, request) {
228
+ try {
229
+ return escape(request);
230
+ }
231
+ catch {
232
+ return { launched: false };
233
+ }
234
+ }
235
+ function removeQuietly(path) {
236
+ try {
237
+ unlinkSync(path);
238
+ }
239
+ catch {
240
+ // racing another reclaimer — fine
241
+ }
242
+ }
203
243
  /**
204
244
  * Spawn the reticle daemon as a detached background process, redirecting output to the log file.
205
245
  * Writes the PID file from the parent before returning so callers can call isRunning
@@ -242,6 +282,9 @@ export function spawnDaemon(nodeExec, scriptPath, args, port, deps = defaultSpaw
242
282
  // a crashed daemon is reclaimed"), it just never said it out loud. Captured before the unlink,
243
283
  // because after it there is no trace left that the previous daemon died at all.
244
284
  orphanPid = uncleanPredecessor(existing, false, process.pid);
285
+ if (null !== orphanPid) {
286
+ reportUncleanAge(pidFilePath, deps);
287
+ }
245
288
  try {
246
289
  unlinkSync(pidFilePath);
247
290
  lockFd = deps.openFile(pidFilePath, 'wx');
@@ -289,11 +332,36 @@ export function spawnDaemon(nodeExec, scriptPath, args, port, deps = defaultSpaw
289
332
  // A log we cannot write is not a reason to refuse to start the daemon.
290
333
  }
291
334
  }
335
+ let method = DaemonSpawnMethod.DETACHED;
336
+ if (WINDOWS === deps.platform && deps.escapeJob !== undefined) {
337
+ const escaped = tryEscapeJob(deps.escapeJob, {
338
+ command: nodeExec,
339
+ args: [scriptPath, ...args],
340
+ cwd: process.cwd(),
341
+ env: { ...process.env, [ReticleEnv.SPAWN_METHOD]: DaemonSpawnMethod.WMI },
342
+ logPath: logFilePath,
343
+ specPath: join(deps.home, `daemon-${port}.spawn.json`),
344
+ });
345
+ if (escaped.launched) {
346
+ deps.closeFile(logFd);
347
+ // No pid in time: release the lock, so the pidfile never names a process that is not ours.
348
+ if (escaped.pid === undefined) {
349
+ deps.closeFile(lockFd);
350
+ removeQuietly(pidFilePath);
351
+ return true;
352
+ }
353
+ writeFileSync(lockFd, String(escaped.pid), 'utf8');
354
+ deps.closeFile(lockFd);
355
+ return true;
356
+ }
357
+ method = DaemonSpawnMethod.WMI_FALLBACK;
358
+ }
292
359
  let child;
293
360
  try {
294
361
  child = deps.spawnChild(nodeExec, [scriptPath, ...args], {
295
362
  detached: true,
296
363
  stdio: ['ignore', logFd, logFd],
364
+ env: { ...process.env, [ReticleEnv.SPAWN_METHOD]: method },
297
365
  });
298
366
  }
299
367
  catch {
@@ -27,6 +27,8 @@ export declare function everServedToolCall(): boolean;
27
27
  */
28
28
  export declare const SETUP_HOLD_MS = 60000;
29
29
  export declare function noteSetupHold(now: number): void;
30
+ /** Call on each attach and each detach of an agent. */
31
+ export declare function noteAgentPresence(now: number): void;
30
32
  /** Tests only. */
31
33
  export declare function resetDaemonUsefulness(): void;
32
34
  interface UsefulnessFacts {