@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
@@ -31,6 +31,7 @@
31
31
  import * as http from 'node:http';
32
32
  import { DRIVE_PATH, LOOPBACK_HOST } from '@reticlehq/core';
33
33
  import { PortPresence } from '../../daemon/binding/port-presence.js';
34
+ import { summarizeStatus } from '../../daemon/binding/daemon-status-probe.js';
34
35
  /** What `drive` should do about the port, given what is on it. */
35
36
  export const DriveMode = {
36
37
  /** Nothing is listening: bind it and run the foreground engine. */
@@ -134,18 +135,84 @@ export async function requestDriveSession(port, url, post = postJson) {
134
135
  }
135
136
  return readAttachResponse(port, url, res);
136
137
  }
138
+ /** Nothing known about the app, as for a page that never connected. */
139
+ export const NO_ATTACHED_APP = { fields: {}, mismatch: false };
140
+ /**
141
+ * Control characters, and the 0x80 to 0x9f range some terminals also obey. Built with
142
+ * `fromCharCode` to keep them out of a regex literal (no-control-regex).
143
+ */
144
+ const TERMINAL_CONTROLS = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(0x1f)}${String.fromCharCode(0x7f)}-${String.fromCharCode(0x9f)}]`, 'g');
145
+ /**
146
+ * A value safe to print. The project id and title come from the page, and the expected project id
147
+ * from a `.reticle.json` anyone can commit. All three are written straight to the terminal (and into
148
+ * the JSON line beside it), so they could otherwise move the cursor or retitle the window. Each
149
+ * control character becomes U+FFFD, so the reader can still see that something was there.
150
+ */
151
+ function printable(value) {
152
+ return value.replace(TERMINAL_CONTROLS, '\uFFFD');
153
+ }
154
+ /**
155
+ * Pick the attached session out of a `/status` payload. Pure.
156
+ *
157
+ * The drive answer is a lease result, which carries no project: the page reports that itself when
158
+ * it connects, and `/status` is where it is already listed.
159
+ */
160
+ export function attachedApp(status, sessionId, expectedProjectId) {
161
+ const row = summarizeStatus(status).sessions.find((s) => s.sessionId === sessionId);
162
+ return {
163
+ fields: {
164
+ ...(row?.projectId === undefined ? {} : { projectId: printable(row.projectId) }),
165
+ ...(row?.title === undefined ? {} : { title: printable(row.title) }),
166
+ ...(expectedProjectId === undefined
167
+ ? {}
168
+ : { expectedProjectId: printable(expectedProjectId) }),
169
+ },
170
+ // Only warned when both sides are known: a page with no project id proves nothing, and neither
171
+ // does a directory without a `.reticle.json`.
172
+ mismatch: row?.projectId !== undefined &&
173
+ expectedProjectId !== undefined &&
174
+ row.projectId !== expectedProjectId,
175
+ };
176
+ }
177
+ /** The fallback when the daemon sent no hint for a page that did not connect. */
178
+ const MSG_NOT_READY_HINT = 'Check that the app embeds @reticlehq/browser.';
179
+ /** How the attach line names the page's project. */
180
+ const PROJECT_LABEL = (projectId) => `project ${JSON.stringify(projectId)}`;
181
+ /** The page is a different project from the one this directory's `.reticle.json` names. */
182
+ const MSG_PROJECT_MISMATCH = (url, expected, actual) => `Warning: this directory's .reticle.json is ${PROJECT_LABEL(expected)}, but the page at ${url} ` +
183
+ `is ${PROJECT_LABEL(actual)}, so another app is probably serving that port. Check which dev ` +
184
+ 'server is on it before trusting anything this session reports.';
185
+ /**
186
+ * The project and title, and a warning when this directory names a different project.
187
+ *
188
+ * In a monorepo the port you meant for one app is easily held by another, and the port, url and
189
+ * session id read the same either way.
190
+ */
191
+ function describeApp(url, app) {
192
+ const { projectId, title, expectedProjectId } = app.fields;
193
+ const named = [
194
+ ...(projectId === undefined ? [] : [PROJECT_LABEL(projectId)]),
195
+ ...(title === undefined ? [] : [JSON.stringify(title)]),
196
+ ];
197
+ const label = 0 === named.length ? '' : ` (${named.join(', ')})`;
198
+ const warning = app.mismatch && projectId !== undefined && expectedProjectId !== undefined
199
+ ? ` ${MSG_PROJECT_MISMATCH(url, expectedProjectId, projectId)}`
200
+ : '';
201
+ return { label, warning };
202
+ }
137
203
  /** The success line. Names the session, because that is the handle everything downstream needs. */
138
- export function describeAttached(port, url, session) {
204
+ export function describeAttached(port, url, session, app = NO_ATTACHED_APP) {
139
205
  const life = session.expiresInMs === undefined
140
206
  ? ''
141
207
  : ` It is released after ${String(Math.round(session.expiresInMs / 1000))}s untouched; any ` +
142
208
  'tool call against it resets that.';
143
209
  if (!session.ready) {
144
210
  return (`the Reticle daemon on :${String(port)} opened ${url} as session ${session.sessionId}, but ` +
145
- `the page did not connect to the bridge. ${session.hint ?? 'Check that the app embeds @reticlehq/core.'}`);
211
+ `the page did not connect to the bridge. ${session.hint ?? MSG_NOT_READY_HINT}`);
146
212
  }
147
- return (`attached to the Reticle daemon on :${String(port)} — it is driving ${url} as session ` +
148
- `${session.sessionId}, which every Reticle tool can address.${life}`);
213
+ const { label, warning } = describeApp(url, app);
214
+ return (`attached to the Reticle daemon on :${String(port)} — it is driving ${url}${label} as session ` +
215
+ `${session.sessionId}, which every Reticle tool can address.${life}${warning}`);
149
216
  }
150
217
  /**
151
218
  * What an attach cannot honour: the window.
@@ -6,8 +6,9 @@
6
6
  * place. The pure parts (which mode, and every sentence a user reads) live next door in
7
7
  * drive-attach.ts, which is where the reasoning for attaching is written down.
8
8
  */
9
+ /** `projectId` is the one in this directory's `.reticle.json`, read by the caller. */
9
10
  export declare function handleDrive(parsed: {
10
11
  port: number;
11
12
  driveUrl: string;
12
13
  headless: boolean;
13
- }): void;
14
+ }, projectId?: string): void;
@@ -13,9 +13,10 @@ import { probeDaemon } from '../../../surface/mcp/mcp-proxy.js';
13
13
  import { readPid } from '../../daemon/daemon.js';
14
14
  import { fetchStatus } from '../../daemon/binding/daemon-status-probe.js';
15
15
  import { captureLookup, findPortHolder } from '../ports/port-holder.js';
16
- import { DriveMode, decideDriveMode, describeAttached, driveForeignHolder, driveHeadlessOnAttach, driveRaceLost, requestDriveSession, } from './drive-attach.js';
17
- export function handleDrive(parsed) {
18
- void driveWithHonestConflict(parsed);
16
+ import { DriveMode, NO_ATTACHED_APP, attachedApp, decideDriveMode, describeAttached, driveForeignHolder, driveHeadlessOnAttach, driveRaceLost, requestDriveSession, } from './drive-attach.js';
17
+ /** `projectId` is the one in this directory's `.reticle.json`, read by the caller. */
18
+ export function handleDrive(parsed, projectId) {
19
+ void driveWithHonestConflict(parsed, projectId);
19
20
  }
20
21
  /**
21
22
  * Decide who gets the port BEFORE binding it — and when the answer is "the daemon", ask it instead.
@@ -29,7 +30,7 @@ export function handleDrive(parsed) {
29
30
  * because the MCP proxy respawns a daemon into the gap. So a healthy daemon is now ATTACHED to —
30
31
  * see cli/drive/drive-attach.ts.
31
32
  */
32
- async function driveWithHonestConflict(parsed) {
33
+ async function driveWithHonestConflict(parsed, projectId) {
33
34
  const presence = await probePresence(parsed.port, { tcpOpen: probeDaemon, status: fetchStatus });
34
35
  const mode = decideDriveMode(presence);
35
36
  if (DriveMode.REFUSE === mode) {
@@ -43,7 +44,7 @@ async function driveWithHonestConflict(parsed) {
43
44
  return;
44
45
  }
45
46
  if (DriveMode.ATTACH === mode) {
46
- await attachToRunningDaemon(parsed.port, parsed.driveUrl, parsed.headless);
47
+ await attachToRunningDaemon(parsed.port, parsed.driveUrl, parsed.headless, projectId);
47
48
  return;
48
49
  }
49
50
  // The probe cannot close the race: something can take the port between here and the bind, and the
@@ -81,7 +82,7 @@ async function driveWithHonestConflict(parsed) {
81
82
  * against it renews its lease), and a foreground hold here could only keep it alive by faking tool
82
83
  * calls at it.
83
84
  */
84
- async function attachToRunningDaemon(port, url, headless) {
85
+ async function attachToRunningDaemon(port, url, headless, projectId) {
85
86
  const result = await requestDriveSession(port, url);
86
87
  if (!result.ok) {
87
88
  log('reticle_drive_attach_failed', { port, url, reason: result.reason });
@@ -89,13 +90,18 @@ async function attachToRunningDaemon(port, url, headless) {
89
90
  process.exit(1);
90
91
  return;
91
92
  }
93
+ // Only a page that connected has reported its project; one that never dialled in is not listed.
94
+ const app = result.session.ready
95
+ ? attachedApp(await fetchStatus(port), result.session.sessionId, projectId)
96
+ : NO_ATTACHED_APP;
92
97
  log('reticle_drive_attached', {
93
98
  port,
94
99
  url,
95
100
  sessionId: result.session.sessionId,
96
101
  ready: result.session.ready,
102
+ ...app.fields,
97
103
  });
98
- process.stderr.write(`${describeAttached(port, url, result.session)}\n`);
104
+ process.stderr.write(`${describeAttached(port, url, result.session, app)}\n`);
99
105
  // The command's own default is headed, and this path cannot deliver that. Said out loud rather
100
106
  // than left for the user to discover by watching a window that never opens.
101
107
  if (!headless)
@@ -0,0 +1,13 @@
1
+ /** The `broken` list of a regression report, or undefined when the report has none. */
2
+ export declare function brokenOf(report: unknown): unknown[] | undefined;
3
+ /** What the platform said about regressions: the broken list, or that it refused the credential. */
4
+ export interface KnownRegression {
5
+ broken?: unknown[];
6
+ /** The platform refused this project's key: said, and the gate fails closed on it. */
7
+ refused?: string;
8
+ }
9
+ /**
10
+ * Nothing when `reticleRoot` is not linked or the platform did not answer (offline is not a failure);
11
+ * `refused` when it answered and refused the key — a revoked key left CI green and silent.
12
+ */
13
+ export declare function knownRegression(reticleRoot: string): Promise<KnownRegression>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The flows the linked project's platform says passed before and are broken now — what
3
+ * `reticle runs regression` prints, read here so `reticle gate` can fail on it too.
4
+ *
5
+ * Its own module, not a call into `cloud-cli.ts`: the gate is on the library's import path, and the
6
+ * cloud CLI reaches the install-time surface the library must never load.
7
+ */
8
+ import { homedir } from 'node:os';
9
+ import { z } from 'zod';
10
+ import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
11
+ import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
12
+ import { CredentialRefusedError, api } from './cloud-kit.js';
13
+ const REGRESSION_PATH = '/v1/project/regression';
14
+ /** The `broken` list of a regression report, or undefined when the report has none. */
15
+ export function brokenOf(report) {
16
+ const parsed = z.object({ broken: z.array(z.unknown()) }).safeParse(report);
17
+ return parsed.success ? parsed.data.broken : undefined;
18
+ }
19
+ /**
20
+ * Nothing when `reticleRoot` is not linked or the platform did not answer (offline is not a failure);
21
+ * `refused` when it answered and refused the key — a revoked key left CI green and silent.
22
+ */
23
+ export async function knownRegression(reticleRoot) {
24
+ try {
25
+ const cloud = await resolveProjectCloud(createNodeFileSystem(), reticleRoot, homedir(), process.env);
26
+ if (null === cloud.config)
27
+ return {};
28
+ const broken = brokenOf(await api('GET', `${cloud.config.url}${REGRESSION_PATH}`, cloud.config.apiKey));
29
+ return broken === undefined ? {} : { broken };
30
+ }
31
+ catch (error) {
32
+ return error instanceof CredentialRefusedError ? { refused: error.message } : {};
33
+ }
34
+ }
@@ -36,6 +36,12 @@ export declare function installedSdkVersion(projectDir: string, readFile: (path:
36
36
  export declare function readTextFile(path: string): string | undefined;
37
37
  /** The one line a person sees on stderr when the CLI hands over — stdout belongs to the protocol. */
38
38
  export declare function versionMatchNote(sdkVersion: string, cliVersion: string): string;
39
+ /**
40
+ * The line `--help` opens with when the command it describes would run at another version (#1378).
41
+ * Help stays on this binary, so without it the flags listed are this release's, and the re-run
42
+ * rejected the ones its older release never had, as an unknown parameter.
43
+ */
44
+ export declare function helpVersionNote(sdkVersion: string, cliVersion: string): string;
39
45
  export interface VersionMatchInput {
40
46
  argv: readonly string[];
41
47
  cliVersion: string;
@@ -48,6 +54,12 @@ export interface VersionMatchInput {
48
54
  * environment are handed in.
49
55
  */
50
56
  export declare function versionToMatch(input: VersionMatchInput): string | undefined;
57
+ /**
58
+ * The version the command asked about with `--help`, or `help <command>`, would actually run at.
59
+ * Undefined when help was not asked for, or when that command runs on this binary. Pure, like
60
+ * `versionToMatch`: it asks that same question about the command with the help request removed.
61
+ */
62
+ export declare function helpRunsAt(input: VersionMatchInput): string | undefined;
51
63
  /** How to launch `npx --yes @reticlehq/server@<version> <args>` on this platform. */
52
64
  export declare function npxInvocation(version: string, args: readonly string[], on: string): {
53
65
  file: string;
@@ -58,6 +58,8 @@ const KEEP_COMMANDS = new Set([
58
58
  '_daemon',
59
59
  ]);
60
60
  const KEEP_FLAGS = new Set(['--version', '-v', '--help', '-h']);
61
+ const HELP_COMMAND = 'help';
62
+ const HELP_FLAGS = new Set(['--help', '-h']);
61
63
  const SETUP_COMMAND = 'setup';
62
64
  const SETUP_INSTALL = 'install';
63
65
  /** A published release — not `workspace:*`, a link, or a tag npx could not pin. */
@@ -105,6 +107,17 @@ export function versionMatchNote(sdkVersion, cliVersion) {
105
107
  return (`This project's Reticle SDK is ${sdkVersion}; running ${SERVER_PACKAGE}@${sdkVersion} to match ` +
106
108
  `(this CLI is ${cliVersion}, a different major). Set ${VersionMatchEnv.OPT_OUT}=1 to keep this one.`);
107
109
  }
110
+ /**
111
+ * The line `--help` opens with when the command it describes would run at another version (#1378).
112
+ * Help stays on this binary, so without it the flags listed are this release's, and the re-run
113
+ * rejected the ones its older release never had, as an unknown parameter.
114
+ */
115
+ export function helpVersionNote(sdkVersion, cliVersion) {
116
+ return (`This help describes ${SERVER_PACKAGE} ${cliVersion}, but in this project the command runs at ` +
117
+ `${SERVER_PACKAGE}@${sdkVersion} to match its SDK, which may not take every flag listed here. ` +
118
+ `Run npx ${SERVER_PACKAGE}@${sdkVersion} <command> --help for that version's help, or set ` +
119
+ `${VersionMatchEnv.OPT_OUT}=1 to run this one.`);
120
+ }
108
121
  /** Did the person name a version on the npx line (`npx @reticlehq/server@<version> …`)? */
109
122
  function pinnedOnNpxLine(spec) {
110
123
  if (spec === undefined || !spec.startsWith(`${SERVER_PACKAGE}@`))
@@ -141,6 +154,18 @@ export function versionToMatch(input) {
141
154
  return undefined;
142
155
  return sdkMajor === majorOf(input.cliVersion) ? undefined : sdk;
143
156
  }
157
+ /**
158
+ * The version the command asked about with `--help`, or `help <command>`, would actually run at.
159
+ * Undefined when help was not asked for, or when that command runs on this binary. Pure, like
160
+ * `versionToMatch`: it asks that same question about the command with the help request removed.
161
+ */
162
+ export function helpRunsAt(input) {
163
+ const viaCommand = HELP_COMMAND === input.argv[0];
164
+ if (!viaCommand && !input.argv.some((arg) => HELP_FLAGS.has(arg)))
165
+ return undefined;
166
+ const asked = (viaCommand ? input.argv.slice(1) : input.argv).filter((arg) => !HELP_FLAGS.has(arg));
167
+ return versionToMatch({ ...input, argv: asked });
168
+ }
144
169
  /** How to launch `npx --yes @reticlehq/server@<version> <args>` on this platform. */
145
170
  export function npxInvocation(version, args, on) {
146
171
  const argv = [NPX_YES, `${SERVER_PACKAGE}@${version}`, ...args];
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import { log } from '../../../log.js';
18
18
  import { RETICLE_VERIFY_DEFAULT_PORT } from '../../../index.js';
19
- import { verifyEndpointMismatch } from '../../../status-payload.js';
19
+ import { strandedClientsNote, verifyEndpointMismatch } from '../../../status-payload.js';
20
20
  import { probeDaemon, waitForDaemonBind } from '../../../surface/mcp/mcp-proxy.js';
21
21
  import { stateDirProblem } from '../../daemon/state-dir.js';
22
22
  import { readPid, isAlive, removePid, spawnDaemon, logPath, reticleStateHome, } from '../../daemon/daemon.js';
@@ -121,8 +121,17 @@ export function handleStop(port, quiet) {
121
121
  const pid = readPid(port);
122
122
  if (null === pid || !isAlive(pid)) {
123
123
  removePid(port);
124
- if (!quiet)
125
- log('reticle_daemon_not_running', { port });
124
+ // No pid on record is not "not running": a daemon whose pid file vanished still answers its
125
+ // port, and `kill` finds the listener and confirms it is Reticle's before signalling it.
126
+ void fetchStatus(port).then(async (status) => {
127
+ if (status !== undefined) {
128
+ if (!(await runKill(port, false)))
129
+ process.exit(1);
130
+ return;
131
+ }
132
+ if (!quiet)
133
+ log('reticle_daemon_not_running', { port });
134
+ });
126
135
  return;
127
136
  }
128
137
  process.kill(pid, 'SIGTERM');
@@ -168,6 +177,9 @@ export function handleStop(port, quiet) {
168
177
  * anything at all, and a single `ok: false` cannot tell them which happened.
169
178
  */
170
179
  export async function handleRestart(port, force) {
180
+ const stranded = strandedClientsNote(await fetchStatus(port));
181
+ if (stranded !== undefined)
182
+ process.stderr.write(`${stranded}\n`);
171
183
  const freed = await runKill(port, force);
172
184
  if (!freed) {
173
185
  log('reticle_restart_aborted', {
@@ -7,6 +7,12 @@
7
7
  * talks to for the rest of its life — and the port resolution at the top is the fix for agents on
8
8
  * different projects silently sharing one daemon, one identity and one blast radius.
9
9
  */
10
+ /**
11
+ * Whether the daemon this proxy starts hides its browser. A daemon on a port nobody chose — the
12
+ * requested one served another project, so this one was moved — was opening a visible browser the
13
+ * person never asked for, on a port nothing records. Only the requested port gets the default.
14
+ */
15
+ export declare function spawnsHeadless(headless: boolean, requested: number, resolved: number): boolean;
10
16
  /**
11
17
  * MCP proxy mode: ensures the daemon is running, then bridges Claude Code's
12
18
  * stdin/stdout to the daemon's SSE endpoint. This is the recommended way to
@@ -12,8 +12,8 @@ import { isAlive, spawnDaemon, reticleStateHome } from '../daemon/daemon.js';
12
12
  import { PortPresence, probePresence, presenceIsUsable, describePresence, } from '../daemon/binding/port-presence.js';
13
13
  import { waitForDaemon, startMcpProxy, probeDaemon, proxyLog, setProxyLogPort, } from '../../surface/mcp/mcp-proxy.js';
14
14
  import { installProxyResilience } from '../daemon/daemon-resilience.js';
15
- import { readProjectId } from './ports/resolve/cli-port.js';
16
- import { resolveMcpPort, daemonProjectAt } from '../daemon/daemon-resolve.js';
15
+ import { readProjectId, readProjectPort } from './ports/resolve/cli-port.js';
16
+ import { resolveMcpPort, daemonProjectAt, relocationReason, } from '../daemon/daemon-resolve.js';
17
17
  import { daemonSpawnArgs } from './daemon-start-options.js';
18
18
  import { WakeAction, decideWake } from '../daemon/wake-decision.js';
19
19
  import { pickDaemonPortToBind } from '../daemon/binding/free-port.js';
@@ -23,6 +23,14 @@ import { ReticleEnv } from '@reticlehq/core';
23
23
  import { agentIo } from '../setup/agent-io.js';
24
24
  import { SERVER_VERSION } from '../version/identity/server-version.js';
25
25
  import { homedir } from 'node:os';
26
+ /**
27
+ * Whether the daemon this proxy starts hides its browser. A daemon on a port nobody chose — the
28
+ * requested one served another project, so this one was moved — was opening a visible browser the
29
+ * person never asked for, on a port nothing records. Only the requested port gets the default.
30
+ */
31
+ export function spawnsHeadless(headless, requested, resolved) {
32
+ return headless || requested !== resolved;
33
+ }
26
34
  /**
27
35
  * MCP proxy mode: ensures the daemon is running, then bridges Claude Code's
28
36
  * stdin/stdout to the daemon's SSE endpoint. This is the recommended way to
@@ -64,12 +72,12 @@ export async function handleMcp(opts) {
64
72
  alive: isAlive,
65
73
  daemonPresent: async (p) => presenceIsUsable(await probePresence(p, { tcpOpen: probeDaemon, status: fetchStatus })),
66
74
  pickPort: (p) => pickDaemonPortToBind(p),
67
- });
75
+ }, readProjectPort(process.cwd()));
68
76
  if (port !== opts.port) {
69
77
  log('reticle_mcp_port_relocated', {
70
78
  requested: opts.port,
71
79
  port,
72
- reason: 'the requested port serves a different project',
80
+ reason: relocationReason(opts.port, port, projectId, reticleStateHome(), isAlive),
73
81
  });
74
82
  }
75
83
  // The proxy IS the MCP server the editor launched. Nothing respawns it, so an uncaught throw here
@@ -119,7 +127,7 @@ export async function handleMcp(opts) {
119
127
  }
120
128
  const daemonArgs = daemonSpawnArgs({
121
129
  port,
122
- headless,
130
+ headless: spawnsHeadless(headless, opts.port, port),
123
131
  http,
124
132
  ...(driveUrl !== undefined ? { driveUrl } : {}),
125
133
  ...(httpPort !== undefined ? { httpPort } : {}),
@@ -51,3 +51,13 @@ export declare function describeForeignHolder(port: number, holder: PortHolder |
51
51
  ourPid?: number | null): string;
52
52
  /** The lookup itself. `exec` is injected so the shelling out never runs in a unit test. */
53
53
  export declare function findPortHolder(port: number, exec: (command: string, args: readonly string[]) => string | null): PortHolder | null;
54
+ /** The path in `lsof -a -p <pid> -d cwd -Fn` output, or null when it printed none. */
55
+ export declare function parseProcessCwd(stdout: string): string | null;
56
+ /**
57
+ * The working directory of whatever LISTENS on `port`, or null.
58
+ *
59
+ * How the daemon tells which checkout served a page when every git worktree declares the same
60
+ * projectId: the dev server runs inside exactly one of them. Null wherever `lsof` cannot answer —
61
+ * Windows, a slim container — and the caller then keeps the answer it had without this.
62
+ */
63
+ export declare function findListenerCwd(port: number, exec: (command: string, args: readonly string[]) => string | null): string | null;
@@ -83,7 +83,7 @@ ourPid) {
83
83
  // Naming the command matters more than naming the process. "Stop that process" describes an
84
84
  // outcome and leaves the reader to invent a route to it, and the route they invent is the `-ti`
85
85
  // pipeline that takes their agent's proxy down with the holder.
86
- const tail = 'a daemon cannot bind it. Free it with `reticle kill --force` (it signals the listener only, ' +
86
+ const tail = 'a daemon cannot bind it. Free it with `reticle restart --force` (it signals the listener only, ' +
87
87
  "never the agent's mcp proxy), or run Reticle on a different port (`--port`), then retry.";
88
88
  if (null === holder) {
89
89
  /**
@@ -121,3 +121,27 @@ export function findPortHolder(port, exec) {
121
121
  const out = exec('lsof', ['-nP', `-iTCP:${String(port)}`, '-sTCP:LISTEN', '-F', 'pc']);
122
122
  return null === out ? null : parsePortHolder(out);
123
123
  }
124
+ /** `lsof -Fn` emits the file name on its own line, prefixed `n`. */
125
+ const NAME_FIELD = 'n';
126
+ /** The path in `lsof -a -p <pid> -d cwd -Fn` output, or null when it printed none. */
127
+ export function parseProcessCwd(stdout) {
128
+ for (const raw of stdout.split('\n')) {
129
+ if (raw.startsWith(NAME_FIELD) && raw.length > NAME_FIELD.length)
130
+ return raw.slice(1);
131
+ }
132
+ return null;
133
+ }
134
+ /**
135
+ * The working directory of whatever LISTENS on `port`, or null.
136
+ *
137
+ * How the daemon tells which checkout served a page when every git worktree declares the same
138
+ * projectId: the dev server runs inside exactly one of them. Null wherever `lsof` cannot answer —
139
+ * Windows, a slim container — and the caller then keeps the answer it had without this.
140
+ */
141
+ export function findListenerCwd(port, exec) {
142
+ const holder = findPortHolder(port, exec);
143
+ if (null === holder)
144
+ return null;
145
+ const out = exec('lsof', ['-a', '-p', String(holder.pid), '-d', 'cwd', '-Fn']);
146
+ return null === out ? null : parseProcessCwd(out);
147
+ }
@@ -11,6 +11,7 @@
11
11
  * A repo already knows its name: the directory it lives in. That is not a guess, it is the name its
12
12
  * owner chose and the one they will look for in a project list.
13
13
  */
14
+ import { z } from 'zod';
14
15
  /** The id used when a directory name yields nothing usable — the historical behaviour, unchanged. */
15
16
  export declare const DEFAULT_PROJECT_ID = "default";
16
17
  /**
@@ -27,4 +28,31 @@ export declare const slugifyProjectName: (raw: string) => string;
27
28
  * do to rotate a key or repoint an environment — must land in that same project or the history
28
29
  * silently splits in two, which is worse than the shared-bucket problem this fixes.
29
30
  */
30
- export declare const defaultProjectFor: (cwdBasename: string, existingProjectId: string | undefined) => string;
31
+ export declare const defaultProjectFor: (cwdBasename: string, existingProjectId: string | undefined,
32
+ /** The `projectId` `init` wrote into `.reticle.json`, when there is one. */
33
+ localProjectId?: string) => string;
34
+ export declare const CreatedProjectSchema: z.ZodObject<{
35
+ projectId: z.ZodString;
36
+ name: z.ZodString;
37
+ }, "strip", z.ZodTypeAny, {
38
+ name: string;
39
+ projectId: string;
40
+ }, {
41
+ name: string;
42
+ projectId: string;
43
+ }>;
44
+ /** ` in workspace "<name>"`, or nothing when no name is known. */
45
+ export declare const inWorkspace: (name: string | undefined) => string;
46
+ /**
47
+ * Which repository, and which folder in it, a project folder is: a hash of the `origin` remote and
48
+ * the folder's path inside the checkout, so every clone of one app agrees and two different apps
49
+ * both named `web` do not. Undefined outside git or with no remote. Neither leaves the machine.
50
+ */
51
+ export declare function repoIdentity(dir: string): string | undefined;
52
+ export declare function resolveProjectId(url: string, token: string, wanted: string, workspace?: string, repo?: string,
53
+ /**
54
+ * The id `init` wrote into `.reticle.json`, for a project created by default: the platform is
55
+ * asked to keep it, so the folder and the dashboard name one project by one id. A platform that
56
+ * does not know the field ignores it and answers with its own, which is what gets linked.
57
+ */
58
+ localId?: string): Promise<string>;
@@ -11,6 +11,12 @@
11
11
  * A repo already knows its name: the directory it lives in. That is not a guess, it is the name its
12
12
  * owner chose and the one they will look for in a project list.
13
13
  */
14
+ import { createHash } from 'node:crypto';
15
+ import { execFileSync } from 'node:child_process';
16
+ import { relative } from 'node:path';
17
+ import { z } from 'zod';
18
+ import { PROJECT_ID_HASH_LENGTH } from '@reticlehq/core';
19
+ import { CredentialRefusedError, api, hint } from './cloud-kit.js';
14
20
  /** Cap the slug so a deep or oddly-named checkout cannot produce an unreadable project id. */
15
21
  const MAX_SLUG = 48;
16
22
  /** The id used when a directory name yields nothing usable — the historical behaviour, unchanged. */
@@ -37,8 +43,107 @@ export const slugifyProjectName = (raw) => {
37
43
  * do to rotate a key or repoint an environment — must land in that same project or the history
38
44
  * silently splits in two, which is worse than the shared-bucket problem this fixes.
39
45
  */
40
- export const defaultProjectFor = (cwdBasename, existingProjectId) => {
46
+ export const defaultProjectFor = (cwdBasename, existingProjectId,
47
+ /** The `projectId` `init` wrote into `.reticle.json`, when there is one. */
48
+ localProjectId) => {
41
49
  if (existingProjectId !== undefined && existingProjectId.length > 0)
42
50
  return existingProjectId;
43
- return slugifyProjectName(cwdBasename);
51
+ // The name part of `init`'s `<name>-<hash>`, else the id as written: a name the owner chose.
52
+ const named = localProjectId === undefined || 0 === localProjectId.length
53
+ ? undefined
54
+ : (nameOfLocalId(localProjectId) ?? localProjectId);
55
+ return slugifyProjectName(named ?? cwdBasename);
44
56
  };
57
+ /** `init`'s id is the app's name and a short hash of where it lives: `nina-todo-f96721e8`. */
58
+ const LOCAL_ID = new RegExp(`^(.+)-[0-9a-f]{${String(PROJECT_ID_HASH_LENGTH)}}$`);
59
+ /**
60
+ * The name part of the id `init` wrote. One project carried two names: `.reticle.json` said
61
+ * `nina-todo-f96721e8` (from the package) while the dashboard said `app` (the folder), so the person
62
+ * looked for one and the list showed the other. The dashboard now takes the name `init` wrote.
63
+ */
64
+ function nameOfLocalId(localProjectId) {
65
+ return LOCAL_ID.exec(localProjectId)?.[1];
66
+ }
67
+ export const CreatedProjectSchema = z.object({ projectId: z.string(), name: z.string() });
68
+ const ProjectsListSchema = z.object({
69
+ projects: z.array(z.object({ projectId: z.string(), name: z.string(), repo: z.string().optional() })),
70
+ });
71
+ /** ` in workspace "<name>"`, or nothing when no name is known. */
72
+ export const inWorkspace = (name) => name === undefined || 0 === name.length ? '' : ` in workspace "${name}"`;
73
+ /** Characters of the repository identity: enough to tell repositories apart, nothing to read. */
74
+ const REPO_ID_CHARS = 16;
75
+ /**
76
+ * Which repository, and which folder in it, a project folder is: a hash of the `origin` remote and
77
+ * the folder's path inside the checkout, so every clone of one app agrees and two different apps
78
+ * both named `web` do not. Undefined outside git or with no remote. Neither leaves the machine.
79
+ */
80
+ export function repoIdentity(dir) {
81
+ try {
82
+ const git = (...args) => execFileSync('git', args, {
83
+ cwd: dir,
84
+ encoding: 'utf8',
85
+ stdio: ['ignore', 'pipe', 'ignore'],
86
+ }).trim();
87
+ const remote = git('config', '--get', 'remote.origin.url')
88
+ .replace(/\.git$/, '')
89
+ .replace(/^[a-z+]+:\/\/|^[^@]+@/i, '')
90
+ .replace(':', '/')
91
+ .toLowerCase();
92
+ if (0 === remote.length)
93
+ return undefined;
94
+ const inside = relative(git('rev-parse', '--show-toplevel'), dir).split('\\').join('/');
95
+ return createHash('sha256')
96
+ .update(`${remote}\u0000${inside}`)
97
+ .digest('hex')
98
+ .slice(0, REPO_ID_CHARS);
99
+ }
100
+ catch {
101
+ return undefined;
102
+ }
103
+ }
104
+ /**
105
+ * The id for the project the caller named, creating it if it does not exist yet — and saying so,
106
+ * in which workspace. A project of that NAME made for another repository is not reused: two apps
107
+ * whose package is `web` shared one dashboard project. A project with no recorded repository, or an
108
+ * id named outright, is reused as before.
109
+ */
110
+ /** Projects named when creating one was refused. */
111
+ const MAX_NAMED = 5;
112
+ export async function resolveProjectId(url, token, wanted, workspace, repo,
113
+ /**
114
+ * The id `init` wrote into `.reticle.json`, for a project created by default: the platform is
115
+ * asked to keep it, so the folder and the dashboard name one project by one id. A platform that
116
+ * does not know the field ignores it and answers with its own, which is what gets linked.
117
+ */
118
+ localId) {
119
+ const { projects } = ProjectsListSchema.parse(await api('GET', `${url}/v1/projects`, token));
120
+ const lc = wanted.toLowerCase();
121
+ const holding = localId === undefined ? undefined : projects.find((p) => p.projectId === localId);
122
+ if (holding !== undefined)
123
+ return holding.projectId;
124
+ const match = projects.find((p) => p.projectId === wanted ||
125
+ (p.name.toLowerCase() === lc &&
126
+ (repo === undefined || p.repo === undefined || p.repo === repo)));
127
+ if (match !== undefined)
128
+ return match.projectId;
129
+ let answer;
130
+ try {
131
+ answer = await api('POST', `${url}/v1/projects`, token, {
132
+ name: wanted,
133
+ ...(repo === undefined ? {} : { repo }),
134
+ ...(localId === undefined ? {} : { projectId: localId }),
135
+ });
136
+ }
137
+ catch (error) {
138
+ // Refused to create one (a contributor): the platform's words, then the step that works.
139
+ if (error instanceof CredentialRefusedError ||
140
+ !(error instanceof Error) ||
141
+ 0 === projects.length)
142
+ throw error;
143
+ const names = projects.map((p) => p.name).slice(0, MAX_NAMED);
144
+ throw new Error(`${error.message}\nTo link one that exists: ${names.map((n) => `\`reticle connect --project ${n}\``).join(', ')}`);
145
+ }
146
+ const created = CreatedProjectSchema.parse(answer);
147
+ hint(`created project "${wanted}" (${created.projectId})${inWorkspace(workspace)} — it did not exist yet`);
148
+ return created.projectId;
149
+ }
@@ -14,7 +14,23 @@ import type { OnboardingStep } from '@reticlehq/core/telemetry';
14
14
  * so the entry point supplies it and every layer below stays a function of its arguments.
15
15
  */
16
16
  export type StepReporter = (step: OnboardingStep) => void;
17
- export declare function handleSetupMcp(reportStep: StepReporter, standalone?: boolean): void;
17
+ /** How many coding agents on this machine have Reticle's tools after this run. */
18
+ export declare function handleSetupMcp(reportStep: StepReporter, standalone?: boolean): number;
19
+ /**
20
+ * The one line the launchers read and strip: what they cannot know and the next steps depend on.
21
+ *
22
+ * The launchers own the closing words (served from main, so wording changes on merge) and used to
23
+ * print "restart your coding agent" to a machine with none, and "cd your-app" to somebody already
24
+ * standing in it. An older launcher shows this line as is; a launcher reading an older CLI finds no
25
+ * line and keeps its generic wording, so neither half has to ship first.
26
+ */
27
+ export declare const INSTALL_RESULT_PREFIX = "RETICLE_INSTALL";
28
+ /** Whether the folder the installer ran in is an app: `init` runs here, or after a `cd`. */
29
+ export declare const InstallAppHere: {
30
+ readonly HERE: "here";
31
+ readonly NONE: "none";
32
+ };
33
+ export declare function installResultLine(agents: number, cwd: string): string;
18
34
  /**
19
35
  * `reticle setup install` — the Node half of the one-line installer.
20
36
  *