@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
@@ -19,12 +19,19 @@ import { CONTRACT_FINGERPRINT } from '@reticlehq/core';
19
19
  import { CspBasis, diagnoseDesktop, diagnoseObservedWebCsp, diagnoseWebCsp, isDesktopProject, resolveWebCspFindings, webCspOptionsFor, } from '@reticlehq/init';
20
20
  import { RETICLE_CONFIG_BASENAME, diagnosePortMismatch, readProjectFramework, readProjectId, readProjectPort, } from './ports/resolve/cli-port.js';
21
21
  import { DoctorRow, doctorRow } from './doctor/doctor-rows.js';
22
+ import { ReticleDir } from '@reticlehq/core';
23
+ import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
24
+ import { BackgroundSyncState, backgroundSyncGate } from '../../memory/cloud/background-sync.js';
25
+ import { readCloudState } from '../../memory/cloud/sync-disk.js';
26
+ import { signedInTo } from './auth/cloud-session.js';
27
+ import { claudeCliHere, projectDirOf, promptCaptureRows } from './hook/hook-command.js';
22
28
  import { coverageLines } from './doctor/doctor-coverage-line.js';
23
29
  import { homedir } from 'node:os';
24
30
  import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
25
31
  import { describeUnsynced } from '../../memory/cloud/unsynced-roots.js';
26
32
  import { machineUnsyncedRoots } from '../../memory/project/sync-status.js';
27
33
  import { attachState, describeAttachState } from '../../surface/mcp/attach-memory.js';
34
+ import { agentLinkText } from './doctor/doctor-agent-link.js';
28
35
  import { findOccupiedSiblings, siblingListenerNote } from './ports/sibling-ports.js';
29
36
  import { daemonsServingProjectElsewhere, resolveDaemonForProject, splitBrainNote, wrongDaemonNote, } from '../daemon/daemon-resolve.js';
30
37
  import { isAlive } from '../daemon/daemon.js';
@@ -37,8 +44,9 @@ import { hasConnectedDocument, observeWebDocument, } from '../../portal/session/
37
44
  */
38
45
  /** Narrow the `/status` payload to the two fields the daemon line reads. */
39
46
  function asIdentity(payload) {
40
- if (typeof payload !== 'object' || null === payload)
47
+ if (typeof payload !== 'object' || null === payload) {
41
48
  return {};
49
+ }
42
50
  const record = payload;
43
51
  const pick = (key) => {
44
52
  const value = record[key];
@@ -93,8 +101,9 @@ export async function handleDoctor(port) {
93
101
  contract: CONTRACT_FINGERPRINT,
94
102
  });
95
103
  line(built.text);
96
- if (built.skew !== undefined)
104
+ if (built.skew !== undefined) {
97
105
  line(doctorRow(DoctorRow.VERSION, `✗ ${built.skew}`));
106
+ }
98
107
  // The same payload already carries whether anything has CONNECTED, and doctor was reading
99
108
  // `version` off it and dropping the rest. Without this the command is silent on the one step the
100
109
  // funnel stalls on: wired correctly, daemon up, and no page has ever dialled in.
@@ -122,18 +131,22 @@ export async function handleDoctor(port) {
122
131
  else {
123
132
  line(doctorRow(DoctorRow.DAEMON, `✗ not running on :${port} — your agent runs \`reticle mcp\` (or \`reticle serve\`)`));
124
133
  }
125
- if (sessions !== undefined)
134
+ if (sessions !== undefined) {
126
135
  line(sessions.text);
127
- for (const row of coverageLines(daemonStatus))
136
+ }
137
+ for (const row of coverageLines(daemonStatus)) {
128
138
  line(row);
139
+ }
129
140
  // Runs nothing will send, named by folder with the one command that sends them.
130
- for (const entry of await machineUnsyncedRoots(createNodeFileSystem(), homedir(), process.env))
141
+ for (const entry of await machineUnsyncedRoots(createNodeFileSystem(), homedir(), process.env)) {
131
142
  line(doctorRow(DoctorRow.UNSYNCED, `✗ ${describeUnsynced(entry, process.cwd())}`));
143
+ }
132
144
  line(doctorRow(DoctorRow.BRIDGE_PORT, `${port} (your app must dial THIS port, not your dev-server port)`));
133
145
  const projectPort = readProjectPort(process.cwd());
134
146
  const mismatch = diagnosePortMismatch(port, projectPort);
135
- if (mismatch !== undefined)
147
+ if (mismatch !== undefined) {
136
148
  line(doctorRow(DoctorRow.PORT_CHECK, `✗ ${mismatch}`));
149
+ }
137
150
  const projectId = readProjectId(process.cwd());
138
151
  // The hop between the agent and this daemon, stated as its own row rather than inferred from the
139
152
  // ones above it. `sessions` says the BROWSER reached the daemon; nothing said whether the AGENT
@@ -145,26 +158,23 @@ export async function handleDoctor(port) {
145
158
  // attached here" and sends the reader to re-register a server that is registered and running —
146
159
  // the confident wrong answer for a link that is not missing but misaimed.
147
160
  const split = splitBrainLine(port, projectId);
148
- line(doctorRow(DoctorRow.AGENT_LINK, split !== undefined
149
- ? `✗ ${split}`
150
- : attachAction === undefined
151
- ? // A RECORD, not a live check, and the row now says so. The attach memory is durable
152
- // and per-port: once a client has attached, enumerated and called, this stays green
153
- // forever. A registration pointing at a path that no longer exists produces a client
154
- // that cannot start at all, and this row reported the link healthy throughout —
155
- // measured, on this machine, for the two days after `packages/` was dissolved and
156
- // nothing updated ~/.claude.json. `doctor` is what a stuck human runs, so a row that
157
- // answers "did this ever work" while looking like "does this work" is the wrong
158
- // shape here even though every word of it is true.
159
- '✓ an MCP client attached here and called tools before (a record, not a live check)'
160
- : `✗ ${attachAction}`));
161
+ // The record alone cannot answer whether the link works NOW (#1710): when the port is held
162
+ // but `/status` does not answer, the record below would still read healthy or blame the
163
+ // client, while the daemon row above already names the one fix for the held port. So in that
164
+ // state the agent link row only points back at the daemon row instead of repeating the
165
+ // record or adding a second command. No probe runs here: `/status` and `/mcp/sse` share one
166
+ // HTTP server, so silence on `/status` already answers the MCP question, and an SSE connect
167
+ // would flip agent presence on a daemon with no agents attached.
168
+ const foreign = presence === PortPresence.FOREIGN;
169
+ line(doctorRow(DoctorRow.AGENT_LINK, agentLinkText({ split, attachAction, foreign })));
161
170
  // Remaining half of #261. The SDK dialling a port we are not on is invisible as a refused inbound,
162
171
  // but a listener on a well-known Reticle port is visible. Report the observation; do not conclude
163
172
  // it is the daemon this app wants — somebody else's daemon looks the same from here.
164
173
  const occupiedSiblings = await findOccupiedSiblings(port, probeDaemon);
165
174
  const siblingNote = siblingListenerNote(port, occupiedSiblings);
166
- if (siblingNote !== undefined)
175
+ if (siblingNote !== undefined) {
167
176
  line(doctorRow(DoctorRow.SIBLING, siblingNote));
177
+ }
168
178
  // The check this checklist was missing: is the APP wired, not just the tools. Everything above can
169
179
  // be green in a project that has never been through `init`, and that combination is precisely the
170
180
  // one `doctor` gets run to explain.
@@ -175,6 +185,10 @@ export async function handleDoctor(port) {
175
185
  // and telling somebody a file is missing while it sits in front of them is its own dead end.
176
186
  configPresent: existsSync(join(process.cwd(), RETICLE_CONFIG_BASENAME)),
177
187
  }));
188
+ // Are prompts reaching `.reticle/`, and is the work reaching the user's own workspace.
189
+ for (const row of await captureAndSyncLines(process.cwd(), process.env)) {
190
+ line(row);
191
+ }
178
192
  // Where to LOOK when something is wrong. The daemon has always written a structured log here and
179
193
  // nothing ever said so, so the first move in every investigation was reading source instead of
180
194
  // reading the log. `RETICLE_TRACE=1` turns the same stream into a per-stage trace — see
@@ -246,6 +260,37 @@ export async function handleDoctor(port) {
246
260
  line(doctorRow(DoctorRow.DESKTOP, '✓ desktop wiring looks right'));
247
261
  }
248
262
  const keychain = keychainNoteFor({ read: readProjectFile });
249
- if (keychain !== undefined)
263
+ if (keychain !== undefined) {
250
264
  line(doctorRow(DoctorRow.DESKTOP, `⚠ ${keychain}`));
265
+ }
266
+ }
267
+ /**
268
+ * Two rows: does each agent hand its prompts to Reticle, and does the daemon send this
269
+ * project's work in the background, and if not, why.
270
+ *
271
+ * Both answers come from the disk, the same files the hook and the daemon read, so `doctor` needs
272
+ * no daemon to give them. A sync the platform refused shows as the last error the cycle recorded.
273
+ */
274
+ async function captureAndSyncLines(cwd, env) {
275
+ const home = homedir();
276
+ const projectDir = projectDirOf(cwd);
277
+ const lines = promptCaptureRows(projectDir, env, claudeCliHere()).map((row) => doctorRow(DoctorRow.PROMPTS, row));
278
+ const reticleRoot = join(projectDir, ReticleDir.ROOT);
279
+ const cloud = await resolveProjectCloud(createNodeFileSystem(), reticleRoot, home, env);
280
+ const gate = backgroundSyncGate({
281
+ reticleRoot,
282
+ cloud,
283
+ env,
284
+ signedIn: (url) => signedInTo(join(home, ReticleDir.ROOT), url),
285
+ });
286
+ const state = readCloudState(reticleRoot);
287
+ const on = BackgroundSyncState.ON === gate.state;
288
+ const last = state.lastPushAt === undefined
289
+ ? 'no push yet'
290
+ : `last push ${new Date(state.lastPushAt).toISOString()}`;
291
+ lines.push(doctorRow(DoctorRow.SYNC, `${on ? '✓ on' : '✗ off'}: ${gate.why}; ${last}`));
292
+ if (state.lastError !== undefined) {
293
+ lines.push(doctorRow(DoctorRow.SYNC, `✗ last error: ${state.lastError}`));
294
+ }
295
+ return lines;
251
296
  }
@@ -10,13 +10,13 @@ import { knownRegression } from './known-regression.js';
10
10
  import { gateHookMessage, GATE_SKIP_ENV } from './answers/gate-hook-message.js';
11
11
  import { readProjectId } from './ports/resolve/cli-port.js';
12
12
  import { changedFilesSince } from '../../language/flows/change/git-changed.js';
13
- import { join } from 'node:path';
13
+ import { isAbsolute, join, sep } from 'node:path';
14
14
  import { ReticleDir } from '@reticlehq/core';
15
15
  import { FlowStore } from '../../language/flows/flows.js';
16
16
  import { RunStore } from '../../judgement/runs/artifact/run-store.js';
17
17
  import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
18
18
  import { affectedSavedFlows, toFlowSources, } from '../../language/flows/change/flow-sources.js';
19
- import { isInteractiveSource, unflowedFiles } from '../../language/flows/change/affected.js';
19
+ import { isInteractiveSource, sourceMatchesChange, unflowedFiles, } from '../../language/flows/change/affected.js';
20
20
  import { LedgerStore, regressions, staleChanged, unexecutedChanged, } from '../../features/exhaust/ledger.js';
21
21
  import { gateDecision, passingFlowNames } from '../../language/flows/change/gate.js';
22
22
  import { FlakeStore } from '../../language/flows/stores/flake-store.js';
@@ -68,18 +68,31 @@ export async function loadNamedFlows(fs, reticleRoot, projectId) {
68
68
  */
69
69
  /**
70
70
  * A changed file's text, or '' when it is gone. `git diff --name-only` answers from the repository
71
- * root while the gate may run in a package below it, so leading segments are dropped until the path
72
- * resolves from `cwd`.
71
+ * root while the gate may run in a package below it, so a leading segment is dropped only when it is
72
+ * the directory the gate runs in (or a chain of them ending at `cwd`). An absolute path is read as is.
73
+ * Never fall through to a shorter suffix that merely happens to exist: that is another file.
73
74
  */
74
75
  function atChangedPath(cwd, file, read) {
75
- const parts = file.split('/');
76
- for (let i = 0; i < parts.length; i += 1) {
76
+ const attempt = (path) => {
77
77
  try {
78
- return read(join(cwd, ...parts.slice(i)));
78
+ return read(path);
79
79
  }
80
80
  catch {
81
- // not at this depth; try the path one segment shorter
81
+ return undefined;
82
+ }
83
+ };
84
+ if (isAbsolute(file))
85
+ return attempt(file);
86
+ const parts = file.split('/');
87
+ const cwdParts = cwd.split(sep);
88
+ for (let i = 0; i < parts.length; i += 1) {
89
+ if (i > 0 &&
90
+ (i > cwdParts.length || cwdParts.slice(-i).join('/') !== parts.slice(0, i).join('/'))) {
91
+ continue;
82
92
  }
93
+ const found = attempt(join(cwd, ...parts.slice(i)));
94
+ if (found !== undefined)
95
+ return found;
83
96
  }
84
97
  return undefined;
85
98
  }
@@ -90,6 +103,30 @@ function readChangedFile(cwd, file) {
90
103
  function changedFileModifiedAt(cwd, file) {
91
104
  return atChangedPath(cwd, file, (path) => statSync(path).mtimeMs);
92
105
  }
106
+ /**
107
+ * The flows that still count as passing for the gate.
108
+ *
109
+ * A flow's newest pass counts only if its run is later than the newest mtime of the changed files
110
+ * that belong to THAT flow: the changed files that match its sources (the same suffix rule as
111
+ * `affectedFlows`, so a repo-root path, a package-relative stamp and an absolute stamp all agree).
112
+ * Edits outside its sources never invalidate it. A flow with no recorded sources cannot be
113
+ * attributed, so every changed file counts for it. A changed file that is gone fails closed. Only
114
+ * `affected` flows are judged; any other flow's newest pass stands.
115
+ */
116
+ async function currentPassing(fs, root, flows, affected, changed) {
117
+ const sourcesOf = new Map(toFlowSources(flows).map((f) => [f.name, f.sources ?? []]));
118
+ const passing = [];
119
+ const cwd = process.cwd();
120
+ for (const [name, at] of await new RunStore(fs, root).passingFlowTimes(passingFlowNames)) {
121
+ const sources = sourcesOf.get(name) ?? [];
122
+ const own = 0 === sources.length ? changed : changed.filter((f) => sourceMatchesChange(f, sources));
123
+ const stale = affected.includes(name) &&
124
+ own.some((f) => !((changedFileModifiedAt(cwd, f) ?? Infinity) < at));
125
+ if (!stale)
126
+ passing.push(name);
127
+ }
128
+ return passing;
129
+ }
93
130
  export async function handleGate(files, since,
94
131
  /** Hook mode: prose for a human, and silence when there was simply nothing to check. */
95
132
  hook = false,
@@ -102,8 +139,7 @@ acceptCoverage = false) {
102
139
  const changed = (await resolveChangedFiles(files, since, process.cwd())).files;
103
140
  const allFlows = await loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd()));
104
141
  const affected = affectedSavedFlows(allFlows, changed).affected;
105
- const latest = await new RunStore(fs, reticleRoot).latest();
106
- const passing = passingFlowNames(latest?.flows ?? []);
142
+ const passing = await currentPassing(fs, reticleRoot, allFlows, affected, changed);
107
143
  const flaky = await new FlakeStore(fs, reticleRoot).flakyFlows();
108
144
  // Anti-reward-hacking: diff each flow's CURRENT assertions against what it asserted the last
109
145
  // time it passed. A mustHold that dropped from a real consequence to a fakeable presence check is a
@@ -133,9 +169,13 @@ acceptCoverage = false) {
133
169
  .map(([name]) => name);
134
170
  // Only against a suite that exists: a project with no flows yet is NOTHING_TO_CHECK, and
135
171
  // demanding a flow per edited component on its first day would block every stop.
172
+ const flowSourcesAll = toFlowSources(allFlows);
136
173
  const unflowed = 0 === allFlows.length
137
174
  ? []
138
- : unflowedFiles(toFlowSources(allFlows), changed, (file) => isInteractiveSource(readChangedFile(process.cwd(), file)));
175
+ : unflowedFiles(flowSourcesAll, changed, (file) => isInteractiveSource(readChangedFile(process.cwd(), file)));
176
+ // Flows exist but none carries a source stamp (a stack without source stamping, or flows saved before stamping was added): `unflowed`
177
+ // then names every changed component, which would read as "nothing drove it" when a flow did.
178
+ const flowsWithoutSources = allFlows.length > 0 && flowSourcesAll.every((f) => 0 === (f.sources ?? []).length);
139
179
  // The coverage ledger, when one exists: a level that fell below its best, and changed code the
140
180
  // browser loaded and never ran. A project that never folded coverage has an empty ledger and
141
181
  // neither can fire.
@@ -181,6 +221,7 @@ acceptCoverage = false) {
181
221
  ...(result.downgraded.length > 0 ? { downgraded: result.downgraded } : {}),
182
222
  ...(result.deleted.length > 0 ? { deletedCoverage: result.deleted } : {}),
183
223
  ...(result.unflowed.length > 0 ? { unflowed: result.unflowed } : {}),
224
+ ...(result.unflowed.length > 0 && flowsWithoutSources ? { flowsWithoutSources } : {}),
184
225
  ...(result.coverageRegressed.length > 0
185
226
  ? { coverageRegressed: result.coverageRegressed }
186
227
  : {}),
@@ -221,6 +262,7 @@ acceptCoverage = false) {
221
262
  downgraded: result.downgraded.map((d) => d.flow),
222
263
  deleted: result.deleted,
223
264
  unflowed: result.unflowed,
265
+ flowsWithoutSources,
224
266
  coverageRegressed: result.coverageRegressed.map((r) => `${r.level} ${String(r.was)}% -> ${String(r.now)}%`),
225
267
  unexecuted: result.unexecuted,
226
268
  regressed: regressed?.length ?? 0,
@@ -54,6 +54,14 @@ export declare function planKill(input: {
54
54
  answersStatus: boolean;
55
55
  force: boolean;
56
56
  }): KillPlan;
57
+ /**
58
+ * Ask the daemon on `port` to run its own shutdown path. True when it accepted.
59
+ *
60
+ * Asked before any signal, on every OS. On Windows a signal ends the process at once, so the daemon
61
+ * did not close its browser or send its stop event. False for an older daemon without the route, a
62
+ * wrong token, or no answer: the caller then sends the signal as before.
63
+ */
64
+ export declare function requestShutdown(port: number, token?: string | undefined): Promise<boolean>;
57
65
  /** `reticle kill` — free the port. Resolves to whether the port is now free. */
58
66
  export declare function runKill(port: number, force: boolean): Promise<boolean>;
59
67
  export {};
@@ -23,6 +23,9 @@ import { probeDaemon } from '../../surface/mcp/mcp-proxy.js';
23
23
  import { log } from '../../log.js';
24
24
  import { fetchStatus } from '../daemon/binding/daemon-status-probe.js';
25
25
  import { captureLookup, findPortHolder } from './ports/port-holder.js';
26
+ import * as http from 'node:http';
27
+ import { LOOPBACK_HOST, SHUTDOWN_PATH } from '@reticlehq/core';
28
+ import { storedPairingToken } from '../../portal/bridge/pairing-token.js';
26
29
  /** What the plan says to do with the port. */
27
30
  export const KillAction = {
28
31
  NOTHING: 'nothing',
@@ -74,14 +77,48 @@ const GRACEFUL_KILL_MS = 5_000;
74
77
  /** How long after SIGKILL before we accept the process is not ours to kill and say so. */
75
78
  const FORCED_KILL_MS = 2_000;
76
79
  const KILL_POLL_MS = 100;
80
+ /** A loopback call: a daemon that does not answer in this time gets the signal instead. */
81
+ const SHUTDOWN_REQUEST_TIMEOUT_MS = 1_000;
82
+ /**
83
+ * Ask the daemon on `port` to run its own shutdown path. True when it accepted.
84
+ *
85
+ * Asked before any signal, on every OS. On Windows a signal ends the process at once, so the daemon
86
+ * did not close its browser or send its stop event. False for an older daemon without the route, a
87
+ * wrong token, or no answer: the caller then sends the signal as before.
88
+ */
89
+ export function requestShutdown(port, token = storedPairingToken()) {
90
+ if (token === undefined) {
91
+ return Promise.resolve(false);
92
+ }
93
+ return new Promise((resolve) => {
94
+ const req = http.request({
95
+ host: LOOPBACK_HOST,
96
+ port,
97
+ path: SHUTDOWN_PATH,
98
+ method: 'POST',
99
+ headers: { authorization: `Bearer ${token}` },
100
+ timeout: SHUTDOWN_REQUEST_TIMEOUT_MS,
101
+ }, (res) => {
102
+ res.resume();
103
+ resolve(202 === res.statusCode);
104
+ });
105
+ req.on('error', () => resolve(false));
106
+ req.on('timeout', () => {
107
+ req.destroy();
108
+ resolve(false);
109
+ });
110
+ req.end();
111
+ });
112
+ }
77
113
  /**
78
114
  * Signal ONE pid and wait for it to go: SIGTERM, then SIGKILL, then give up and say it survived.
115
+ * `asked`: the daemon already accepted a shutdown request, so the SIGTERM is not sent.
79
116
  *
80
117
  * The escalation is the reason this exists rather than a bare SIGTERM — there is a field report of a
81
118
  * daemon that ignored SIGTERM until a human ran `kill -9` by hand, which is the moment the `lsof -ti`
82
119
  * pipeline gets typed and the agent's proxy dies with the daemon.
83
120
  */
84
- async function terminate(pid) {
121
+ async function terminate(pid, asked = false) {
85
122
  const signal = (name) => {
86
123
  try {
87
124
  process.kill(pid, name);
@@ -90,7 +127,9 @@ async function terminate(pid) {
90
127
  // Gone between the liveness check and here. The next poll reports it as gone.
91
128
  }
92
129
  };
93
- signal('SIGTERM');
130
+ if (!asked) {
131
+ signal('SIGTERM');
132
+ }
94
133
  const started = Date.now();
95
134
  let escalated = false;
96
135
  for (;;) {
@@ -143,7 +182,8 @@ export async function runKill(port, force) {
143
182
  log('reticle_kill_nothing_to_do', { port, presence });
144
183
  return true;
145
184
  }
146
- const { gone, escalated } = await terminate(pid);
185
+ const asked = PortPresence.DAEMON === presence && (await requestShutdown(port));
186
+ const { gone, escalated } = await terminate(pid, asked);
147
187
  if (gone)
148
188
  removePid(port);
149
189
  log(gone ? 'reticle_killed' : 'reticle_kill_survived', {
@@ -11,6 +11,8 @@ export declare const BUG_FLAG = "--bug";
11
11
  */
12
12
  export declare const KIND_FLAG = "--kind";
13
13
  export declare const AGENT_FLAG = "--agent";
14
+ /** `--contact <email>`: a reply address, sent only when the person gives it. */
15
+ export declare const CONTACT_FLAG = "--contact";
14
16
  /** Accepted `--kind` values, from core's enum — never a second hand-written list to drift from it. */
15
17
  export declare const FEEDBACK_KINDS: readonly string[];
16
18
  /** What `parseFeedbackArgs` yields: the parsed command, or a usage error to print. */
@@ -23,6 +25,8 @@ export type ParsedFeedback = {
23
25
  bug: boolean;
24
26
  /** `--agent`: file as the agent, so agent reports never dilute the human rating signal. */
25
27
  agent: boolean;
28
+ /** `--contact`: a reply address the person gave. */
29
+ contact?: string;
26
30
  } | {
27
31
  kind: 'error';
28
32
  message: string;
@@ -5,7 +5,7 @@
5
5
  * is the one command whose arguments are free text, so it is the only place in the grammar where
6
6
  * "everything that is not a flag" is a rule with edge cases rather than a one-liner.
7
7
  */
8
- import { FeedbackKind } from '@reticlehq/core/telemetry';
8
+ import { FEEDBACK_CONTACT_MAX, FeedbackKind, isFeedbackContact } from '@reticlehq/core/telemetry';
9
9
  /** `reticle feedback --rating 4 "the words"` — the human half of the channel. */
10
10
  export const RATING_FLAG = '--rating';
11
11
  export const BUG_FLAG = '--bug';
@@ -19,6 +19,8 @@ export const BUG_FLAG = '--bug';
19
19
  */
20
20
  export const KIND_FLAG = '--kind';
21
21
  export const AGENT_FLAG = '--agent';
22
+ /** `--contact <email>`: a reply address, sent only when the person gives it. */
23
+ export const CONTACT_FLAG = '--contact';
22
24
  /** Accepted `--kind` values, from core's enum — never a second hand-written list to drift from it. */
23
25
  export const FEEDBACK_KINDS = Object.values(FeedbackKind);
24
26
  /** Parse everything after `reticle feedback`. */
@@ -33,6 +35,14 @@ export function parseFeedbackArgs(rest) {
33
35
  if (feedbackKind !== undefined && !FEEDBACK_KINDS.includes(feedbackKind)) {
34
36
  return { kind: 'error', message: `${KIND_FLAG} takes one of: ${FEEDBACK_KINDS.join(', ')}` };
35
37
  }
38
+ const contactAt = rest.indexOf(CONTACT_FLAG);
39
+ const contact = -1 === contactAt ? undefined : (rest[contactAt + 1] ?? '');
40
+ if (contact !== undefined && !isFeedbackContact(contact)) {
41
+ return {
42
+ kind: 'error',
43
+ message: `${CONTACT_FLAG} takes one email address of at most ${String(FEEDBACK_CONTACT_MAX)} characters, such as you@example.com`,
44
+ };
45
+ }
36
46
  // Everything that is not a flag or a flag's VALUE is the message. Quoting is the user's job for
37
47
  // shell reasons, but joining the remainder means an unquoted sentence still works. Both value
38
48
  // positions have to be consumed: without that, `--kind bug "..."` filed a report whose text began
@@ -40,6 +50,7 @@ export function parseFeedbackArgs(rest) {
40
50
  const consumed = new Set([
41
51
  ...(-1 === ratingAt ? [] : [ratingAt, ratingAt + 1]),
42
52
  ...(-1 === kindAt ? [] : [kindAt, kindAt + 1]),
53
+ ...(-1 === contactAt ? [] : [contactAt, contactAt + 1]),
43
54
  ]);
44
55
  const text = rest
45
56
  .filter((arg, i) => !consumed.has(i) && !arg.startsWith('--'))
@@ -52,5 +63,6 @@ export function parseFeedbackArgs(rest) {
52
63
  ...(feedbackKind !== undefined ? { feedbackKind } : {}),
53
64
  bug: rest.includes(BUG_FLAG),
54
65
  agent: rest.includes(AGENT_FLAG),
66
+ ...(contact !== undefined ? { contact } : {}),
55
67
  };
56
68
  }
@@ -46,8 +46,7 @@ export declare const CLOUD_COMMANDS: readonly string[];
46
46
  export declare const RENAMED_COMMANDS: ReadonlyMap<string, string>;
47
47
  /**
48
48
  * The command an old name now goes by, when the note saying so should print; otherwise undefined.
49
- * Not for a request for help (that answer names the new command itself), and not for
50
- * `login --email`, which `connect --help` documents as the sign-in for CI and agents.
49
+ * Not for a request for help (that answer names the new command itself).
51
50
  */
52
51
  export declare function renamedCommandFor(argv: readonly string[]): string | undefined;
53
52
  /**
@@ -82,19 +82,14 @@ export const RENAMED_COMMANDS = new Map([
82
82
  ['memory', 'runs memory'],
83
83
  ]);
84
84
  const HELP_FLAGS = new Set(['--help', '-h']);
85
- /** `login --email` is the documented sign-in without a browser, so it is not a renamed `connect`. */
86
- const BROWSERLESS_LOGIN = { command: 'login', flag: '--email' };
87
85
  /**
88
86
  * The command an old name now goes by, when the note saying so should print; otherwise undefined.
89
- * Not for a request for help (that answer names the new command itself), and not for
90
- * `login --email`, which `connect --help` documents as the sign-in for CI and agents.
87
+ * Not for a request for help (that answer names the new command itself).
91
88
  */
92
89
  export function renamedCommandFor(argv) {
93
90
  const name = argv[0];
94
91
  if (name === undefined || argv.some((arg) => HELP_FLAGS.has(arg)))
95
92
  return undefined;
96
- if (BROWSERLESS_LOGIN.command === name && argv.includes(BROWSERLESS_LOGIN.flag))
97
- return undefined;
98
93
  return RENAMED_COMMANDS.get(name);
99
94
  }
100
95
  /**
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Force a hidden browser. The default is now HEADED: a run nobody can see is a run nobody trusts,
3
+ * and every "did it actually do anything?" question cost a round-trip. CI passes this (or just sets
4
+ * CI, which flips the default) because there is no display there to be headed on.
5
+ */
6
+ export declare const HEADLESS_FLAG = "--headless";
7
+ export declare const DRIVE_FLAG = "--drive";
8
+ export declare const HTTP_FLAG = "--http";
9
+ export declare const HTTP_PORT_FLAG = "--http-port";
10
+ export declare const HTTP_TOKEN_FLAG = "--http-token";
11
+ type ServeFlags = {
12
+ kind: 'ok';
13
+ port: number;
14
+ driveUrl?: string;
15
+ headless: boolean;
16
+ http: boolean;
17
+ httpPort?: number;
18
+ httpToken?: string;
19
+ } | {
20
+ kind: 'error';
21
+ message: string;
22
+ };
23
+ export declare function parseServeFlags(args: string[], defaultPort: number, defaultHeadless: boolean): ServeFlags;
24
+ export {};
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The serve / mcp / `_daemon` flag grammar, including the verify HTTP endpoint.
3
+ *
4
+ * Split out of `cli-parse.ts` when that file crossed the line cap. These three commands share one
5
+ * flag set: the bridge port, a drive URL, headless, and the verify endpoint `--http` starts.
6
+ */
7
+ import { HEADED_FLAG, PORT_FLAG, missingValue, notANumber, unknownArgument, } from './cli-parse-grammar.js';
8
+ /**
9
+ * Force a hidden browser. The default is now HEADED: a run nobody can see is a run nobody trusts,
10
+ * and every "did it actually do anything?" question cost a round-trip. CI passes this (or just sets
11
+ * CI, which flips the default) because there is no display there to be headed on.
12
+ */
13
+ export const HEADLESS_FLAG = '--headless';
14
+ export const DRIVE_FLAG = '--drive';
15
+ export const HTTP_FLAG = '--http';
16
+ export const HTTP_PORT_FLAG = '--http-port';
17
+ export const HTTP_TOKEN_FLAG = '--http-token';
18
+ const requiresHttp = (flag) => ({
19
+ kind: 'error',
20
+ message: `${flag} requires ${HTTP_FLAG} — it configures the verify endpoint ${HTTP_FLAG} starts`,
21
+ });
22
+ /**
23
+ * The verify endpoint cannot use the bridge port.
24
+ *
25
+ * `reticle serve --http --http-port 4400` reached `listen` and died with a raw
26
+ * `EADDRINUSE 127.0.0.1:4400`. That number is this daemon's bridge port, and MCP is already
27
+ * served there. Name both ports and stop before anything listens (#1786).
28
+ */
29
+ const httpPortIsBridge = (httpPort, bridgePort) => ({
30
+ kind: 'error',
31
+ message: `${HTTP_PORT_FLAG} ${String(httpPort)} is the bridge port ${String(bridgePort)}. ` +
32
+ 'Pick another port. MCP is already served on the bridge port.',
33
+ });
34
+ export function parseServeFlags(args, defaultPort, defaultHeadless) {
35
+ let port = defaultPort;
36
+ let driveUrl;
37
+ let headless = defaultHeadless;
38
+ let http = false;
39
+ let httpPort;
40
+ let httpToken;
41
+ let i = 0;
42
+ while (i < args.length) {
43
+ const arg = args[i];
44
+ // `i < args.length` already guarantees this, but the index signature does not say so and the
45
+ // unknown-argument error needs a real string to name.
46
+ if (arg === undefined) {
47
+ break;
48
+ }
49
+ if (arg === PORT_FLAG) {
50
+ i++;
51
+ const n = args[i];
52
+ if (n === undefined) {
53
+ return missingValue(PORT_FLAG);
54
+ }
55
+ const parsed = parseInt(n, 10);
56
+ if (isNaN(parsed)) {
57
+ return notANumber(PORT_FLAG, n);
58
+ }
59
+ port = parsed;
60
+ }
61
+ else if (arg === DRIVE_FLAG) {
62
+ i++;
63
+ driveUrl = args[i];
64
+ if (driveUrl === undefined) {
65
+ return missingValue(DRIVE_FLAG);
66
+ }
67
+ }
68
+ else if (arg === HEADED_FLAG) {
69
+ headless = false;
70
+ }
71
+ else if (arg === HEADLESS_FLAG) {
72
+ headless = true;
73
+ }
74
+ else if (arg === HTTP_FLAG) {
75
+ http = true;
76
+ }
77
+ else if (arg === HTTP_PORT_FLAG) {
78
+ i++;
79
+ const n = args[i];
80
+ if (n === undefined) {
81
+ return missingValue(HTTP_PORT_FLAG);
82
+ }
83
+ const parsed = parseInt(n, 10);
84
+ if (isNaN(parsed)) {
85
+ return notANumber(HTTP_PORT_FLAG, n);
86
+ }
87
+ httpPort = parsed;
88
+ }
89
+ else if (arg === HTTP_TOKEN_FLAG) {
90
+ i++;
91
+ httpToken = args[i];
92
+ if (httpToken === undefined) {
93
+ return missingValue(HTTP_TOKEN_FLAG);
94
+ }
95
+ }
96
+ else {
97
+ return unknownArgument(arg);
98
+ }
99
+ i++;
100
+ }
101
+ // Without `--http` these flags configure an endpoint nothing starts, and they were accepted and
102
+ // silently ignored — worse than being rejected, because the whole reason to pass them is to be
103
+ // honoured (#687).
104
+ if (!http && httpPort !== undefined) {
105
+ return requiresHttp(HTTP_PORT_FLAG);
106
+ }
107
+ if (!http && httpToken !== undefined) {
108
+ return requiresHttp(HTTP_TOKEN_FLAG);
109
+ }
110
+ // `port` is the bridge port this command will bind. The caller passes the resolved default
111
+ // (RETICLE_PORT, the project port, this project's daemon, or 4400). `--port` replaces it.
112
+ if (httpPort !== undefined && httpPort === port) {
113
+ return httpPortIsBridge(httpPort, port);
114
+ }
115
+ return {
116
+ kind: 'ok',
117
+ port,
118
+ headless,
119
+ http,
120
+ ...(driveUrl !== undefined ? { driveUrl } : {}),
121
+ ...(httpPort !== undefined ? { httpPort } : {}),
122
+ ...(httpToken !== undefined ? { httpToken } : {}),
123
+ };
124
+ }