@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
@@ -67,7 +67,17 @@ function reopenableUrl(raw) {
67
67
  * bin on PATH, so a bare `reticle init` fails with "command not found" exactly where it is handed out.
68
68
  */
69
69
  const CLI = 'npx @reticlehq/server';
70
- const INIT_COMMAND = `${CLI} init`;
70
+ export const INIT_COMMAND = `${CLI} init`;
71
+ /**
72
+ * The consent question for wiring, in one wording for every place that offers `init`: the
73
+ * handshake, the first session call, every next action and the plugin hook. `init` changes the user's files, so the
74
+ * agent asks first. The lease changes nothing, so it needs no question.
75
+ */
76
+ export function wiringConsent(init = INIT_COMMAND) {
77
+ return ('`init` changes files: it adds a dev-only SDK to package.json and the lockfile, edits the ' +
78
+ 'build config and starts the dev server. Ask the user before you wire the app. If they ' +
79
+ `agree, run \`${init}\` in the app's folder. If they decline, do not ask again.`);
80
+ }
71
81
  const OPEN_COMMAND = `${CLI} open`;
72
82
  const LOCALHOST = 'http://localhost';
73
83
  /**
@@ -77,13 +87,26 @@ const LOCALHOST = 'http://localhost';
77
87
  const ZERO_INSTALL_SEES = 'the lease supplies the SDK itself: DOM, network, console and routes, but no component state ' +
78
88
  'or source file:line until the app is wired';
79
89
  /** The zero-install call, with the URL only when it can be named without guessing. */
80
- function zeroInstallLease(url) {
81
- return `reticle_lease {action:"acquire", url:"${url ?? "<the app's URL>"}"}`;
90
+ export function zeroInstallLease(url) {
91
+ // Through reticle_run: reticle_lease is not on the default surface, and reticle_run is on every one (#1547).
92
+ return `reticle_run { tool: "reticle_lease", args: { action: "acquire", url: "${url ?? "<the app's URL>"}" } }`;
82
93
  }
83
94
  /** Nothing here says this project was ever wired: no config, no recorded connection, no session. */
84
95
  function neverWired(facts) {
85
96
  return !facts.initialized && true !== facts.previouslyConnected && !facts.everConnected;
86
97
  }
98
+ /**
99
+ * The start advice's first claim when no port is this project's. A scan that heard a page it could
100
+ * not tie to this project says so, because "nothing is listening" is then false.
101
+ */
102
+ function notThisProject(others) {
103
+ if (others === undefined || 0 === others.length) {
104
+ return 'nothing is listening on the ports Reticle scans, so the app is probably not running — ';
105
+ }
106
+ const named = others.map((port) => `:${String(port)}`).join(', ');
107
+ return (`${named} serves a page, but its process does not run in this project's folder, so this app ` +
108
+ `is probably not running — if one of them IS this app, open it instead of starting a second one, `);
109
+ }
87
110
  export function nextActionFor(facts) {
88
111
  // FIRST, above every other cause, because it is the only one supported by positive evidence about
89
112
  // a daemon rather than by an absence. This project's own connection record names a live daemon
@@ -149,7 +172,8 @@ export function nextActionFor(facts) {
149
172
  (departedTo === undefined || '' === departedTo
150
173
  ? 'the tab was closed, reloaded, or the lease aged out. '
151
174
  : `the page navigated away to ${redactUrl(departedTo)}. `) +
152
- 'Reopen the app, or take one you own with reticle_lease {action:"acquire", url}.' +
175
+ 'Reopen the app, or take one you own with ' +
176
+ 'reticle_run { tool: "reticle_lease", args: { action: "acquire", url } }.' +
153
177
  bound,
154
178
  };
155
179
  }
@@ -163,8 +187,8 @@ export function nextActionFor(facts) {
163
187
  const projectIds = configsElsewhere.flatMap((config) => config.projectId === undefined ? [] : [config.projectId]);
164
188
  const leaseAlternative = 0 === projectIds.length
165
189
  ? ''
166
- : ' Alternatively, acquire the app URL explicitly with reticle_lease ' +
167
- '{action:"acquire", url, projectId} using the matching projectId above.';
190
+ : ' Alternatively, acquire the app URL explicitly with reticle_run { tool: "reticle_lease", ' +
191
+ 'args: { action: "acquire", url, projectId } } using the matching projectId above.';
168
192
  return {
169
193
  action: NoSessionAction.OPEN_APP,
170
194
  reason: `a \`.reticle.json\` was found outside this daemon's directory: ${named}. This is a ` +
@@ -215,8 +239,8 @@ export function nextActionFor(facts) {
215
239
  'This daemon was started outside the project (an IDE that registers the MCP server ' +
216
240
  'globally starts it in `/` or your home directory), so it has no `.reticle.json` to match ' +
217
241
  'the page against. Do NOT run `reticle init`: the config it would write is already correct ' +
218
- 'somewhere else. Take a context you own instead with reticle_lease {action:"acquire", url, ' +
219
- "projectId}, or restart the daemon from the app's own directory.",
242
+ 'somewhere else. Take a context you own instead with reticle_run { tool: "reticle_lease", ' +
243
+ 'args: { action: "acquire", url, projectId } }, or restart the daemon from the app\'s own directory.',
220
244
  };
221
245
  }
222
246
  if (0 === facts.listening.length || departedPortIsGone) {
@@ -229,7 +253,7 @@ export function nextActionFor(facts) {
229
253
  : ` The session that was on ${redactUrl(stopped.url)} is gone and nothing listens there now.`;
230
254
  const notRunning = departedPortIsGone
231
255
  ? "nothing answers on the port this project's app was last on, so the app is probably not running — "
232
- : 'nothing is listening on the ports Reticle scans, so the app is probably not running — ';
256
+ : notThisProject(facts.otherListeners);
233
257
  if (dev === undefined) {
234
258
  if (facts.exists !== undefined && !facts.exists('package.json')) {
235
259
  const ecosystem = detectNonJsEcosystem(facts.exists);
@@ -279,12 +303,12 @@ export function nextActionFor(facts) {
279
303
  (undefined === dev.script ? 'launcher' : `\`${dev.script}\` script`) +
280
304
  (dev.directory === undefined ? '' : `, in \`${dev.directory}\``) +
281
305
  ` — run it in the ` +
282
- 'background, tell the human it is running, then call reticle_sessions again.' +
306
+ 'background, tell the human it is running, then call reticle_session { action: "list" } again.' +
283
307
  stoppedNote +
284
308
  (neverWired(facts)
285
309
  ? ` Once it is up, ${zeroInstallLease(dev.port === undefined ? undefined : `${LOCALHOST}:${String(dev.port)}`)} ` +
286
310
  `gets a verdict with nothing installed (${ZERO_INSTALL_SEES}); ` +
287
- `\`${facts.init ?? INIT_COMMAND}\` wires it for good — then restart the dev server and reload.`
311
+ `To wire it for good: ${wiringConsent(facts.init ?? INIT_COMMAND)} Then restart the dev server and reload.`
288
312
  : ''),
289
313
  };
290
314
  }
@@ -301,9 +325,9 @@ export function nextActionFor(facts) {
301
325
  reason: `something is listening (${ports}) but no \`.reticle.json\` was found, so the app may ` +
302
326
  'carry no Reticle SDK. For a verdict NOW with nothing installed: ' +
303
327
  `${zeroInstallLease(target === undefined ? undefined : `${LOCALHOST}:${String(target)}`)} — ` +
304
- `${ZERO_INSTALL_SEES}. To wire it for good, run this command yourself (it runs in the ` +
305
- "APP's own folder, not where this daemon stands), then restart the dev server and reload " +
306
- 'the page.',
328
+ `${ZERO_INSTALL_SEES}. To wire it for good: ${wiringConsent(facts.init ?? INIT_COMMAND)} ` +
329
+ "The app's folder is not always where this daemon stands. Then restart the dev server and " +
330
+ 'reload the page.',
307
331
  };
308
332
  }
309
333
  if (only === undefined) {
@@ -343,7 +367,8 @@ export function nextActionFor(facts) {
343
367
  /** The same action as one sentence, for the prose message the human reads. */
344
368
  export function renderNextAction(next) {
345
369
  const command = next.command;
346
- return command === undefined
370
+ // `init` changes the user's files, so its line repeats the consent in the reason, not an order.
371
+ return command === undefined || NoSessionAction.RUN_INIT === next.action
347
372
  ? `NEXT ACTION: ${next.reason}`
348
373
  : `NEXT ACTION: run \`${command}\` — ${next.reason}`;
349
374
  }
@@ -67,6 +67,13 @@ interface NoSessionWatchOptions {
67
67
  * somebody else's app. Injected for tests; production reads the registry scoped by projectId/root.
68
68
  */
69
69
  ownDevServerPorts?: () => readonly number[];
70
+ /**
71
+ * The folder the process listening on `port` runs in, or undefined when it cannot be read.
72
+ *
73
+ * An unwired project announces no port, so this is the one fact that ties a running dev server
74
+ * to it. Injected for tests; a test that injects `probe` and omits this observes no folder.
75
+ */
76
+ listenerDirectory?: (port: number) => string | undefined;
70
77
  /**
71
78
  * What the route the last session was on answers right now, as an HTTP status, or undefined
72
79
  * when there is no answer to report.
@@ -30,6 +30,8 @@ import { findOccupiedSiblings } from '../../command/cli/ports/sibling-ports.js';
30
30
  import { isAuthRefusalReason } from '../bridge/auth-failure-reason.js';
31
31
  import { devServersForProject } from '@reticlehq/core';
32
32
  import { readDevServers } from '../../command/daemon/dev-servers.js';
33
+ import { servingDirectoryOf } from './serving-directory.js';
34
+ import { within } from './zero-install-first-call.js';
33
35
  /** Slow enough to be free, fast enough that a dev server started 15s ago is already reflected. */
34
36
  const REFRESH_MS = 15_000;
35
37
  /** The URL an auto-attach opens. `localhost` for the same reason the probe uses it: both stacks. */
@@ -69,6 +71,12 @@ export function startNoSessionWatch(options) {
69
71
  * `options.probe` returns only the serving set, so this stays empty for injected probes.
70
72
  */
71
73
  let slowListeners = [];
74
+ /** The folder each listening port's process runs in, read on the scan's cadence, not when asked. */
75
+ let listenerDirs = new Map();
76
+ const listenerDirectory = options.listenerDirectory ??
77
+ (options.probe === undefined
78
+ ? (port) => servingDirectoryOf(`${LOCALHOST}:${String(port)}`)
79
+ : () => undefined);
72
80
  let siblingListeners = [];
73
81
  /**
74
82
  * What the last-known route answered, cached beside the port scan for the same reason the scan
@@ -97,8 +105,9 @@ export function startNoSessionWatch(options) {
97
105
  */
98
106
  const projectScopeFacts = () => {
99
107
  const initialized = isWired();
100
- if (initialized)
108
+ if (initialized) {
101
109
  return { initialized };
110
+ }
102
111
  const discovery = discoverProjectConfigs(directory);
103
112
  const elsewhere = discovery.found.filter((config) => config.directory !== directory);
104
113
  if (elsewhere.length > 0) {
@@ -192,21 +201,25 @@ export function startNoSessionWatch(options) {
192
201
  */
193
202
  const scanPorts = () => {
194
203
  const ports = new Set(DEV_SERVER_PORTS);
195
- for (const port of ownDevServerPorts())
204
+ for (const port of ownDevServerPorts()) {
196
205
  ports.add(port);
206
+ }
197
207
  const pinned = detectDevCommandInProject(directory)?.port;
198
- if (pinned !== undefined)
208
+ if (pinned !== undefined) {
199
209
  ports.add(pinned);
210
+ }
200
211
  const known = options.sessions.lastKnown?.();
201
212
  const knownPort = known === undefined ? undefined : portOfUrl(known.url);
202
- if (knownPort !== undefined)
213
+ if (knownPort !== undefined) {
203
214
  ports.add(knownPort);
215
+ }
204
216
  // Every departed project, not only the newest. B can still be serving on :3005 after A leaves
205
217
  // on :5173, and a scan that never asked :3005 would report B's app as stopped.
206
218
  for (const url of options.sessions.tombstoneUrls?.() ?? []) {
207
219
  const port = portOfUrl(url);
208
- if (port !== undefined)
220
+ if (port !== undefined) {
209
221
  ports.add(port);
222
+ }
210
223
  }
211
224
  return [...ports];
212
225
  };
@@ -216,8 +229,9 @@ export function startNoSessionWatch(options) {
216
229
  * browser is worse than the sentence the diagnosis already writes about the ports it saw.
217
230
  */
218
231
  const attributable = (port) => {
219
- if (ownDevServerPorts().includes(port))
232
+ if (ownDevServerPorts().includes(port)) {
220
233
  return true;
234
+ }
221
235
  const known = options.sessions.lastKnown?.();
222
236
  const projectId = readProjectId(directory);
223
237
  if (known === undefined || projectId === undefined || known.projectId !== projectId) {
@@ -232,17 +246,22 @@ export function startNoSessionWatch(options) {
232
246
  };
233
247
  const autoAttach = async (ports) => {
234
248
  const attach = options.attach;
235
- if (attach === undefined)
249
+ if (attach === undefined) {
236
250
  return;
237
- if (1 !== ports.length)
251
+ }
252
+ if (1 !== ports.length) {
238
253
  return;
254
+ }
239
255
  const [only] = ports;
240
- if (only === undefined || attempted.has(only))
256
+ if (only === undefined || attempted.has(only)) {
241
257
  return;
242
- if (!isWired())
258
+ }
259
+ if (!isWired()) {
243
260
  return;
244
- if (!attributable(only))
261
+ }
262
+ if (!attributable(only)) {
245
263
  return;
264
+ }
246
265
  attempted.add(only);
247
266
  try {
248
267
  await attach(`${LOCALHOST}:${String(only)}`);
@@ -254,10 +273,12 @@ export function startNoSessionWatch(options) {
254
273
  const refresh = () => {
255
274
  // Nothing to diagnose while a session is live, and no reason to scan. What the last scan saw
256
275
  // predates this session, so it is no observation of where the session goes on to depart from.
257
- if (options.sessions.count() > 0)
276
+ if (options.sessions.count() > 0) {
258
277
  probed = new Set();
259
- if (running || options.sessions.count() > 0)
278
+ }
279
+ if (running || options.sessions.count() > 0) {
260
280
  return;
281
+ }
261
282
  running = true;
262
283
  const candidates = scanPorts();
263
284
  void (options.probe === undefined
@@ -269,6 +290,10 @@ export function startNoSessionWatch(options) {
269
290
  .then(async (ports) => {
270
291
  probed = new Set(candidates);
271
292
  listening = ports;
293
+ listenerDirs = new Map(ports.flatMap((port) => {
294
+ const dir = listenerDirectory(port);
295
+ return dir === undefined ? [] : [[port, dir]];
296
+ }));
272
297
  siblingListeners =
273
298
  options.occupiedSiblings !== undefined
274
299
  ? await options.occupiedSiblings()
@@ -280,8 +305,9 @@ export function startNoSessionWatch(options) {
280
305
  const known = options.sessions.lastKnown?.();
281
306
  if (known !== undefined && lastKnownStatus?.url !== known.url) {
282
307
  const status = await routeStatus(known.url);
283
- if (status !== undefined)
308
+ if (status !== undefined) {
284
309
  lastKnownStatus = { url: known.url, status };
310
+ }
285
311
  }
286
312
  await autoAttach(ports);
287
313
  })
@@ -324,10 +350,12 @@ export function startNoSessionWatch(options) {
324
350
  */
325
351
  const currentHelloRefusal = () => {
326
352
  const closure = options.sessions.lastClosure?.();
327
- if (closure?.page === undefined || isAuthRefusalReason(closure.reason))
353
+ if (closure?.page === undefined || isAuthRefusalReason(closure.reason)) {
328
354
  return undefined;
329
- if (true === options.sessions.connectedSinceLastClosure?.())
355
+ }
356
+ if (true === options.sessions.connectedSinceLastClosure?.()) {
330
357
  return undefined;
358
+ }
331
359
  return { reason: closure.reason, ...closure.page };
332
360
  };
333
361
  /**
@@ -354,15 +382,25 @@ export function startNoSessionWatch(options) {
354
382
  const ownPorts = new Set(devServersForProject(readDevServers(stateDir), { projectId, root: dir }).map((entry) => entry.port));
355
383
  if (known !== undefined) {
356
384
  const port = portOfUrl(known.url);
357
- if (port !== undefined)
385
+ if (port !== undefined) {
358
386
  ownPorts.add(port);
387
+ }
388
+ }
389
+ // A process that runs in this folder is this project's dev server, announced or not. An unwired
390
+ // project announces nothing, and without this its running app read as absent.
391
+ for (const port of listening) {
392
+ if (within(listenerDirs.get(port), dir)) {
393
+ ownPorts.add(port);
394
+ }
359
395
  }
360
396
  const heard = listening.filter((port) => ownPorts.has(port));
397
+ const others = listening.filter((port) => !ownPorts.has(port));
361
398
  // Not in the last scan means we have not looked, not that the server stopped. Treating the
362
399
  // gap as "down" is what tells a still-running app to start a second one.
363
400
  for (const port of ownPorts) {
364
- if (!probed.has(port) && !heard.includes(port))
401
+ if (!probed.has(port) && !heard.includes(port)) {
365
402
  heard.push(port);
403
+ }
366
404
  }
367
405
  const slow = slowListeners.filter((port) => ownPorts.has(port));
368
406
  const closure = options.sessions.lastClosure?.();
@@ -433,6 +471,7 @@ export function startNoSessionWatch(options) {
433
471
  ...(helloRefused === undefined ? {} : { helloRefused: helloRefused.reason }),
434
472
  ...(split === undefined ? {} : { splitBrain: split }),
435
473
  listening: heard,
474
+ ...(0 === others.length ? {} : { otherListeners: others }),
436
475
  slowListeners: slow,
437
476
  ...(known === undefined
438
477
  ? {}
@@ -451,8 +490,9 @@ export function startNoSessionWatch(options) {
451
490
  */
452
491
  const callerAnswer = () => {
453
492
  const caller = callingClientDirectory();
454
- if (caller === undefined)
493
+ if (caller === undefined) {
455
494
  return undefined;
495
+ }
456
496
  return diagnosisFor(caller);
457
497
  };
458
498
  /**
@@ -489,8 +529,9 @@ export function startNoSessionWatch(options) {
489
529
  // command and the sentence beside it name the same page.
490
530
  ...(() => {
491
531
  const known = options.sessions.lastKnown?.();
492
- if (known === undefined)
532
+ if (known === undefined) {
493
533
  return {};
534
+ }
494
535
  return {
495
536
  lastKnownUrl: known.url,
496
537
  ...(known.departedTo === undefined ? {} : { departedTo: known.departedTo }),
@@ -512,8 +553,9 @@ export function startNoSessionWatch(options) {
512
553
  // calls a moment apart can genuinely disagree (#615).
513
554
  const explain = () => {
514
555
  const caller = callerAnswer();
515
- if (caller !== undefined)
556
+ if (caller !== undefined) {
516
557
  return explainNoSession(caller.facts);
558
+ }
517
559
  const scope = projectScopeFacts();
518
560
  return explainNoSession({
519
561
  everConnected: options.sessions.everConnected(),
@@ -563,8 +605,9 @@ export function startNoSessionWatch(options) {
563
605
  // has none to name.
564
606
  ...(() => {
565
607
  const known = options.sessions.lastKnown?.();
566
- if (undefined === known)
608
+ if (undefined === known) {
567
609
  return {};
610
+ }
568
611
  // The status rides only when it was fetched for THIS url. A departure since the fetch
569
612
  // means the cached answer is about a route nobody is asking about.
570
613
  const status = lastKnownStatus !== undefined && lastKnownStatus.url === known.url
@@ -635,8 +678,9 @@ export function wireSessionScope(sessions, activeProjectId, port,
635
678
  wasReapedLease,
636
679
  /** Opens a URL in a Reticle-owned browser (the pool). Omitted ⇒ auto-attach is off. */
637
680
  attach) {
638
- if (activeProjectId !== undefined)
681
+ if (activeProjectId !== undefined) {
639
682
  sessions.setDefaultScope({ projectId: activeProjectId });
683
+ }
640
684
  return startNoSessionWatch({
641
685
  sessions,
642
686
  port,
@@ -79,4 +79,14 @@ export declare function sizeCost(payload: unknown): SizeCost;
79
79
  * Non-object results (e.g. a thrown-error envelope) pass through unchanged.
80
80
  */
81
81
  export declare function withSizeCost<T>(result: T): T;
82
+ /**
83
+ * Drop `sessionId` from an event in a response the caller scoped to ONE session.
84
+ *
85
+ * The caller passed that id in the request, so echoing it on every event is the request quoted back
86
+ * once per row. Measured on a live app it was 25% of a four-event `reticle_observe` payload, and it
87
+ * grows linearly with the timeline — a fifty-event window spends ~2.5KB restating a fact the caller
88
+ * supplied. The id stays on the wire between SDK and bridge, where events from different sessions
89
+ * really do interleave; it is only redundant at this boundary.
90
+ */
91
+ export declare function withoutConstantSessionId(event: unknown): unknown;
82
92
  export {};
@@ -106,3 +106,19 @@ export function withSizeCost(result) {
106
106
  return result;
107
107
  return { ...result, cost: sizeCost(result) };
108
108
  }
109
+ /**
110
+ * Drop `sessionId` from an event in a response the caller scoped to ONE session.
111
+ *
112
+ * The caller passed that id in the request, so echoing it on every event is the request quoted back
113
+ * once per row. Measured on a live app it was 25% of a four-event `reticle_observe` payload, and it
114
+ * grows linearly with the timeline — a fifty-event window spends ~2.5KB restating a fact the caller
115
+ * supplied. The id stays on the wire between SDK and bridge, where events from different sessions
116
+ * really do interleave; it is only redundant at this boundary.
117
+ */
118
+ export function withoutConstantSessionId(event) {
119
+ if (typeof event !== 'object' || null === event) {
120
+ return event;
121
+ }
122
+ const { sessionId: _sessionId, ...rest } = event;
123
+ return rest;
124
+ }
@@ -12,3 +12,5 @@ export interface SessionLease {
12
12
  IMPORTANT: string;
13
13
  }
14
14
  export declare function buildSessionLease(sessionId: string, openedAt: number): SessionLease;
15
+ /** The age warning spliced onto session-bound results after SESSION_LEASE.WARN_AFTER_MS, else undefined. */
16
+ export declare function sessionAgeWarning(sessionId: string, ageMs: number): string | undefined;
@@ -1,3 +1,4 @@
1
+ import { SESSION_LEASE } from '@reticlehq/core';
1
2
  /**
2
3
  * Kept SHORT on purpose, and this is the reason to read before editing it.
3
4
  *
@@ -12,3 +13,10 @@ const SESSION_LEASE_NOTICE = 'When you stop driving, call reticle_session {actio
12
13
  export function buildSessionLease(sessionId, openedAt) {
13
14
  return { sessionId, opened_at: openedAt, IMPORTANT: SESSION_LEASE_NOTICE };
14
15
  }
16
+ /** The age warning spliced onto session-bound results after SESSION_LEASE.WARN_AFTER_MS, else undefined. */
17
+ export function sessionAgeWarning(sessionId, ageMs) {
18
+ if (ageMs < SESSION_LEASE.WARN_AFTER_MS)
19
+ return undefined;
20
+ const minutes = Math.floor(ageMs / 60_000);
21
+ return `Session ${sessionId} has been open for ${String(minutes)} minutes. If your task is complete, call reticle_session{action:"end"} now.`;
22
+ }
@@ -1,5 +1,5 @@
1
1
  import type { InboxMessage } from './human/live-control.js';
2
- import { type Coverage, CoverageCapability, type ImpactSnapshot } from '@reticlehq/core';
2
+ import { type Coverage, CoverageCapability, type ImpactSnapshot, ENGINE_BLIND_SPOTS_FIELD, type EngineBlindSpot, type Predicate } from '@reticlehq/core';
3
3
  export interface RecordedGap {
4
4
  kind: string;
5
5
  missing: string;
@@ -46,6 +46,16 @@ export interface ProbedTab extends NotedTab {
46
46
  * True when a page showed something not known before.
47
47
  */
48
48
  export declare function probeMarkers(tabs: readonly ProbedTab[]): Promise<boolean>;
49
+ /**
50
+ * The `engineBlindSpots` field for a verdict result: what this engine could not observe in the
51
+ * session so far. Notes this verdict's own comparison first, so a `compare` clears the arithmetic
52
+ * spot on the result that ran it. `claims`: the inline intent, then the run's declared intents.
53
+ */
54
+ export declare function engineBlindSpotsField(sessionId: string, predicate: Predicate | undefined, intent: unknown, declared: readonly {
55
+ statement: string;
56
+ }[]): {
57
+ [ENGINE_BLIND_SPOTS_FIELD]: EngineBlindSpot[];
58
+ };
49
59
  /** What this session's verdicts recorded, newest first. */
50
60
  export declare function recordedGaps(sessionId: string): readonly RecordedGap[];
51
61
  /** Forget a session that ended. What its app has shown is kept: it is still that app's. */
@@ -72,22 +82,16 @@ export declare function announcedChannels(tab: InstrumentedTab): string[];
72
82
  * The platform reads the same list from the local-apps report, so both sides move together.
73
83
  */
74
84
  export declare function notApplicableOf(tab: NotedTab): CoverageCapability[];
75
- /** Whether the Harness may drive this tab's app (see core's `instrumentation-coverage.ts`), as pushed. */
76
- export interface TabHarnessGate {
77
- percent: number;
78
- unlocked: boolean;
79
- reason?: string;
80
- }
81
85
  /**
82
- * This tab's coverage and its Harness gate, with the coding-agent prompt when its verdicts recorded
83
- * any gap or the gate is shut: below the gate the prompt names every unseen capability, so there is
84
- * always something to hand the agent.
86
+ * This tab's coverage and its setup score (see core's `instrumentation-coverage.ts`), with the
87
+ * coding-agent prompt when its verdicts recorded any gap. The score is information: it never gates
88
+ * the Harness.
85
89
  */
86
90
  export declare function instrumentationOf(tab: InstrumentedTab,
87
91
  /** The app's other tabs: what any of them has seen or recorded counts, as on the platform. */
88
92
  siblings?: readonly InstrumentedTab[]): Coverage & {
89
93
  prompt?: string;
90
- harnessGate: TabHarnessGate;
94
+ setupScore: number;
91
95
  };
92
96
  /**
93
97
  * The impact snapshot a tab is pushed, carrying that tab's own coverage, running drive and agent
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { withRunningDrive } from '../../features/harness/drive-runs.js';
10
10
  import { agentLinkOf } from './agent-link.js';
11
- import { CoverageMarker, InstrumentationGapKind, LINK_APP_GAPS_MAX, ReticleCommand, agentPromptFor, coverageOf, harnessGateOf, harnessUnlockPrompt, CoverageCapability, } from '@reticlehq/core';
11
+ import { CoverageMarker, InstrumentationGapKind, LINK_APP_GAPS_MAX, ReticleCommand, agentPromptFor, coverageOf, coveragePercent, CoverageCapability, ENGINE_BLIND_SPOTS_FIELD, computesComparison, engineBlindSpots, } from '@reticlehq/core';
12
12
  const bySession = new Map();
13
13
  const text = (value) => 'string' === typeof value && 0 < value.length ? value : undefined;
14
14
  /** Remember gaps a verdict on this session just reported. Malformed entries are skipped. */
@@ -90,6 +90,13 @@ export function noteActedElement(tab, result) {
90
90
  return;
91
91
  const acted = result;
92
92
  noteTestidSeen(tab, text(acted['testid']));
93
+ // An action that ran with a canvas on screen: its pixels go unobserved for this run.
94
+ const effect = acted['effect'];
95
+ const canvases = 'object' === typeof effect && null !== effect
96
+ ? effect['canvases']
97
+ : undefined;
98
+ if ('number' === typeof canvases && 0 < canvases)
99
+ canvasSeen.add(tab.id);
93
100
  const source = acted['source'];
94
101
  if ('object' === typeof source && null !== source) {
95
102
  const file = text(source['file']);
@@ -146,6 +153,29 @@ export async function probeMarkers(tabs) {
146
153
  }));
147
154
  return before < sourceSeen.size + testidSeen.size;
148
155
  }
156
+ /**
157
+ * Sessions where an action ran with a canvas on screen, and sessions where a verdict ran a computed
158
+ * comparison. Facts about a RUN, so a reload (a new HELLO under the same id) does not clear them.
159
+ */
160
+ const canvasSeen = new Set();
161
+ const comparedSeen = new Set();
162
+ /**
163
+ * The `engineBlindSpots` field for a verdict result: what this engine could not observe in the
164
+ * session so far. Notes this verdict's own comparison first, so a `compare` clears the arithmetic
165
+ * spot on the result that ran it. `claims`: the inline intent, then the run's declared intents.
166
+ */
167
+ export function engineBlindSpotsField(sessionId, predicate, intent, declared) {
168
+ if (computesComparison(predicate))
169
+ comparedSeen.add(sessionId);
170
+ const claims = [text(intent), ...declared.map((each) => each.statement)];
171
+ return {
172
+ [ENGINE_BLIND_SPOTS_FIELD]: engineBlindSpots({
173
+ canvasSeen: canvasSeen.has(sessionId),
174
+ compared: comparedSeen.has(sessionId),
175
+ claims,
176
+ }),
177
+ };
178
+ }
149
179
  /** What this session's verdicts recorded, newest first. */
150
180
  export function recordedGaps(sessionId) {
151
181
  return bySession.get(sessionId) ?? [];
@@ -162,6 +192,8 @@ export function forgetAllRecordedGaps() {
162
192
  sourceSeen.clear();
163
193
  testidSeen.clear();
164
194
  sourceNotApplicable.clear();
195
+ canvasSeen.clear();
196
+ comparedSeen.clear();
165
197
  }
166
198
  /**
167
199
  * The tab's HELLO channels, plus the `source` marker when an act or verdict mapped a control to
@@ -204,9 +236,9 @@ export function notApplicableOf(tab) {
204
236
  : [];
205
237
  }
206
238
  /**
207
- * This tab's coverage and its Harness gate, with the coding-agent prompt when its verdicts recorded
208
- * any gap or the gate is shut: below the gate the prompt names every unseen capability, so there is
209
- * always something to hand the agent.
239
+ * This tab's coverage and its setup score (see core's `instrumentation-coverage.ts`), with the
240
+ * coding-agent prompt when its verdicts recorded any gap. The score is information: it never gates
241
+ * the Harness.
210
242
  */
211
243
  export function instrumentationOf(tab,
212
244
  /** The app's other tabs: what any of them has seen or recorded counts, as on the platform. */
@@ -220,21 +252,10 @@ siblings = []) {
220
252
  const url = tab.url ?? '';
221
253
  const appName = appNameOf(url);
222
254
  const notApplicable = notApplicableOf(tab);
223
- const gate = harnessGateOf(coverage, notApplicable);
224
- const harnessGate = {
225
- percent: gate.percent,
226
- unlocked: gate.unlocked,
227
- ...(gate.reason === undefined ? {} : { reason: gate.reason }),
228
- };
229
- if (!gate.unlocked)
230
- return {
231
- ...coverage,
232
- harnessGate,
233
- prompt: harnessUnlockPrompt({ coverage, gaps, appName, url, notApplicable }),
234
- };
255
+ const setupScore = coveragePercent(coverage, notApplicable);
235
256
  return 0 === gaps.length
236
- ? { ...coverage, harnessGate }
237
- : { ...coverage, harnessGate, prompt: agentPromptFor({ gaps, appName, url }) };
257
+ ? { ...coverage, setupScore }
258
+ : { ...coverage, setupScore, prompt: agentPromptFor({ gaps, appName, url }) };
238
259
  }
239
260
  /**
240
261
  * The impact snapshot a tab is pushed, carrying that tab's own coverage, running drive and agent
@@ -8,13 +8,24 @@
8
8
  * which `memory/project` has no business knowing. The resolver takes the answer as an injected
9
9
  * function; the composition roots pass this one.
10
10
  */
11
- import { type DevServerEntry } from '@reticlehq/core';
11
+ import { type Checkout, type DevServerEntry } from '@reticlehq/core';
12
+ import { type CheckoutSource } from './session-manager.js';
12
13
  /** Where `servingDirectoryOf` gets its two observations. Injected so a test needs no processes. */
13
14
  export interface ServingDirectoryIo {
14
15
  /** Live dev servers that announced themselves (the Vite plugin writes `devserver-<port>.json`). */
15
16
  devServers: () => readonly DevServerEntry[];
16
17
  /** The working directory of whatever listens on `port`, or null when it cannot be read. */
17
18
  listenerCwd: (port: number) => string | null;
19
+ /** A running dev proxy that serves names under `.localhost`, or undefined when there is none. */
20
+ devProxy?: () => DevProxy | undefined;
21
+ }
22
+ /** A dev proxy: the ports it listens on, and the dev server port behind each name it serves. */
23
+ export interface DevProxy {
24
+ ports: readonly number[];
25
+ routes: readonly {
26
+ hostname: string;
27
+ port: number;
28
+ }[];
18
29
  }
19
30
  /**
20
31
  * The directory of the dev server that served `origin`, or undefined when it cannot be observed.
@@ -22,6 +33,17 @@ export interface ServingDirectoryIo {
22
33
  * Two observations, exact one first. A dev server whose plugin announced this port names its own
23
34
  * root and works on every platform. Otherwise the process listening on the port is asked for its
24
35
  * working directory, which covers frameworks with no announcing plugin (Next.js) wherever `lsof`
25
- * runs. Loopback only: a remote page's port says nothing about any process on this machine.
36
+ * runs. Behind a dev proxy, the proxy's route table first names the dev server's own port. Loopback
37
+ * only: a remote page's port says nothing about any process on this machine.
26
38
  */
27
39
  export declare function servingDirectoryOf(origin: string, io?: ServingDirectoryIo): string | undefined;
40
+ /**
41
+ * The live answers for a worktree-scoped resolve: the calling agent's checkout (from the directory
42
+ * its MCP proxy runs in) and each tab's checkout (from the dev server that served it).
43
+ *
44
+ * A tab is placed once for each connection. A page that a different dev server serves has reloaded,
45
+ * and a reload is a new connection. A cache by origin and time named a port that moved to another
46
+ * worktree after the old one for its whole lifetime.
47
+ * ponytail: a lookup that failed stays failed for that connection; the tab then counts as unknown.
48
+ */
49
+ export declare function liveCheckoutSource(placeOrigin?: (origin: string) => Checkout | undefined): CheckoutSource;