@reticlehq/server 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (721) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +123 -116
  3. package/dist/chromium-launch-options.d.ts +3 -1
  4. package/dist/chromium-launch-options.js +2 -1
  5. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  6. package/dist/command/cli/adhoc-suite.js +42 -7
  7. package/dist/command/cli/adhoc-verdict.d.ts +19 -2
  8. package/dist/command/cli/adhoc-verdict.js +76 -9
  9. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  10. package/dist/command/cli/answers/gate-exit.js +45 -0
  11. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  12. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  13. package/dist/command/cli/answers/open-note.d.ts +2 -0
  14. package/dist/command/cli/answers/open-note.js +22 -0
  15. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  16. package/dist/command/cli/auth/device-flow.js +17 -0
  17. package/dist/command/cli/cli-doctor.js +14 -0
  18. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  19. package/dist/command/cli/cli-flow-commands.js +31 -112
  20. package/dist/command/cli/cli-kill.js +3 -2
  21. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  22. package/dist/command/cli/cli-parse-grammar.js +75 -0
  23. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  24. package/dist/command/cli/cli-parse-verify.js +18 -0
  25. package/dist/command/cli/cli-parse.d.ts +19 -28
  26. package/dist/command/cli/cli-parse.js +82 -182
  27. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  28. package/dist/command/cli/cli-update-commands.js +61 -9
  29. package/dist/command/cli/cli-usage.d.ts +33 -0
  30. package/dist/command/cli/cli-usage.js +287 -0
  31. package/dist/command/cli/cli-verify.d.ts +35 -5
  32. package/dist/command/cli/cli-verify.js +114 -35
  33. package/dist/command/cli/cloud-cli.d.ts +13 -0
  34. package/dist/command/cli/cloud-cli.js +192 -341
  35. package/dist/command/cli/cloud-kit.d.ts +12 -0
  36. package/dist/command/cli/cloud-kit.js +41 -2
  37. package/dist/command/cli/cloud-link.d.ts +57 -0
  38. package/dist/command/cli/cloud-link.js +308 -0
  39. package/dist/command/cli/cloud-login.d.ts +22 -0
  40. package/dist/command/cli/cloud-login.js +96 -8
  41. package/dist/command/cli/context-command.d.ts +1 -0
  42. package/dist/command/cli/context-command.js +33 -0
  43. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  44. package/dist/command/cli/daemon-start-options.js +24 -3
  45. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
  46. package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
  47. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  48. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  49. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  50. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  51. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  52. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  53. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  54. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  55. package/dist/command/cli/drive/drive-attach.d.ts +27 -2
  56. package/dist/command/cli/drive/drive-attach.js +71 -4
  57. package/dist/command/cli/drive/drive-command.d.ts +2 -1
  58. package/dist/command/cli/drive/drive-command.js +13 -7
  59. package/dist/command/cli/known-regression.d.ts +13 -0
  60. package/dist/command/cli/known-regression.js +34 -0
  61. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  62. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  63. package/dist/command/cli/lifecycle/daemon-lifecycle.js +15 -3
  64. package/dist/command/cli/mcp-command.d.ts +6 -0
  65. package/dist/command/cli/mcp-command.js +13 -5
  66. package/dist/command/cli/ports/port-holder.d.ts +10 -0
  67. package/dist/command/cli/ports/port-holder.js +25 -1
  68. package/dist/command/cli/project-name.d.ts +29 -1
  69. package/dist/command/cli/project-name.js +107 -2
  70. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  71. package/dist/command/cli/setup-mcp-cli.js +35 -12
  72. package/dist/command/cli/status/status-lines.d.ts +1 -0
  73. package/dist/command/cli/status/status-lines.js +47 -2
  74. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  75. package/dist/command/cli/status/workspace-links.js +29 -0
  76. package/dist/command/cli/try-command.d.ts +96 -0
  77. package/dist/command/cli/try-command.js +362 -0
  78. package/dist/command/cli/tutorial.d.ts +0 -100
  79. package/dist/command/cli/tutorial.js +0 -181
  80. package/dist/command/cli/verify-results.d.ts +19 -0
  81. package/dist/command/cli/verify-results.js +29 -0
  82. package/dist/command/cli-onboarding.d.ts +0 -11
  83. package/dist/command/cli-onboarding.js +0 -15
  84. package/dist/command/cli.d.ts +20 -0
  85. package/dist/command/cli.js +130 -104
  86. package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
  87. package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
  88. package/dist/command/daemon/daemon-resilience.js +4 -4
  89. package/dist/command/daemon/daemon-resolve.d.ts +23 -1
  90. package/dist/command/daemon/daemon-resolve.js +79 -9
  91. package/dist/command/setup/agent-writer.d.ts +1 -1
  92. package/dist/command/setup/agent-writer.js +3 -2
  93. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  94. package/dist/command/setup/bringup/bridge-port.js +13 -3
  95. package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
  96. package/dist/command/setup/bringup/connect-lease.js +1 -0
  97. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  98. package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
  99. package/dist/command/setup/bringup/dev-server-wait.js +19 -0
  100. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  101. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  102. package/dist/command/setup/init/agent-restart.js +28 -0
  103. package/dist/command/setup/init/init-port.d.ts +14 -1
  104. package/dist/command/setup/init/init-port.js +32 -2
  105. package/dist/command/setup/init/init-runtime.d.ts +22 -2
  106. package/dist/command/setup/init/init-runtime.js +114 -38
  107. package/dist/command/setup/node-effects.d.ts +2 -0
  108. package/dist/command/setup/node-effects.js +38 -9
  109. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  110. package/dist/command/setup/probe/existing-app.js +14 -0
  111. package/dist/command/setup/remaining-steps.js +2 -1
  112. package/dist/command/setup/run-setup.d.ts +34 -9
  113. package/dist/command/setup/run-setup.js +65 -51
  114. package/dist/command/setup/setup-command.d.ts +25 -1
  115. package/dist/command/setup/setup-command.js +59 -4
  116. package/dist/command/setup/setup-mcp.js +25 -2
  117. package/dist/command/setup/tauri-signing.d.ts +19 -0
  118. package/dist/command/setup/tauri-signing.js +79 -0
  119. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  120. package/dist/command/setup/terminal/listeners.js +37 -6
  121. package/dist/command/update/update-nudge.d.ts +9 -0
  122. package/dist/command/update/update-nudge.js +1 -1
  123. package/dist/command/update/updater.js +11 -15
  124. package/dist/command/version/version-nudge.js +3 -0
  125. package/dist/command/version/version-skew.d.ts +20 -1
  126. package/dist/command/version/version-skew.js +49 -4
  127. package/dist/features/crawl/crawl-tools.js +4 -0
  128. package/dist/features/crawl/crawl.d.ts +6 -0
  129. package/dist/features/crawl/crawl.js +23 -2
  130. package/dist/features/exhaust/ledger.d.ts +21 -14
  131. package/dist/features/exhaust/ledger.js +35 -9
  132. package/dist/features/harness/app-findings.d.ts +2 -0
  133. package/dist/features/harness/app-findings.js +52 -0
  134. package/dist/features/harness/drive-report.d.ts +61 -1
  135. package/dist/features/harness/drive-report.js +394 -26
  136. package/dist/features/harness/drive-runs.d.ts +120 -0
  137. package/dist/features/harness/drive-runs.js +289 -0
  138. package/dist/features/harness/drivers.d.ts +10 -14
  139. package/dist/features/harness/drivers.js +10 -14
  140. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  141. package/dist/features/harness/explore/console-pages.js +146 -0
  142. package/dist/features/harness/explore/disparity.d.ts +19 -0
  143. package/dist/features/harness/explore/disparity.js +71 -0
  144. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  145. package/dist/features/harness/explore/fake-app.js +49 -0
  146. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  147. package/dist/features/harness/explore/goal-search.js +144 -0
  148. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  149. package/dist/features/harness/explore/page-tree.js +148 -0
  150. package/dist/features/harness/explore/site-map.d.ts +34 -0
  151. package/dist/features/harness/explore/site-map.js +150 -0
  152. package/dist/features/harness/fill-values.d.ts +3 -73
  153. package/dist/features/harness/fill-values.js +3 -169
  154. package/dist/features/harness/goals.d.ts +82 -0
  155. package/dist/features/harness/goals.js +330 -0
  156. package/dist/features/harness/harness.d.ts +51 -1
  157. package/dist/features/harness/harness.js +207 -6
  158. package/dist/features/harness/platform/drive-target.d.ts +30 -0
  159. package/dist/features/harness/platform/drive-target.js +81 -0
  160. package/dist/features/harness/platform/local-apps.d.ts +127 -0
  161. package/dist/features/harness/platform/local-apps.js +280 -0
  162. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  163. package/dist/features/harness/platform/persona-credentials.js +69 -0
  164. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  165. package/dist/features/harness/platform/platform-drives.js +114 -0
  166. package/dist/features/harness/platform/refusal.d.ts +52 -0
  167. package/dist/features/harness/platform/refusal.js +71 -0
  168. package/dist/features/harness/platform/remote-drive.d.ts +186 -0
  169. package/dist/features/harness/platform/remote-drive.js +378 -0
  170. package/dist/features/harness/platform/script.d.ts +94 -0
  171. package/dist/features/harness/platform/script.js +260 -0
  172. package/dist/features/harness/platform/server-driver.d.ts +54 -0
  173. package/dist/features/harness/platform/server-driver.js +182 -0
  174. package/dist/features/harness/platform-config.d.ts +41 -1
  175. package/dist/features/harness/platform-config.js +106 -9
  176. package/dist/features/harness/route-guess.d.ts +13 -0
  177. package/dist/features/harness/route-guess.js +49 -0
  178. package/dist/features/harness/script/app-controls.d.ts +5 -0
  179. package/dist/features/harness/script/app-controls.js +40 -0
  180. package/dist/features/harness/script/lane-ids.d.ts +14 -0
  181. package/dist/features/harness/script/lane-ids.js +16 -0
  182. package/dist/features/harness/script/script-run.d.ts +70 -0
  183. package/dist/features/harness/script/script-run.js +606 -0
  184. package/dist/features/license/license.d.ts +2 -2
  185. package/dist/features/visual/step-shots.d.ts +31 -0
  186. package/dist/features/visual/step-shots.js +231 -0
  187. package/dist/features/visual/visual-tools.d.ts +10 -1
  188. package/dist/features/visual/visual-tools.js +62 -17
  189. package/dist/hooks/client-directory.d.ts +18 -0
  190. package/dist/hooks/client-directory.js +57 -0
  191. package/dist/hooks/coding-agents.d.ts +34 -0
  192. package/dist/hooks/coding-agents.js +117 -0
  193. package/dist/hooks/driven-by.d.ts +23 -0
  194. package/dist/hooks/driven-by.js +56 -0
  195. package/dist/hooks/hook-bus.d.ts +4 -0
  196. package/dist/hooks/hook-bus.js +18 -0
  197. package/dist/hooks/hook-commands.js +15 -4
  198. package/dist/hooks/tool-log.d.ts +9 -0
  199. package/dist/hooks/tool-log.js +29 -0
  200. package/dist/index.d.ts +2 -0
  201. package/dist/index.js +80 -243
  202. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  203. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  204. package/dist/judgement/capsule/causal-summary.js +33 -0
  205. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  206. package/dist/judgement/runs/artifact/build-verification-run.js +25 -3
  207. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  208. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  209. package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
  210. package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
  211. package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
  212. package/dist/judgement/runs/artifact/run-store.js +195 -3
  213. package/dist/judgement/runs/context-tools.js +59 -1
  214. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  215. package/dist/judgement/runs/default-run-id.js +16 -0
  216. package/dist/judgement/runs/drive-run.d.ts +71 -1
  217. package/dist/judgement/runs/drive-run.js +317 -5
  218. package/dist/judgement/runs/repair-prompt.js +1 -1
  219. package/dist/judgement/runs/resume.d.ts +44 -0
  220. package/dist/judgement/runs/resume.js +137 -0
  221. package/dist/judgement/runs/reticle-runner.js +13 -3
  222. package/dist/judgement/runs/runner-port.d.ts +5 -1
  223. package/dist/judgement/runs/runner-port.js +8 -2
  224. package/dist/judgement/runs/verification-sync.d.ts +5 -2
  225. package/dist/judgement/runs/verification-sync.js +40 -18
  226. package/dist/language/flows/change/gate.d.ts +10 -0
  227. package/dist/language/flows/change/gate.js +22 -0
  228. package/dist/language/flows/decision.js +36 -1
  229. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  230. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  231. package/dist/language/flows/flow-anchor.d.ts +61 -10
  232. package/dist/language/flows/flow-anchor.js +98 -6
  233. package/dist/language/flows/flow-cross-step.d.ts +15 -0
  234. package/dist/language/flows/flow-cross-step.js +21 -0
  235. package/dist/language/flows/flow-intent.d.ts +1 -0
  236. package/dist/language/flows/flow-journey.d.ts +6 -0
  237. package/dist/language/flows/flow-journey.js +20 -0
  238. package/dist/language/flows/flow-learning.d.ts +4 -0
  239. package/dist/language/flows/flow-learning.js +45 -14
  240. package/dist/language/flows/flow-mutate-tools.js +5 -3
  241. package/dist/language/flows/flow-replay-run.d.ts +23 -9
  242. package/dist/language/flows/flow-replay-run.js +115 -110
  243. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  244. package/dist/language/flows/flow-replay.d.ts +40 -1
  245. package/dist/language/flows/flow-replay.js +110 -22
  246. package/dist/language/flows/flow-result.d.ts +22 -1
  247. package/dist/language/flows/flow-result.js +47 -2
  248. package/dist/language/flows/flow-scope.js +5 -1
  249. package/dist/language/flows/flow-step-runners.d.ts +22 -2
  250. package/dist/language/flows/flow-step-runners.js +247 -47
  251. package/dist/language/flows/flow-store-for-session.d.ts +2 -2
  252. package/dist/language/flows/flow-store-for-session.js +7 -3
  253. package/dist/language/flows/flow-tools.d.ts +10 -0
  254. package/dist/language/flows/flow-tools.js +112 -89
  255. package/dist/language/flows/flows.d.ts +16 -1
  256. package/dist/language/flows/flows.js +74 -12
  257. package/dist/language/flows/heal-run.js +6 -4
  258. package/dist/language/flows/narrow-write.d.ts +7 -0
  259. package/dist/language/flows/narrow-write.js +36 -1
  260. package/dist/language/flows/recording/flake.d.ts +2 -2
  261. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  262. package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
  263. package/dist/language/flows/recording/tape/recordings.js +95 -13
  264. package/dist/language/flows/replay-from-hud.d.ts +20 -0
  265. package/dist/language/flows/replay-from-hud.js +51 -0
  266. package/dist/language/flows/replay.d.ts +9 -5
  267. package/dist/language/flows/replay.js +56 -15
  268. package/dist/language/flows/single-replay.d.ts +7 -0
  269. package/dist/language/flows/single-replay.js +26 -0
  270. package/dist/language/flows/suite/suite-flakes.js +2 -0
  271. package/dist/language/flows/suite-selection.d.ts +2 -15
  272. package/dist/language/flows/suite-selection.js +4 -3
  273. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  274. package/dist/language/flows/verify-change-tools.js +202 -191
  275. package/dist/launch-chromium.d.ts +27 -5
  276. package/dist/launch-chromium.js +38 -8
  277. package/dist/memory/cloud/cloud-config.d.ts +22 -1
  278. package/dist/memory/cloud/cloud-config.js +34 -5
  279. package/dist/memory/cloud/cloud-sync.d.ts +17 -14
  280. package/dist/memory/cloud/cloud-sync.js +15 -4
  281. package/dist/memory/cloud/harness-config.d.ts +75 -1
  282. package/dist/memory/cloud/harness-config.js +115 -24
  283. package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
  284. package/dist/memory/cloud/hud-notices-source.js +128 -0
  285. package/dist/memory/cloud/memory-scope.d.ts +161 -0
  286. package/dist/memory/cloud/memory-scope.js +227 -0
  287. package/dist/memory/cloud/sync-cycle.d.ts +44 -7
  288. package/dist/memory/cloud/sync-cycle.js +129 -15
  289. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  290. package/dist/memory/cloud/sync-daemon.js +121 -9
  291. package/dist/memory/cloud/sync-disk.d.ts +1 -1
  292. package/dist/memory/cloud/sync-disk.js +31 -10
  293. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  294. package/dist/memory/cloud/sync-screenshots.js +105 -0
  295. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  296. package/dist/memory/cloud/unsynced-roots.js +166 -0
  297. package/dist/memory/impact/account-watch.d.ts +34 -0
  298. package/dist/memory/impact/account-watch.js +59 -0
  299. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  300. package/dist/memory/impact/impact-recorder.js +12 -2
  301. package/dist/memory/impact/impact-store.d.ts +17 -4
  302. package/dist/memory/impact/impact-store.js +169 -63
  303. package/dist/memory/intent/inline-intent.d.ts +1 -0
  304. package/dist/memory/intent/intent-shard-store.js +16 -4
  305. package/dist/memory/intent/intent-shard.d.ts +14 -2
  306. package/dist/memory/intent/intent-store.d.ts +1 -0
  307. package/dist/memory/intent/intent-tools.js +122 -4
  308. package/dist/memory/intent/open-intents.d.ts +6 -0
  309. package/dist/memory/intent/open-intents.js +10 -1
  310. package/dist/memory/intent/settled-words.d.ts +24 -0
  311. package/dist/memory/intent/settled-words.js +130 -0
  312. package/dist/memory/journal/drive-flow.d.ts +16 -0
  313. package/dist/memory/journal/drive-flow.js +34 -2
  314. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  315. package/dist/memory/journal/drive-run-flush.js +20 -5
  316. package/dist/memory/journal/envelope.d.ts +8 -8
  317. package/dist/memory/journal/journal-recorder.js +52 -3
  318. package/dist/memory/journal/on-disk/retention.d.ts +8 -0
  319. package/dist/memory/journal/on-disk/retention.js +32 -2
  320. package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
  321. package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
  322. package/dist/memory/journal/session-end.d.ts +15 -1
  323. package/dist/memory/journal/session-end.js +42 -9
  324. package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
  325. package/dist/memory/project/artifact-root-resolver.js +125 -16
  326. package/dist/memory/project/artifact-root.d.ts +46 -8
  327. package/dist/memory/project/artifact-root.js +89 -10
  328. package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
  329. package/dist/memory/project/dir/reticle-dir.js +26 -3
  330. package/dist/memory/project/link-directory.d.ts +15 -0
  331. package/dist/memory/project/link-directory.js +44 -0
  332. package/dist/memory/project/project-tools.js +22 -3
  333. package/dist/memory/project/root-claims.d.ts +6 -0
  334. package/dist/memory/project/root-claims.js +39 -0
  335. package/dist/memory/project/session-root.d.ts +26 -1
  336. package/dist/memory/project/session-root.js +49 -5
  337. package/dist/memory/project/sync-status.d.ts +85 -0
  338. package/dist/memory/project/sync-status.js +224 -0
  339. package/dist/memory/recall/memory-tools.js +47 -2
  340. package/dist/memory/recall/platform-memory.d.ts +34 -0
  341. package/dist/memory/recall/platform-memory.js +139 -0
  342. package/dist/memory/recall/project-memory.d.ts +19 -0
  343. package/dist/memory/recall/project-memory.js +80 -13
  344. package/dist/portal/bridge/bridge.d.ts +9 -3
  345. package/dist/portal/bridge/bridge.js +82 -22
  346. package/dist/portal/bridge/harness-request.d.ts +23 -0
  347. package/dist/portal/bridge/harness-request.js +27 -0
  348. package/dist/portal/bridge/pairing-token.d.ts +9 -0
  349. package/dist/portal/bridge/pairing-token.js +17 -0
  350. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  351. package/dist/portal/bridge/wrong-path.js +35 -0
  352. package/dist/portal/input/network-mock-tools.js +11 -2
  353. package/dist/portal/input/real-input.d.ts +83 -10
  354. package/dist/portal/input/real-input.js +218 -30
  355. package/dist/portal/input/viewport-tools.js +3 -3
  356. package/dist/portal/pool/browser-pool.d.ts +70 -9
  357. package/dist/portal/pool/browser-pool.js +190 -37
  358. package/dist/portal/pool/context-permissions.d.ts +33 -0
  359. package/dist/portal/pool/context-permissions.js +33 -0
  360. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  361. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  362. package/dist/portal/pool/playwright-launcher.d.ts +35 -0
  363. package/dist/portal/pool/playwright-launcher.js +64 -3
  364. package/dist/portal/pool/pool-contract.d.ts +28 -5
  365. package/dist/portal/session/agent-link.d.ts +8 -0
  366. package/dist/portal/session/agent-link.js +17 -0
  367. package/dist/portal/session/command-payload.d.ts +8 -0
  368. package/dist/portal/session/command-payload.js +24 -0
  369. package/dist/portal/session/daemon-answers.d.ts +3 -3
  370. package/dist/portal/session/daemon-answers.js +4 -2
  371. package/dist/portal/session/dev-server/dev-command.d.ts +21 -0
  372. package/dist/portal/session/dev-server/dev-command.js +87 -12
  373. package/dist/portal/session/facts/departure-note.d.ts +22 -0
  374. package/dist/portal/session/facts/departure-note.js +47 -0
  375. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  376. package/dist/portal/session/facts/observed-state.js +46 -3
  377. package/dist/portal/session/facts/session-replaced.d.ts +5 -0
  378. package/dist/portal/session/facts/session-replaced.js +5 -0
  379. package/dist/portal/session/first-run-wiring.d.ts +42 -0
  380. package/dist/portal/session/first-run-wiring.js +132 -0
  381. package/dist/portal/session/human/live-control.d.ts +9 -2
  382. package/dist/portal/session/human/live-control.js +12 -3
  383. package/dist/portal/session/human/notes-ledger.d.ts +20 -0
  384. package/dist/portal/session/human/notes-ledger.js +55 -0
  385. package/dist/portal/session/human/review-store.d.ts +12 -0
  386. package/dist/portal/session/human/review-store.js +18 -10
  387. package/dist/portal/session/live-control-tools.d.ts +0 -13
  388. package/dist/portal/session/live-control-tools.js +107 -13
  389. package/dist/portal/session/narration-args.d.ts +5 -0
  390. package/dist/portal/session/narration-args.js +17 -0
  391. package/dist/portal/session/no-session-diagnosis.d.ts +8 -1
  392. package/dist/portal/session/no-session-diagnosis.js +46 -9
  393. package/dist/portal/session/no-session-next-action.d.ts +31 -0
  394. package/dist/portal/session/no-session-next-action.js +159 -60
  395. package/dist/portal/session/no-session-watch.d.ts +14 -1
  396. package/dist/portal/session/no-session-watch.js +227 -17
  397. package/dist/portal/session/presence/session-lease.js +1 -1
  398. package/dist/portal/session/presence/session-mirror.js +3 -0
  399. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  400. package/dist/portal/session/recorded-gaps.js +251 -0
  401. package/dist/portal/session/serving-directory.d.ts +27 -0
  402. package/dist/portal/session/serving-directory.js +45 -0
  403. package/dist/portal/session/session-health.d.ts +18 -0
  404. package/dist/portal/session/session-health.js +9 -1
  405. package/dist/portal/session/session-info.d.ts +8 -1
  406. package/dist/portal/session/session-info.js +8 -1
  407. package/dist/portal/session/session-manager.d.ts +39 -0
  408. package/dist/portal/session/session-manager.js +98 -11
  409. package/dist/portal/session/session-reaper.js +4 -1
  410. package/dist/portal/session/session-successor.d.ts +13 -0
  411. package/dist/portal/session/session-successor.js +1 -1
  412. package/dist/portal/session/session-tools.js +26 -3
  413. package/dist/portal/session/session.d.ts +22 -30
  414. package/dist/portal/session/session.js +81 -79
  415. package/dist/portal/session/timing/command-timeout.js +25 -1
  416. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  417. package/dist/portal/session/timing/wall-clock.js +1 -1
  418. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  419. package/dist/portal/session/zero-install-first-call.js +88 -0
  420. package/dist/start-options.d.ts +12 -0
  421. package/dist/start-wiring.d.ts +63 -0
  422. package/dist/start-wiring.js +169 -0
  423. package/dist/status-payload.d.ts +23 -1
  424. package/dist/status-payload.js +36 -1
  425. package/dist/surface/http-server.js +18 -2
  426. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  427. package/dist/surface/mcp/attach-memory.js +12 -1
  428. package/dist/surface/mcp/mcp-proxy.d.ts +9 -0
  429. package/dist/surface/mcp/mcp-proxy.js +65 -13
  430. package/dist/surface/mcp/mcp.d.ts +34 -6
  431. package/dist/surface/mcp/mcp.js +61 -17
  432. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  433. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  434. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  435. package/dist/surface/mcp/server-instructions.d.ts +4 -2
  436. package/dist/surface/mcp/server-instructions.js +32 -14
  437. package/dist/surface/mcp/shared-params.js +2 -2
  438. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  439. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  440. package/dist/surface/tools/account-tool.d.ts +22 -0
  441. package/dist/surface/tools/account-tool.js +157 -0
  442. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  443. package/dist/surface/tools/act/act-danger.js +38 -1
  444. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  445. package/dist/surface/tools/act/act-observation.js +57 -0
  446. package/dist/surface/tools/act/act-preflight.js +25 -2
  447. package/dist/surface/tools/act/act-target.js +8 -3
  448. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
  449. package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
  450. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  451. package/dist/surface/tools/act/resolve-target.js +18 -3
  452. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  453. package/dist/surface/tools/act/screen-request.js +113 -0
  454. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  455. package/dist/surface/tools/act/sequence-grade.js +13 -2
  456. package/dist/surface/tools/act/settle-in-flight.js +25 -3
  457. package/dist/surface/tools/act-sequence-tool.js +138 -29
  458. package/dist/surface/tools/act-tools.d.ts +0 -9
  459. package/dist/surface/tools/act-tools.js +71 -41
  460. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  461. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  462. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  463. package/dist/surface/tools/agent/app-notes.js +48 -0
  464. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  465. package/dist/surface/tools/agent/build-staleness.js +62 -0
  466. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  467. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  468. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  469. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  470. package/dist/surface/tools/agent/notices.d.ts +50 -0
  471. package/dist/surface/tools/agent/notices.js +152 -0
  472. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  473. package/dist/surface/tools/agent/reteach.js +50 -0
  474. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  475. package/dist/surface/tools/args/alias-args.js +10 -0
  476. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  477. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  478. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  479. package/dist/surface/tools/assert/assert-source.js +40 -0
  480. package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
  481. package/dist/surface/tools/assert/assert-verdict.js +42 -17
  482. package/dist/surface/tools/browser-tools.js +51 -2
  483. package/dist/surface/tools/chat-drives.d.ts +101 -0
  484. package/dist/surface/tools/chat-drives.js +409 -0
  485. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  486. package/dist/surface/tools/coverage-tools.js +2 -53
  487. package/dist/surface/tools/dynamic-tools.js +29 -1
  488. package/dist/surface/tools/empty-session-list.d.ts +51 -0
  489. package/dist/surface/tools/empty-session-list.js +120 -0
  490. package/dist/surface/tools/error-recovery.d.ts +14 -0
  491. package/dist/surface/tools/error-recovery.js +105 -8
  492. package/dist/surface/tools/explore-tools.d.ts +31 -1
  493. package/dist/surface/tools/explore-tools.js +438 -66
  494. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  495. package/dist/surface/tools/feedback-tools.js +18 -3
  496. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  497. package/dist/surface/tools/gap-novelty.js +8 -1
  498. package/dist/surface/tools/harness-explore.d.ts +118 -57
  499. package/dist/surface/tools/harness-explore.js +344 -292
  500. package/dist/surface/tools/harness-gate.d.ts +88 -0
  501. package/dist/surface/tools/harness-gate.js +235 -0
  502. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  503. package/dist/surface/tools/harness-hunt.js +215 -0
  504. package/dist/surface/tools/harness-plan.d.ts +17 -0
  505. package/dist/surface/tools/harness-plan.js +38 -0
  506. package/dist/surface/tools/harness-script.d.ts +30 -0
  507. package/dist/surface/tools/harness-script.js +560 -0
  508. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  509. package/dist/surface/tools/harness-tab-guard.js +27 -0
  510. package/dist/surface/tools/harness-toolset.d.ts +22 -1
  511. package/dist/surface/tools/harness-toolset.js +101 -7
  512. package/dist/surface/tools/human-notes.d.ts +16 -0
  513. package/dist/surface/tools/human-notes.js +27 -0
  514. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  515. package/dist/surface/tools/invoke-tool.js +263 -85
  516. package/dist/surface/tools/lease-hint.js +26 -5
  517. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  518. package/dist/surface/tools/lease-permissions.js +73 -0
  519. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  520. package/dist/surface/tools/lease-readiness.js +57 -0
  521. package/dist/surface/tools/lease-seed.d.ts +49 -0
  522. package/dist/surface/tools/lease-seed.js +167 -0
  523. package/dist/surface/tools/lease-tools.d.ts +13 -24
  524. package/dist/surface/tools/lease-tools.js +146 -197
  525. package/dist/surface/tools/live-call-text.js +4 -4
  526. package/dist/surface/tools/merge-tools.js +42 -2
  527. package/dist/surface/tools/merged-name-redirect.js +4 -0
  528. package/dist/surface/tools/next-step.d.ts +29 -0
  529. package/dist/surface/tools/next-step.js +214 -0
  530. package/dist/surface/tools/observe-tools.js +45 -9
  531. package/dist/surface/tools/platform-moment.d.ts +72 -0
  532. package/dist/surface/tools/platform-moment.js +296 -0
  533. package/dist/surface/tools/query-hint-schema.d.ts +7 -0
  534. package/dist/surface/tools/query-hint-schema.js +10 -0
  535. package/dist/surface/tools/read-tools.js +71 -14
  536. package/dist/surface/tools/real-input-attempt.js +96 -13
  537. package/dist/surface/tools/reticle-result.d.ts +120 -0
  538. package/dist/surface/tools/reticle-result.js +364 -0
  539. package/dist/surface/tools/tool-kit.d.ts +83 -3
  540. package/dist/surface/tools/tool-kit.js +77 -7
  541. package/dist/surface/tools/tools.js +43 -59
  542. package/dist/telemetry/account-envelope.d.ts +7 -0
  543. package/dist/telemetry/account-envelope.js +61 -0
  544. package/dist/telemetry/agent-client.d.ts +15 -0
  545. package/dist/telemetry/agent-client.js +57 -0
  546. package/dist/telemetry/app-instrumented.js +9 -2
  547. package/dist/telemetry/argument-shape.d.ts +7 -0
  548. package/dist/telemetry/argument-shape.js +86 -1
  549. package/dist/telemetry/automation-hint.d.ts +2 -3
  550. package/dist/telemetry/automation-hint.js +33 -8
  551. package/dist/telemetry/cli-telemetry.js +7 -2
  552. package/dist/telemetry/daemon-telemetry.js +3 -0
  553. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  554. package/dist/telemetry/error-fingerprint.js +61 -5
  555. package/dist/telemetry/feedback-cli.d.ts +0 -13
  556. package/dist/telemetry/feedback-cli.js +0 -77
  557. package/dist/telemetry/feedback.d.ts +13 -0
  558. package/dist/telemetry/feedback.js +183 -17
  559. package/dist/telemetry/harness-run.d.ts +18 -0
  560. package/dist/telemetry/harness-run.js +80 -0
  561. package/dist/telemetry/hud-events.d.ts +16 -0
  562. package/dist/telemetry/hud-events.js +27 -0
  563. package/dist/telemetry/hud-metrics.d.ts +29 -6
  564. package/dist/telemetry/hud-metrics.js +116 -25
  565. package/dist/telemetry/init-telemetry.js +2 -2
  566. package/dist/telemetry/install-source.d.ts +13 -25
  567. package/dist/telemetry/install-source.js +44 -3
  568. package/dist/telemetry/mcp-connection.d.ts +0 -14
  569. package/dist/telemetry/mcp-connection.js +5 -1
  570. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  571. package/dist/telemetry/onboarding-firsts.js +81 -6
  572. package/dist/telemetry/platform-linked.d.ts +5 -0
  573. package/dist/telemetry/platform-linked.js +32 -0
  574. package/dist/telemetry/project-profile.js +5 -3
  575. package/dist/telemetry/proxy-telemetry.js +4 -1
  576. package/dist/telemetry/session-metrics.d.ts +15 -4
  577. package/dist/telemetry/session-metrics.js +88 -52
  578. package/dist/telemetry/telemetry.d.ts +38 -2
  579. package/dist/telemetry/telemetry.js +144 -34
  580. package/dist/telemetry/verification-of.d.ts +3 -1
  581. package/dist/telemetry/verification-of.js +13 -4
  582. package/dist/wire-journal.d.ts +2 -2
  583. package/dist/wire-journal.js +20 -6
  584. package/docs/README.md +3 -3
  585. package/docs/actions.mdx +6 -3
  586. package/docs/adapters.md +1 -1
  587. package/docs/agent-cheatsheet.md +25 -28
  588. package/docs/architecture.md +5 -5
  589. package/docs/autodrive.md +33 -28
  590. package/docs/benchmarks.md +5 -5
  591. package/docs/best-practices.mdx +27 -9
  592. package/docs/capabilities.mdx +14 -16
  593. package/docs/cli/affected.mdx +1 -1
  594. package/docs/cli/cloud.mdx +54 -75
  595. package/docs/cli/doctor.mdx +14 -3
  596. package/docs/cli/drive.mdx +20 -14
  597. package/docs/cli/feedback.mdx +3 -3
  598. package/docs/cli/gate.mdx +7 -2
  599. package/docs/cli/help.mdx +50 -55
  600. package/docs/cli/init.mdx +43 -28
  601. package/docs/cli/license.mdx +12 -8
  602. package/docs/cli/mcp.mdx +4 -4
  603. package/docs/cli/open.mdx +3 -3
  604. package/docs/cli/report.mdx +4 -2
  605. package/docs/cli/restart.mdx +2 -2
  606. package/docs/cli/rollback.mdx +14 -8
  607. package/docs/cli/serve.mdx +4 -4
  608. package/docs/cli/setup.mdx +23 -0
  609. package/docs/cli/status.mdx +18 -5
  610. package/docs/cli/stop.mdx +67 -8
  611. package/docs/cli/try.mdx +62 -0
  612. package/docs/cli/update.mdx +4 -3
  613. package/docs/cli/verify.mdx +17 -6
  614. package/docs/cli/version.mdx +5 -4
  615. package/docs/cli.mdx +111 -42
  616. package/docs/debugging.md +3 -3
  617. package/docs/deploy-checks.md +1 -1
  618. package/docs/desktop.mdx +9 -3
  619. package/docs/enterprise.md +11 -10
  620. package/docs/environment.mdx +7 -8
  621. package/docs/faq.mdx +3 -3
  622. package/docs/first-drive.md +5 -4
  623. package/docs/flows.md +35 -27
  624. package/docs/for-agents.md +4 -5
  625. package/docs/frameworks.mdx +32 -21
  626. package/docs/getting-started.md +65 -61
  627. package/docs/human-control.md +16 -16
  628. package/docs/index.mdx +15 -42
  629. package/docs/install-agentic.mdx +22 -37
  630. package/docs/install-manual.mdx +23 -13
  631. package/docs/instrumentation.mdx +5 -3
  632. package/docs/integration-patterns.md +7 -7
  633. package/docs/license-activation.mdx +1 -1
  634. package/docs/multi-agent-testing.md +24 -6
  635. package/docs/packages/babel-plugin.mdx +4 -2
  636. package/docs/packages/browser.mdx +16 -10
  637. package/docs/packages/core.mdx +12 -5
  638. package/docs/packages/electron.mdx +3 -2
  639. package/docs/packages/engine.mdx +1 -1
  640. package/docs/packages/eslint-plugin.mdx +18 -12
  641. package/docs/packages/next.mdx +8 -7
  642. package/docs/packages/open-verification.mdx +1 -1
  643. package/docs/packages/server.mdx +5 -5
  644. package/docs/packages/tauri.mdx +9 -9
  645. package/docs/packages/test.mdx +4 -10
  646. package/docs/packages/vite-plugin.mdx +32 -4
  647. package/docs/packages.mdx +11 -15
  648. package/docs/platform-integration.md +6 -5
  649. package/docs/predicates.mdx +40 -24
  650. package/docs/quickstart.mdx +69 -30
  651. package/docs/required-checks.md +8 -7
  652. package/docs/reticle-manual.md +15 -5
  653. package/docs/skill-file.mdx +17 -79
  654. package/docs/skill-setup.md +9 -9
  655. package/docs/skill.md +200 -0
  656. package/docs/system-map.md +7 -7
  657. package/docs/telemetry.md +23 -25
  658. package/docs/testing.md +4 -4
  659. package/docs/token-efficiency.md +12 -12
  660. package/docs/tools/act-and-wait.mdx +9 -2
  661. package/docs/tools/act-sequence.mdx +6 -7
  662. package/docs/tools/act.mdx +2 -2
  663. package/docs/tools/assert.mdx +18 -17
  664. package/docs/tools/console.mdx +9 -9
  665. package/docs/tools/inspect.mdx +16 -7
  666. package/docs/tools/look.mdx +24 -0
  667. package/docs/tools/navigate.mdx +5 -3
  668. package/docs/tools/network.mdx +2 -2
  669. package/docs/tools/observe.mdx +6 -6
  670. package/docs/tools/overview.mdx +34 -33
  671. package/docs/tools/query.mdx +5 -5
  672. package/docs/tools/session-and-feedback.mdx +22 -13
  673. package/docs/tools/sessions.mdx +8 -8
  674. package/docs/tools/snapshot.mdx +6 -5
  675. package/docs/tools/state.mdx +9 -9
  676. package/docs/tools/tools-and-run.mdx +26 -24
  677. package/docs/tools/verify.mdx +28 -0
  678. package/docs/tools/wait-for.mdx +8 -4
  679. package/docs/troubleshooting.mdx +21 -6
  680. package/docs/usage.md +55 -46
  681. package/docs/use-cases.mdx +3 -3
  682. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  683. package/docs/vs-playwright-mcp.mdx +3 -1
  684. package/docs/what-is-recorded.md +17 -5
  685. package/docs/what-is-reticle.mdx +5 -3
  686. package/docs/why-reticle.mdx +1 -1
  687. package/package.json +9 -12
  688. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  689. package/dist/command/cli/demo/demo-page.js +0 -241
  690. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  691. package/dist/command/cli/demo/demo-run.js +0 -138
  692. package/dist/features/harness/driver.d.ts +0 -50
  693. package/dist/features/harness/driver.js +0 -236
  694. package/dist/features/harness/jev-driver.d.ts +0 -188
  695. package/dist/features/harness/jev-driver.js +0 -678
  696. package/dist/features/harness/openai-driver.d.ts +0 -58
  697. package/dist/features/harness/openai-driver.js +0 -206
  698. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  699. package/dist/judgement/hunt/hunt-report.js +0 -84
  700. package/dist/language/flows/buddy-status.d.ts +0 -25
  701. package/dist/language/flows/buddy-status.js +0 -32
  702. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  703. package/dist/language/flows/change/watch-batcher.js +0 -19
  704. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  705. package/dist/memory/cloud/harness-offer.js +0 -145
  706. package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
  707. package/dist/memory/project/dir/fill-value-store.js +0 -88
  708. package/dist/surface/tools/feature-capture.d.ts +0 -151
  709. package/dist/surface/tools/feature-capture.js +0 -235
  710. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  711. package/dist/surface/tools/tool-hit-rate.js +0 -90
  712. package/dist/telemetry/harness-drive.d.ts +0 -4
  713. package/dist/telemetry/harness-drive.js +0 -35
  714. package/dist/telemetry/identify.d.ts +0 -22
  715. package/dist/telemetry/identify.js +0 -73
  716. package/docs/cli/capsules.mdx +0 -70
  717. package/docs/cli/hunt.mdx +0 -73
  718. package/docs/cli/identify.mdx +0 -76
  719. package/docs/cli/kill.mdx +0 -91
  720. package/docs/cli/watch.mdx +0 -62
  721. package/docs/local-registry.md +0 -143
@@ -12,10 +12,12 @@
12
12
  * the hot resolve() path and this stays unit-testable.
13
13
  */
14
14
  import { NoSessionReason } from '@reticlehq/core/telemetry';
15
+ import { redactUrl } from '@reticlehq/core';
15
16
  import { leaseCaveat } from './presence/lease-availability.js';
16
17
  import { DEV_SERVER_PORTS } from '../../command/cli/ports/resolve/cli-port.js';
17
18
  import { siblingListenerNote } from '../../command/cli/ports/sibling-ports.js';
18
19
  import { STALL_AFTER_MS } from './stall-clock.js';
20
+ import { departedPortGone } from './no-session-next-action.js';
19
21
  import { pageTornDownWhileOn } from '@reticlehq/engine/evidence/page-teardown.js';
20
22
  /** How every hello-refusal reason the bridge records separates its cause from its fix. */
21
23
  const CAUSE_FIX_SEPARATOR = ' — ';
@@ -28,7 +30,7 @@ const NUXT = 'nuxt';
28
30
  * recovery: a message that already carries its own next action must not be handed a second, more
29
31
  * generic one that contradicts it.
30
32
  */
31
- export const SELF_RECOVERING_MARKER = 'Then call reticle_sessions again — it will appear within a second of the page loading.';
33
+ export const SELF_RECOVERING_MARKER = 'Then call reticle_session { action: "list" } again — it will appear within a second of the page loading.';
32
34
  const RETRY = SELF_RECOVERING_MARKER;
33
35
  /**
34
36
  * The no-shell path, for the branches where a BLIND lease would be wrong.
@@ -61,12 +63,21 @@ function leaseAdvice(base, facts) {
61
63
  /**
62
64
  * The way out that needs no human at all.
63
65
  *
64
- * Only offered when the app is known to carry the SDK: leasing an uninstrumented app just burns a
65
- * browser and comes back `ready:false`.
66
+ * Offered here when the app is known to carry the SDK. An app that carries none is offered
67
+ * {@link ZERO_INSTALL} instead, which says what a lease on it can and cannot see.
66
68
  */
67
69
  const SELF_SERVE = 'You do not have to wait for the human: reticle_lease {action:"acquire", url} opens a browser ' +
68
70
  'Reticle drives itself, and returns a sessionId you can use immediately (reach it with ' +
69
71
  'reticle_run {tool:"reticle_lease"} if it is not advertised directly; release it when you finish).';
72
+ /**
73
+ * The way past an app nobody wired, without waiting for the wiring.
74
+ *
75
+ * A lease on a page that never dials in hands it the zero-install reader, so an MCP-only install
76
+ * (a plugin, a hand-written `npx … mcp` config — `init` never ran) still gets a verdict on the first
77
+ * call instead of a diagnosis it stops at. The URL and the command live in the next action.
78
+ */
79
+ const ZERO_INSTALL = 'You can get a verdict NOW with nothing installed: reticle_lease on the app URL supplies the ' +
80
+ 'SDK itself (no component state or source file:line until it is wired) — the next action names it.';
70
81
  /** The hedge that is true for every vanished tab we did not watch leave. */
71
82
  const TAB_GONE_WHAT = 'The tab was closed, navigated away, or hard-reloaded.';
72
83
  /**
@@ -323,11 +334,12 @@ function alreadyListeningClause(listening) {
323
334
  return '';
324
335
  if (1 === listening.length) {
325
336
  const port = listening[0];
326
- return (` An app is already listening on ${String(port)}; just open http://localhost:${String(port)} ` +
327
- '— do not start a second stack.');
337
+ return (` Something is serving a page on :${String(port)}; it may not be this app — just open ` +
338
+ `http://localhost:${String(port)} rather than starting a second stack.`);
328
339
  }
329
- return (` An app is already listening on ${listening.join(', ')}; just open one of those URLs — do not ` +
330
- 'start a second stack.');
340
+ const ports = listening.map((p) => `:${String(p)}`).join(', ');
341
+ return (` Something is serving a page on ${ports}; those listeners may not be this ` +
342
+ 'app — open the URL that belongs to this project rather than starting a second stack.');
331
343
  }
332
344
  /**
333
345
  * The diagnosis, and the CODE for the branch that produced it.
@@ -404,6 +416,30 @@ export function explainNoSession(facts) {
404
416
  'the SDK cannot reconnect to it. Fix the route, then reload the tab' +
405
417
  `${orOpenCommand(facts)}.${alreadyListeningClause(listening)} ${RETRY}`);
406
418
  }
419
+ // Ranked above TAB_GONE because it is not a hedge: the SDK reported the departure while the
420
+ // old document was still alive, so this is where the tab WENT rather than one of several
421
+ // opposite situations. Ranked below ROUTE_SERVER_ERROR because that branch names a defect in
422
+ // the app itself. Only reached when the departure note arrived fresh — a stale note is no
423
+ // fact, and the tombstone already refused to carry one (#1256).
424
+ if (facts.departedTo !== undefined && '' !== facts.departedTo) {
425
+ return reason(NoSessionReason.NAVIGATED_AWAY, 'no browser session connected, but one WAS connected to this daemon earlier, so the wiring ' +
426
+ // Redacted: a redirect target can carry credentials (OAuth callbacks, reset links), and
427
+ // this message is agent-facing. The raw value stays on the tombstone for matching.
428
+ `is correct. The page navigated away to ${redactUrl(facts.departedTo)} just before the ` +
429
+ 'connection closed — that is where the tab went, not a closed tab and not an install ' +
430
+ `problem. Ask the human to go back to the app${orOpenCommand(facts)}, or reload the tab. ` +
431
+ `${leaseAdvice(SELF_SERVE, facts)} ${RETRY}`, alreadyListeningClause(listening).trim());
432
+ }
433
+ // The dev server that served this session has stopped: the departed session's own port no
434
+ // longer answers, so "ask the human to reopen the app" points at a dead socket. Keyed on that
435
+ // port, as the next action is (#1421) — the prose and the executable half agree on the story.
436
+ // No "already listening" clause: whatever else answers is not where this app was.
437
+ if (facts.lastKnownUrl !== undefined && departedPortGone(facts)) {
438
+ return reason(NoSessionReason.TAB_GONE, 'no browser session connected, but one WAS connected to this daemon earlier, so the wiring ' +
439
+ `is correct. ${tabGoneWhat(facts.lastKnownUrl)} The dev server that served it has stopped ` +
440
+ '— nothing answers on that port any more — so start the app again (the command is in ' +
441
+ `\`next_action\`). ${RETRY}`);
442
+ }
407
443
  return reason(NoSessionReason.TAB_GONE, 'no browser session connected, but one WAS connected to this daemon earlier, so the wiring ' +
408
444
  `is correct. ${tabGoneWhat(facts.lastKnownUrl)} Ask the human to reopen ` +
409
445
  `the app${orOpenCommand(facts)}, or reload the tab. ${leaseAdvice(SELF_SERVE, facts)} ${RETRY}`, alreadyListeningClause(listening).trim());
@@ -449,7 +485,8 @@ export function explainNoSession(facts) {
449
485
  'dev server may not be running: START IT YOURSELF, in the background, using the command ' +
450
486
  'in `next_action`, and tell the human in one line that it is running. ' +
451
487
  `(2) There is no \`.reticle.json\` in ${where}, which is the file ${INIT_CMD} writes, so ` +
452
- `the app may carry no Reticle SDK. Check the app's OWN directory before re-running it. ${RETRY}`, `The scan covers ${SCANNED_PORTS} and nothing else, so a server on any other port is ` +
488
+ `the app may carry no Reticle SDK. Check the app's OWN directory before re-running it. ` +
489
+ `${ZERO_INSTALL} ${RETRY}`, `The scan covers ${SCANNED_PORTS} and nothing else, so a server on any other port is ` +
453
490
  'invisible to it: if the app IS running, ask for its URL rather than assuming it is down, ' +
454
491
  `and open it with ${OPEN_CMD}. The missing config is not proof either — in a monorepo the ` +
455
492
  'daemon often runs at the root while the app lives in a subdirectory, and an app wired by ' +
@@ -480,7 +517,7 @@ export function explainNoSession(facts) {
480
517
  `${INIT_CMD} writes, so the app may carry no Reticle SDK. Check the app's OWN directory: ` +
481
518
  `if it has no config, run ${INIT_CMD} ` +
482
519
  'there and restart the dev server; if it has one, the app is wired and simply has no page ' +
483
- `open — ${OPEN_CMD}. ${RETRY}`, 'That absence is not proof: the same one is expected in a monorepo whose daemon runs at the ' +
520
+ `open — ${OPEN_CMD}. ${ZERO_INSTALL} ${RETRY}`, 'That absence is not proof: the same one is expected in a monorepo whose daemon runs at the ' +
484
521
  'root while the app lives in a subdirectory, or in an app wired by the Vite or Babel ' +
485
522
  `plugin. ${unattributedListeners(listening)}${searchedClause(facts)}${siblingListenerClause(facts)}`);
486
523
  }
@@ -29,6 +29,11 @@ interface NextActionFacts {
29
29
  initialized: boolean;
30
30
  listening: readonly number[];
31
31
  dev: DevCommand | undefined;
32
+ /**
33
+ * File-existence predicate for the project root, pure for testing.
34
+ * Used to recognize non-JS ecosystems (e.g. Flutter) when no dev script exists.
35
+ */
36
+ exists?: (file: string) => boolean;
32
37
  /** Configs found in other workspace directories: positive evidence of a scope mismatch. */
33
38
  configsElsewhere?: readonly {
34
39
  directory: string;
@@ -82,7 +87,33 @@ interface NextActionFacts {
82
87
  * its one hit is as likely to be another repo's dev server as this one's.
83
88
  */
84
89
  lastKnownUrl?: string;
90
+ /** Ports that accepted a connection and answered nothing in time: up, not gone. */
91
+ slowListeners?: readonly number[];
92
+ /**
93
+ * Where the departed tab was seen heading, when the SDK reported it fresh (#1256). The
94
+ * next-action reason must agree with the diagnosis: when this is present the tab was not
95
+ * closed, it navigated away.
96
+ */
97
+ departedTo?: string;
98
+ /**
99
+ * The command that wires THIS project for good — `init` in the app's own folder through the
100
+ * project's own runner (see `initCommandIn`). Absent means the generic npx spelling.
101
+ */
102
+ init?: string;
85
103
  }
104
+ /** The port a tombstone URL names, when it names one — anything unparseable names no port. */
105
+ export declare function portOfUrl(url: string): number | undefined;
106
+ /**
107
+ * The departed session's own port no longer answers. Direct evidence, because the scan always
108
+ * covers that port — unlike an empty scan, which proves nothing the moment another project
109
+ * happens to be listening (#1421). A slow listener is up, not gone, and a url with no explicit
110
+ * port was never scanned, so neither counts.
111
+ */
112
+ export declare function departedPortGone(facts: {
113
+ lastKnownUrl?: string;
114
+ listening: readonly number[];
115
+ slowListeners?: readonly number[];
116
+ }): boolean;
86
117
  export declare function nextActionFor(facts: NextActionFacts): NoSessionNextAction;
87
118
  /** The same action as one sentence, for the prose message the human reads. */
88
119
  export declare function renderNextAction(next: NoSessionNextAction): string;
@@ -12,7 +12,33 @@
12
12
  *
13
13
  * Pure. The facts arrive from the watch; nothing here touches the disk or the clock.
14
14
  */
15
- import { NoSessionAction, RETICLE_URL_PARAM, ReticleEnv } from '@reticlehq/core';
15
+ import { NoSessionAction, RETICLE_URL_PARAM, ReticleEnv, redactUrl } from '@reticlehq/core';
16
+ import { detectNonJsEcosystem, noPackageJsonMessage } from '@reticlehq/init';
17
+ /** The port a tombstone URL names, when it names one — anything unparseable names no port. */
18
+ export function portOfUrl(url) {
19
+ try {
20
+ const raw = new URL(url).port;
21
+ if ('' === raw)
22
+ return undefined;
23
+ const port = Number(raw);
24
+ return Number.isSafeInteger(port) && port > 0 ? port : undefined;
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ }
30
+ /**
31
+ * The departed session's own port no longer answers. Direct evidence, because the scan always
32
+ * covers that port — unlike an empty scan, which proves nothing the moment another project
33
+ * happens to be listening (#1421). A slow listener is up, not gone, and a url with no explicit
34
+ * port was never scanned, so neither counts.
35
+ */
36
+ export function departedPortGone(facts) {
37
+ const port = facts.lastKnownUrl === undefined ? undefined : portOfUrl(facts.lastKnownUrl);
38
+ return (port !== undefined &&
39
+ !facts.listening.includes(port) &&
40
+ !(facts.slowListeners ?? []).includes(port));
41
+ }
16
42
  /**
17
43
  * The departed session's url as a human would type it: the params a Reticle launcher stamps on a
18
44
  * lease are stripped, because reopening WITH them would adopt the dead lease's identity. Undefined
@@ -35,10 +61,29 @@ function reopenableUrl(raw) {
35
61
  const port = '' === url.port ? ('https:' === url.protocol ? 443 : 80) : Number(url.port);
36
62
  return { url: url.toString(), port };
37
63
  }
38
- /** `reticle init`, the only command here that is Reticle's own and so cannot be wrong. */
39
- const INIT_COMMAND = 'reticle init';
40
- const OPEN_COMMAND = 'reticle open';
64
+ /**
65
+ * Reticle's own commands, the only ones here that cannot be wrong. Spelled through `npx`, like the
66
+ * CLI's own messages: the default MCP registration runs Reticle through `npx` and puts no `reticle`
67
+ * bin on PATH, so a bare `reticle init` fails with "command not found" exactly where it is handed out.
68
+ */
69
+ const CLI = 'npx @reticlehq/server';
70
+ const INIT_COMMAND = `${CLI} init`;
71
+ const OPEN_COMMAND = `${CLI} open`;
41
72
  const LOCALHOST = 'http://localhost';
73
+ /**
74
+ * What a lease on an app with no SDK can see. The lease supplies the SDK itself (the zero-install
75
+ * reader), so an unwired app still gets a verdict — on what the page does, not on its source.
76
+ */
77
+ const ZERO_INSTALL_SEES = 'the lease supplies the SDK itself: DOM, network, console and routes, but no component state ' +
78
+ 'or source file:line until the app is wired';
79
+ /** 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>"}"}`;
82
+ }
83
+ /** Nothing here says this project was ever wired: no config, no recorded connection, no session. */
84
+ function neverWired(facts) {
85
+ return !facts.initialized && true !== facts.previouslyConnected && !facts.everConnected;
86
+ }
42
87
  export function nextActionFor(facts) {
43
88
  // FIRST, above every other cause, because it is the only one supported by positive evidence about
44
89
  // a daemon rather than by an absence. This project's own connection record names a live daemon
@@ -70,7 +115,11 @@ export function nextActionFor(facts) {
70
115
  // (`connectedSinceLastClosure` in the manager). Read as the weaker "a refusal was recorded at
71
116
  // some point", the flip trades this bug for its mirror image and blames the token for a tab the
72
117
  // human closed. The ordering belongs to the fact; what this branch does with it is then obvious.
73
- if (facts.everConnected && true !== facts.authRefused) {
118
+ // A departed session whose port is ALSO gone is the one shape where "reopen that" points at a
119
+ // dead socket and forbids the restart that fixes it (#1421). Keyed on that port itself, not on
120
+ // an empty scan: another project listening elsewhere says nothing about this one.
121
+ const departedPortIsGone = facts.everConnected && true !== facts.authRefused && departedPortGone(facts);
122
+ if (facts.everConnected && true !== facts.authRefused && !departedPortIsGone) {
74
123
  const listening = facts.listening;
75
124
  const only = 1 === listening.length ? listening[0] : undefined;
76
125
  // The departed session's own url first: it is where this project's app demonstrably was, while
@@ -81,19 +130,26 @@ export function nextActionFor(facts) {
81
130
  : 0 === listening.length
82
131
  ? ''
83
132
  : only === undefined
84
- ? ` An app is already listening on ${listening.join(', ')}; just open the URL the human names — do not start a second stack.`
85
- : ` An app is already listening on ${String(only)}; just open ${LOCALHOST}:${String(only)} — do not start a second stack.`;
133
+ ? ` Something is serving a page on ${listening.map((p) => `:${String(p)}`).join(', ')}; it may not be this app — open the URL the human names rather than starting a second stack.`
134
+ : ` Something is serving a page on :${String(only)}; it may not be this app — just open ${LOCALHOST}:${String(only)} rather than starting a second stack.`;
86
135
  const target = known !== undefined
87
136
  ? { command: `${OPEN_COMMAND} ${known.url}`, port: known.port }
88
137
  : only === undefined
89
138
  ? {}
90
139
  : { command: `${OPEN_COMMAND} ${LOCALHOST}:${String(only)}`, port: only };
140
+ // Where the tab was seen heading, when the SDK reported it fresh — the next action must
141
+ // tell the same story as the diagnosis (#1256).
142
+ const departedTo = facts.departedTo;
91
143
  return {
92
144
  action: NoSessionAction.REOPEN_APP,
93
145
  ...target,
94
- reason: 'a session was connected to this daemon earlier, so the wiring is correct — the tab was ' +
95
- 'closed, reloaded, or the lease aged out. Reopen the app, or take one you own with ' +
96
- 'reticle_lease {action:"acquire", url}.' +
146
+ reason: 'a session was connected to this daemon earlier, so the wiring is correct — ' +
147
+ // Agrees with the diagnosis: when the SDK saw the page leave, "the tab was closed" is
148
+ // the wrong story. Redacted like the diagnosis — this reason is agent-facing too.
149
+ (departedTo === undefined || '' === departedTo
150
+ ? 'the tab was closed, reloaded, or the lease aged out. '
151
+ : `the page navigated away to ${redactUrl(departedTo)}. `) +
152
+ 'Reopen the app, or take one you own with reticle_lease {action:"acquire", url}.' +
97
153
  bound,
98
154
  };
99
155
  }
@@ -116,50 +172,11 @@ export function nextActionFor(facts) {
116
172
  `point it there), then open the app.${leaseAlternative}`,
117
173
  };
118
174
  }
119
- if (0 === facts.listening.length) {
120
- const dev = facts.dev;
121
- if (dev === undefined) {
122
- return {
123
- action: NoSessionAction.START_DEV_SERVER,
124
- reason: 'nothing is listening on the ports Reticle scans, so the app is probably not running — ' +
125
- 'but this project declares no dev script (no `dev`, `develop` or `start` in its ' +
126
- 'package.json), so there is no command to hand you. Ask the human how their app is ' +
127
- 'started, and for the URL it serves on.',
128
- };
129
- }
130
- return {
131
- action: NoSessionAction.START_DEV_SERVER,
132
- command: dev.command,
133
- ...(dev.port === undefined ? {} : { port: dev.port }),
134
- // "Probably", to match the branch above it and the paragraph beside it.
135
- //
136
- // The same fact was stated at two confidence levels by one function: no dev script said the
137
- // app was "probably not running", and THIS branch — the one that hands over a command to run
138
- // — asserted it flatly. That is the branch where being wrong costs something, because the
139
- // agent then starts a SECOND dev server on a second port, which the guard below calls the
140
- // exact confusion this probe exists to prevent.
141
- //
142
- // It also contradicted its own payload: the prose beside it says the scan is narrow, that a
143
- // server on any other port is invisible to it, and that a running app should be checked for
144
- // rather than assumed away. Measured on a machine with three dev servers up on ports the scan
145
- // does not cover, it reported the app was not running.
146
- reason: 'nothing is listening on the ports Reticle scans, so the app is probably not running — ' +
147
- 'though that scan is narrow, so if it IS up on another port, ask for its URL instead of ' +
148
- `starting a second one. This is the project's own ` +
149
- (undefined === dev.script ? 'launcher' : `\`${dev.script}\` script`) +
150
- ` — run it in the ` +
151
- 'background, tell the human it is running, then call reticle_sessions again.',
152
- };
153
- }
154
- // Something IS up. Whatever else is true, do NOT hand back a start command: a second dev server on
155
- // a second port is the exact confusion the probe exists to prevent.
175
+ // A current pairing-token refusal is positive evidence that the app is running and instrumented.
176
+ // It must outrank an empty port scan, which only says the app is outside this daemon's scan set.
156
177
  const ports = facts.listening.join(', ');
157
178
  const only = 1 === facts.listening.length ? facts.listening[0] : undefined;
158
- // A refused dial outranks the absence of a local config, for the same reason `previouslyConnected`
159
- // does: it is positive evidence about the app, and `initialized` only ever answers "is there a
160
- // `.reticle.json` in the ONE directory this daemon stands in". A globally-registered daemon stands
161
- // in `/` or `$HOME`, so that answer is no for every project it serves -- and every page it turns
162
- // away is proof that the project it turned away is wired.
179
+ const where = '' === ports ? 'on a port this daemon did not scan' : `${ports} listening`;
163
180
  // A refusal against a project that IS initialised here. The daemon has the config, so this is not
164
181
  // a scope problem — the page reached the right daemon and presented a credential it would not
165
182
  // accept. The usual cause is a dev server that shares no filesystem with the daemon (Docker, a
@@ -171,7 +188,7 @@ export function nextActionFor(facts) {
171
188
  return {
172
189
  action: NoSessionAction.OPEN_APP,
173
190
  ...(only === undefined ? {} : { port: only }),
174
- reason: `a page dialled this daemon and was refused on the pairing token (${ports} listening), so ` +
191
+ reason: `a page dialled this daemon and was refused on the pairing token (${where}), so ` +
175
192
  'the app IS running and instrumented and this project IS wired — the page simply presented ' +
176
193
  'a token this daemon does not own. The usual cause is a dev server that does not share a ' +
177
194
  'filesystem with the daemon (Docker, a devcontainer, WSL): the build plugin reads the token ' +
@@ -184,12 +201,17 @@ export function nextActionFor(facts) {
184
201
  'dev server is on this machine or in a container.',
185
202
  };
186
203
  }
204
+ // A refused dial outranks the absence of a local config, for the same reason `previouslyConnected`
205
+ // does: it is positive evidence about the app, and `initialized` only ever answers "is there a
206
+ // `.reticle.json` in the ONE directory this daemon stands in". A globally-registered daemon stands
207
+ // in `/` or `$HOME`, so that answer is no for every project it serves -- and every page it turns
208
+ // away is proof that the project it turned away is wired.
187
209
  if (!facts.initialized && true === facts.authRefused) {
188
210
  return {
189
211
  action: NoSessionAction.OPEN_APP,
190
212
  ...(only === undefined ? {} : { port: only }),
191
213
  reason: `a page dialled this daemon and was refused on the pairing token, so the app IS running ` +
192
- `and instrumented (${ports} listening) — this is a SCOPE problem, not an install problem. ` +
214
+ `and instrumented (${where}) — this is a SCOPE problem, not an install problem. ` +
193
215
  'This daemon was started outside the project (an IDE that registers the MCP server ' +
194
216
  'globally starts it in `/` or your home directory), so it has no `.reticle.json` to match ' +
195
217
  'the page against. Do NOT run `reticle init`: the config it would write is already correct ' +
@@ -197,14 +219,91 @@ export function nextActionFor(facts) {
197
219
  "projectId}, or restart the daemon from the app's own directory.",
198
220
  };
199
221
  }
222
+ if (0 === facts.listening.length || departedPortIsGone) {
223
+ const dev = facts.dev;
224
+ // The start advice below follows a departed session whose port is gone. Name it, so the restart
225
+ // does not read as if nothing had ever run here (#1421).
226
+ const stopped = departedPortIsGone ? reopenableUrl(facts.lastKnownUrl) : undefined;
227
+ const stoppedNote = stopped === undefined
228
+ ? ''
229
+ : ` The session that was on ${redactUrl(stopped.url)} is gone and nothing listens there now.`;
230
+ const notRunning = departedPortIsGone
231
+ ? "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 — ';
233
+ if (dev === undefined) {
234
+ if (facts.exists !== undefined && !facts.exists('package.json')) {
235
+ const ecosystem = detectNonJsEcosystem(facts.exists);
236
+ if (ecosystem !== undefined) {
237
+ return {
238
+ action: NoSessionAction.START_DEV_SERVER,
239
+ reason: 'Flutter' === ecosystem
240
+ ? noPackageJsonMessage(facts.exists)
241
+ : `This looks like a ${ecosystem} project, with no package.json in this directory. ` +
242
+ 'There is no dev command to hand you. Ask the human how the app starts and which ' +
243
+ 'URL it serves. If the web app has its own package.json in another directory, ' +
244
+ 'run Reticle from that app directory instead.',
245
+ };
246
+ }
247
+ }
248
+ return {
249
+ action: NoSessionAction.START_DEV_SERVER,
250
+ reason: notRunning +
251
+ 'but this project declares no dev script (no `dev`, `develop` or `start` in its ' +
252
+ 'package.json), so there is no command to hand you. Ask the human how their app is ' +
253
+ 'started, and for the URL it serves on.' +
254
+ stoppedNote,
255
+ };
256
+ }
257
+ // The app can live one directory down; the command has to be runnable from where the daemon
258
+ // stands, so it carries its own `cd` (reticle#1368).
259
+ const inApp = dev.directory === undefined ? '' : `cd ${dev.directory} && `;
260
+ return {
261
+ action: NoSessionAction.START_DEV_SERVER,
262
+ command: `${inApp}${dev.command}`,
263
+ ...(dev.port === undefined ? {} : { port: dev.port }),
264
+ // "Probably", to match the branch above it and the paragraph beside it.
265
+ //
266
+ // The same fact was stated at two confidence levels by one function: no dev script said the
267
+ // app was "probably not running", and THIS branch — the one that hands over a command to run
268
+ // — asserted it flatly. That is the branch where being wrong costs something, because the
269
+ // agent then starts a SECOND dev server on a second port, which the guard below calls the
270
+ // exact confusion this probe exists to prevent.
271
+ //
272
+ // It also contradicted its own payload: the prose beside it says the scan is narrow, that a
273
+ // server on any other port is invisible to it, and that a running app should be checked for
274
+ // rather than assumed away. Measured on a machine with three dev servers up on ports the scan
275
+ // does not cover, it reported the app was not running.
276
+ reason: notRunning +
277
+ 'though that scan is narrow, so if it IS up on another port, ask for its URL instead of ' +
278
+ `starting a second one. This is the project's own ` +
279
+ (undefined === dev.script ? 'launcher' : `\`${dev.script}\` script`) +
280
+ (dev.directory === undefined ? '' : `, in \`${dev.directory}\``) +
281
+ ` — run it in the ` +
282
+ 'background, tell the human it is running, then call reticle_sessions again.' +
283
+ stoppedNote +
284
+ (neverWired(facts)
285
+ ? ` Once it is up, ${zeroInstallLease(dev.port === undefined ? undefined : `${LOCALHOST}:${String(dev.port)}`)} ` +
286
+ `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.`
288
+ : ''),
289
+ };
290
+ }
291
+ // Something IS up. Whatever else is true, do NOT hand back a start command: a second dev server on
292
+ // a second port is the exact confusion the probe exists to prevent.
200
293
  if (!facts.initialized && true !== facts.previouslyConnected) {
294
+ // The port the project's own dev script pins outranks a lone listener: the scan is machine-wide.
295
+ const pinned = facts.dev?.port;
296
+ const target = pinned !== undefined && facts.listening.includes(pinned) ? pinned : only;
201
297
  return {
202
298
  action: NoSessionAction.RUN_INIT,
203
- command: INIT_COMMAND,
204
- ...(only === undefined ? {} : { port: only }),
299
+ command: facts.init ?? INIT_COMMAND,
300
+ ...(target === undefined ? {} : { port: target }),
205
301
  reason: `something is listening (${ports}) but no \`.reticle.json\` was found, so the app may ` +
206
- "carry no Reticle SDK. Run this in the APP's own directory — in a monorepo that is not " +
207
- 'where this daemon stands — then restart the dev server.',
302
+ 'carry no Reticle SDK. For a verdict NOW with nothing installed: ' +
303
+ `${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.',
208
307
  };
209
308
  }
210
309
  if (only === undefined) {
@@ -232,12 +331,12 @@ export function nextActionFor(facts) {
232
331
  command: `${OPEN_COMMAND} ${LOCALHOST}:${String(only)}`,
233
332
  port: only,
234
333
  reason: neverConnected
235
- ? 'this project is wired and a dev server is listening, but no app has ever connected to ' +
334
+ ? 'this project is wired and something is listening on that port (it may not be this app), but no app has ever connected to ' +
236
335
  'this daemon — Reticle only ever sees a page a browser has LOADED, and nothing has loaded ' +
237
336
  'one. If opening it does not produce a session, the dev server is older than the Reticle ' +
238
337
  'plugin and its bundle carries no SDK: restart the dev server (do not rely on HMR) and ' +
239
338
  'load the page again.'
240
- : 'this project is wired and a dev server is listening — Reticle only ever sees a page a ' +
339
+ : 'this project is wired and something is listening on that port (it may not be this app) — Reticle only ever sees a page a ' +
241
340
  'browser has LOADED, and nothing has loaded one.',
242
341
  };
243
342
  }
@@ -17,7 +17,20 @@ interface NoSessionWatchOptions {
17
17
  initialized: boolean;
18
18
  /** Where that was decided — this daemon's working directory unless a caller says otherwise. */
19
19
  directory?: string;
20
- probe?: () => Promise<number[]>;
20
+ /**
21
+ * File-existence predicate for the project directory. Injected for tests; defaults to
22
+ * checking the directory on disk.
23
+ */
24
+ exists?: (file: string) => boolean;
25
+ /**
26
+ * The background port scan. Injected for tests; production probes each port on both loopback
27
+ * families.
28
+ *
29
+ * Receives the candidate list — the well-known ports plus the ones that name THIS project
30
+ * (#1367) — so a test can pin the observation without opening a socket. A test that injects it
31
+ * owns the scan.
32
+ */
33
+ probe?: (ports: readonly number[]) => Promise<number[]>;
21
34
  /**
22
35
  * Well-known Reticle ports other than ours that currently accept a connection.
23
36
  *