@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
@@ -26,6 +26,11 @@ interface SyncPolicy {
26
26
  * the bug happen again, and a defect nobody else can reproduce is a defect nobody else can fix.
27
27
  */
28
28
  capsules: boolean;
29
+ /**
30
+ * Push each run's step screenshots after the run. Follows `runs` when the link does not say:
31
+ * a project that keeps its runs local has not agreed to send pictures of its pages either.
32
+ */
33
+ screenshots: boolean;
29
34
  }
30
35
  /** Where a verification actually executes. Reserved for the hosted-runner path; default local. */
31
36
  export declare const VerifyMode: {
@@ -40,8 +45,12 @@ export interface ProjectCloud {
40
45
  verify: VerifyMode;
41
46
  /** The cloud project id this project is linked to (for display/logging); null when env-fallback. */
42
47
  projectId: string | null;
48
+ /** The link as one key, cloud + workspace + project (`credentialSlot`); absent when env-fallback. */
49
+ link?: string;
43
50
  /** Why `config` is null, in words a person can act on. Absent when attached. */
44
51
  reason?: string;
52
+ /** Attached, but not with the key the caller exported: said, never silent. */
53
+ note?: string;
45
54
  }
46
55
  /** Look up the API key for a cloud project id in the user credentials map. */
47
56
  /**
@@ -77,7 +86,19 @@ export declare function resolveProjectCloud(fs: FileSystemPort, reticleRoot: str
77
86
  * three lines somewhere they belong. The harness reads it so a machine that has run `reticle link`
78
87
  * needs no exported key — see `withLinkedCredential`.
79
88
  */
80
- export declare const linkedCloudPort: (fs: FileSystemPort, reticleRoot: string, homeDir: string, env: NodeJS.ProcessEnv) => () => Promise<CloudConfig | null>;
89
+ export declare const linkedCloudPort: (fs: FileSystemPort, reticleRoot: string, homeDir: string, env: NodeJS.ProcessEnv) => (root?: string) => Promise<CloudConfig | null>;
90
+ /**
91
+ * The API key a tab's own project resolves to, so a credential is only ever used for its own tabs.
92
+ * A tab whose project cannot be resolved has no key.
93
+ */
94
+ export declare const sessionApiKeyPort: (fs: FileSystemPort, homeDir: string, env: NodeJS.ProcessEnv, rootOf: (id: string) => string) => (sessionId: string) => Promise<string | undefined>;
95
+ /** The platform and key a tab's own project resolves to, or undefined when it is not linked. */
96
+ export declare const sessionCloudPort: (fs: FileSystemPort, homeDir: string, env: NodeJS.ProcessEnv, rootOf: (id: string) => string) => (sessionId: string) => Promise<CloudConfig | undefined>;
97
+ /**
98
+ * The credential for pushing RUNS, or null when this project opted out with `sync.runs: false`.
99
+ * `reticle verify` used the port above and pushed its run and progress regardless of the opt-out.
100
+ */
101
+ export declare const linkedRunsCloudPort: (fs: FileSystemPort, reticleRoot: string, homeDir: string, env: NodeJS.ProcessEnv) => () => Promise<CloudConfig | null>;
81
102
  /**
82
103
  * The environment with this project's resolved credential written into it, for the readers that
83
104
  * take an env record (the panel's model config and harness switch). Handed `process.env` alone,
@@ -17,7 +17,13 @@ import { resolveCloudConfig } from './cloud-sync.js';
17
17
  export const CLOUD_LINK_FILE = ReticleDir.CLOUD_LINK_FILE;
18
18
  /** `~/.reticle/credentials.json` — the user's per-cloud-project API keys (the only secret). */
19
19
  export const CREDENTIALS_FILE = 'credentials.json';
20
- const DEFAULT_SYNC_POLICY = { runs: true, memory: true, flows: true, capsules: true };
20
+ const DEFAULT_SYNC_POLICY = {
21
+ runs: true,
22
+ memory: true,
23
+ flows: true,
24
+ capsules: true,
25
+ screenshots: true,
26
+ };
21
27
  /** Where a verification actually executes. Reserved for the hosted-runner path; default local. */
22
28
  export const VerifyMode = { LOCAL: 'local', SERVER: 'server' };
23
29
  const asBool = (v, fallback) => ('boolean' === typeof v ? v : fallback);
@@ -51,6 +57,7 @@ function parseLink(raw) {
51
57
  memory: asBool(sync.memory, DEFAULT_SYNC_POLICY.memory),
52
58
  flows: asBool(sync.flows, DEFAULT_SYNC_POLICY.flows),
53
59
  capsules: asBool(sync.capsules, DEFAULT_SYNC_POLICY.capsules),
60
+ screenshots: asBool(sync.screenshots, asBool(sync.runs, DEFAULT_SYNC_POLICY.screenshots)),
54
61
  },
55
62
  verify: o.verify === VerifyMode.SERVER ? VerifyMode.SERVER : VerifyMode.LOCAL,
56
63
  };
@@ -135,7 +142,7 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
135
142
  verify: VerifyMode.LOCAL,
136
143
  projectId: null,
137
144
  ...(null === config
138
- ? { reason: 'cloud not attached here: run `reticle link`, or set RETICLE_API_KEY' }
145
+ ? { reason: 'cloud not attached here: run `reticle connect`, or set RETICLE_API_KEY' }
139
146
  : {}),
140
147
  };
141
148
  }
@@ -144,6 +151,7 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
144
151
  memory: link.sync.memory ?? DEFAULT_SYNC_POLICY.memory,
145
152
  flows: link.sync.flows ?? DEFAULT_SYNC_POLICY.flows,
146
153
  capsules: link.sync.capsules ?? DEFAULT_SYNC_POLICY.capsules,
154
+ screenshots: link.sync.screenshots ?? DEFAULT_SYNC_POLICY.screenshots,
147
155
  };
148
156
  const stored = credentialFor(await readJson(fs, join(homeDir, ReticleDir.ROOT, CREDENTIALS_FILE)), link.projectId, link.url, link.orgId);
149
157
  /*
@@ -161,16 +169,22 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
161
169
  ? undefined
162
170
  : fromEnv !== null
163
171
  ? `this repo is linked to ${linkedUrl}, and RETICLE_API_KEY is set for ${fromEnv.url}: ` +
164
- `set RETICLE_CLOUD_URL=${linkedUrl} to use that key here, or run \`reticle login\` for it`
172
+ `set RETICLE_CLOUD_URL=${linkedUrl} to use that key here, or run \`reticle connect\` for it`
165
173
  : `this repo is linked to ${linkedUrl}, and this machine has no key for it: run ` +
166
- '`reticle login`, or set RETICLE_API_KEY' +
174
+ '`reticle connect`, or set RETICLE_API_KEY' +
167
175
  (DEFAULT_PLATFORM_URL === linkedUrl ? '' : ` with RETICLE_CLOUD_URL=${linkedUrl}`);
176
+ const note = stored !== null && fromEnv !== null && fromEnv.apiKey !== stored
177
+ ? `RETICLE_API_KEY is set, but this repo uses the key \`reticle connect\` stored for it: ` +
178
+ 'a stored key wins over the environment, so the exported key was not used'
179
+ : undefined;
168
180
  return {
169
181
  config,
170
182
  policy,
171
183
  verify: link.verify,
172
184
  projectId: link.projectId,
185
+ link: credentialSlot(link.url, link.projectId, link.orgId),
173
186
  ...(reason === undefined ? {} : { reason }),
187
+ ...(note === undefined ? {} : { note }),
174
188
  };
175
189
  }
176
190
  /**
@@ -181,7 +195,22 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
181
195
  * three lines somewhere they belong. The harness reads it so a machine that has run `reticle link`
182
196
  * needs no exported key — see `withLinkedCredential`.
183
197
  */
184
- export const linkedCloudPort = (fs, reticleRoot, homeDir, env) => async () => (await resolveProjectCloud(fs, reticleRoot, homeDir, env)).config;
198
+ export const linkedCloudPort = (fs, reticleRoot, homeDir, env) => async (root) => (await resolveProjectCloud(fs, root ?? reticleRoot, homeDir, env)).config;
199
+ /**
200
+ * The API key a tab's own project resolves to, so a credential is only ever used for its own tabs.
201
+ * A tab whose project cannot be resolved has no key.
202
+ */
203
+ export const sessionApiKeyPort = (fs, homeDir, env, rootOf) => async (sessionId) => (await sessionCloudPort(fs, homeDir, env, rootOf)(sessionId))?.apiKey;
204
+ /** The platform and key a tab's own project resolves to, or undefined when it is not linked. */
205
+ export const sessionCloudPort = (fs, homeDir, env, rootOf) => async (sessionId) => (await resolveProjectCloud(fs, rootOf(sessionId), homeDir, env)).config ?? undefined;
206
+ /**
207
+ * The credential for pushing RUNS, or null when this project opted out with `sync.runs: false`.
208
+ * `reticle verify` used the port above and pushed its run and progress regardless of the opt-out.
209
+ */
210
+ export const linkedRunsCloudPort = (fs, reticleRoot, homeDir, env) => async () => {
211
+ const cloud = await resolveProjectCloud(fs, reticleRoot, homeDir, env);
212
+ return cloud.policy.runs ? cloud.config : null;
213
+ };
185
214
  /**
186
215
  * The environment with this project's resolved credential written into it, for the readers that
187
216
  * take an env record (the panel's model config and harness switch). Handed `process.env` alone,
@@ -1,13 +1,3 @@
1
- /**
2
- * Optional cloud sync for saved flows. "Logged in" here means the two cloud env vars are set (written by
3
- * `reticle login` later; settable by hand today): the hosted URL and an API key from the Reticle
4
- * dashboard. When present, a freshly-saved flow is pushed to `POST /v1/flows` so the team's regression
5
- * suite lives in the cloud — surviving refactors and runnable in CI. When absent, sync is a no-op and
6
- * everything stays 100% local (the "no phone-home" default: nothing leaves the machine unless you opt in).
7
- *
8
- * Sync is best-effort: a network failure NEVER fails the local save. The flow is already on disk; the
9
- * cloud copy is an enhancement, so a push error is logged and swallowed.
10
- */
11
1
  import { z } from 'zod';
12
2
  import { type FlowFile, type ReticleVerificationRun, type RunRecord, type VerifyProgressEvent } from '@reticlehq/core';
13
3
  /**
@@ -40,6 +30,19 @@ export declare function cloudFetch(url: string, init: {
40
30
  headers: Record<string, string>;
41
31
  body?: string;
42
32
  }, timeoutMs?: number): Promise<Response>;
33
+ /**
34
+ * One sync request, status and body, under the same timeout every cloud call has. The sync daemon
35
+ * and `reticle sync` each called a bare `fetch`: one accepted-but-silent connection left the daemon's
36
+ * cycle running forever, and the dashboard stopped updating with nothing logged.
37
+ */
38
+ export declare function syncRequest(url: string, init: {
39
+ method: string;
40
+ headers: Record<string, string>;
41
+ body?: string;
42
+ }, timeoutMs?: number): Promise<{
43
+ status: number;
44
+ text: string;
45
+ }>;
43
46
  export declare const SyncOutcome: {
44
47
  readonly SYNCED: "synced";
45
48
  readonly SKIPPED: "skipped";
@@ -123,20 +126,20 @@ declare const ServerVerificationSchema: z.ZodObject<{
123
126
  }>, "many">;
124
127
  summary: z.ZodString;
125
128
  }, "strip", z.ZodTypeAny, {
126
- verificationId: string;
127
- verdict: string | null;
128
129
  flows: {
129
130
  status: string;
130
131
  name: string;
131
132
  }[];
132
- summary: string;
133
- }, {
134
133
  verificationId: string;
135
134
  verdict: string | null;
135
+ summary: string;
136
+ }, {
136
137
  flows: {
137
138
  status: string;
138
139
  name: string;
139
140
  }[];
141
+ verificationId: string;
142
+ verdict: string | null;
140
143
  summary: string;
141
144
  }>;
142
145
  export type ServerVerification = z.infer<typeof ServerVerificationSchema>;
@@ -8,8 +8,9 @@
8
8
  * Sync is best-effort: a network failure NEVER fails the local save. The flow is already on disk; the
9
9
  * cloud copy is an enhancement, so a push error is logged and swallowed.
10
10
  */
11
+ import { shareableRun } from '@reticlehq/core/artifacts';
11
12
  import { z } from 'zod';
12
- import { VERIFY_PROGRESS_MAX_EVENTS, platformCredentialFrom, } from '@reticlehq/core';
13
+ import { VERIFY_PROGRESS_MAX_EVENTS, platformCredentialFrom, flowJsonReplacer, } from '@reticlehq/core';
13
14
  /**
14
15
  * Env var names — the presence of BOTH is what "logged in" means for cloud sync.
15
16
  *
@@ -60,7 +61,7 @@ const TIMEOUT_ERROR_NAMES = new Set(['TimeoutError', 'AbortError']);
60
61
  const UNSENDABLE_HEADER_CHAR = /[^ -ÿ]/;
61
62
  /** Which knob holds the credential behind a header, so the error can name the thing to go and edit. */
62
63
  const CREDENTIAL_SOURCE = {
63
- authorization: `${CloudEnv.KEY} (or the session from \`reticle login\`)`,
64
+ authorization: `${CloudEnv.KEY} (or the session from \`reticle connect\`)`,
64
65
  };
65
66
  /**
66
67
  * Refuse a request whose headers cannot be encoded, before it is sent.
@@ -97,6 +98,15 @@ export async function cloudFetch(url, init, timeoutMs = CLOUD_FETCH_TIMEOUT_MS)
97
98
  throw err;
98
99
  }
99
100
  }
101
+ /**
102
+ * One sync request, status and body, under the same timeout every cloud call has. The sync daemon
103
+ * and `reticle sync` each called a bare `fetch`: one accepted-but-silent connection left the daemon's
104
+ * cycle running forever, and the dashboard stopped updating with nothing logged.
105
+ */
106
+ export async function syncRequest(url, init, timeoutMs = CLOUD_FETCH_TIMEOUT_MS) {
107
+ const res = await cloudFetch(url, init, timeoutMs);
108
+ return { status: res.status, text: await res.text() };
109
+ }
100
110
  export const SyncOutcome = {
101
111
  SYNCED: 'synced',
102
112
  SKIPPED: 'skipped',
@@ -116,7 +126,7 @@ export async function syncFlowToCloud(flow, config, projectId, fetchImpl) {
116
126
  'content-type': 'application/json',
117
127
  authorization: `Bearer ${config.apiKey}`,
118
128
  },
119
- body: JSON.stringify(projectId === undefined ? { flow } : { flow, projectId }),
129
+ body: JSON.stringify(projectId === undefined ? { flow } : { flow, projectId }, flowJsonReplacer),
120
130
  });
121
131
  return res.ok
122
132
  ? { outcome: SyncOutcome.SYNCED, status: res.status }
@@ -143,7 +153,8 @@ export async function syncRunToCloud(run, config, fetchImpl) {
143
153
  'content-type': 'application/json',
144
154
  authorization: `Bearer ${config.apiKey}`,
145
155
  },
146
- body: JSON.stringify(run),
156
+ // The prompt context leaves the machine only when the project opted in.
157
+ body: JSON.stringify(shareableRun(run)),
147
158
  });
148
159
  return res.ok
149
160
  ? { outcome: SyncOutcome.SYNCED, status: res.status }
@@ -1,3 +1,24 @@
1
+ /**
2
+ * The harness switch, cached for a HUD that reads it inline.
3
+ *
4
+ * `fetchPlatformConfig` already asks the platform and parses the answer; this adds the one thing the
5
+ * impact snapshot needs and the drive path does not — a SYNCHRONOUS read. The snapshot is rebuilt
6
+ * dozens of times a session, the answer changes about as often as somebody opens a settings page,
7
+ * and a panel that awaited the network on every repaint would be a panel that stutters.
8
+ *
9
+ * Deliberately its own cache rather than a shared abstraction with the notices source:
10
+ * two callers with the same caching problem is not yet a pattern, and the day one of them needs a
11
+ * different staleness rule the shared version becomes the awkward one.
12
+ *
13
+ * Every failure answers `undefined`, which the HUD must read as "we have not heard" and render as NO
14
+ * control — never as "off". Showing a switch that cannot be honoured is worse than showing none.
15
+ *
16
+ * The loader arrives as a PORT rather than an import. Reading the platform lives in
17
+ * `features/harness`, and a cloud-memory file reaching into a feature is the reach the directory
18
+ * guard refuses — correctly, and for the same reason it refused the tool surface reaching the other
19
+ * way. Whoever wires the daemon owns both sides and can hand one to the other.
20
+ */
21
+ import type { CreditKind } from '@reticlehq/core';
1
22
  /** Narrowed to what this file stores: the caller's own type is richer and irrelevant here. */
2
23
  export interface HarnessConfigView {
3
24
  provider: string;
@@ -5,8 +26,61 @@ export interface HarnessConfigView {
5
26
  harnessEntitled: boolean;
6
27
  /** Whether the platform holds a key for `provider`. Entitlement is not readiness — see the offer. */
7
28
  providerReady: boolean;
29
+ credits?: {
30
+ used: number;
31
+ limit: number;
32
+ kind?: CreditKind | undefined;
33
+ endsAt?: number;
34
+ };
35
+ /** The platform's coverage gate, when it sent one: the HUD prefers it to the local score. */
36
+ gate?: {
37
+ unlocked: boolean;
38
+ percent?: number;
39
+ reason?: string;
40
+ prompt?: string;
41
+ };
42
+ plan?: {
43
+ kind: CreditKind;
44
+ daysLeft?: number;
45
+ seats?: number;
46
+ };
47
+ harnessRuns?: number;
48
+ memoryEntries?: number;
8
49
  }
50
+ /**
51
+ * The answer as the HUD is pushed it: the grant's end date becomes whole days left, counted on the
52
+ * daemon's clock (the HUD has none worth trusting for this). No end date, no days. Pure.
53
+ */
54
+ export declare function configForHud(config: HarnessConfigView, now: number): Omit<HarnessConfigView, 'credits'> & {
55
+ credits?: {
56
+ used: number;
57
+ limit: number;
58
+ kind?: CreditKind | undefined;
59
+ daysLeft?: number;
60
+ };
61
+ };
9
62
  export interface ConfigSource {
10
63
  read(): HarnessConfigView | undefined;
11
64
  }
12
- export declare function harnessConfigSource(load: () => Promise<HarnessConfigView | undefined>, now?: () => number): ConfigSource;
65
+ export interface MutableConfigSource extends ConfigSource {
66
+ applyWrite(enabled: boolean): void;
67
+ recheck(): void;
68
+ subscribe(listener: () => void): () => void;
69
+ /** Re-read in the background, telling listeners only when the answer changed. */
70
+ poll(): void;
71
+ }
72
+ export declare function harnessConfigSource(load: () => Promise<HarnessConfigView | undefined>, now?: () => number): MutableConfigSource;
73
+ export type ConfigsByRoot = (root: string) => MutableConfigSource;
74
+ /**
75
+ * One live config source per project root, created on first ask; `onChange` hears every update.
76
+ *
77
+ * The platform read arrives as `load`, so this cache never reaches for the harness feature that
78
+ * performs it: the daemon, which owns both, joins them. It sat inline in `start` and `startDaemon`.
79
+ */
80
+ export declare function harnessConfigsByRoot(load: (root: string) => Promise<HarnessConfigView | undefined>, onChange?: (root: string) => void): ConfigsByRoot;
81
+ /**
82
+ * The HUD's harness switch, written to the platform with this project's credential. Nothing is
83
+ * awaited: an accepted write updates the cache at once, and a refused or failed one re-reads the
84
+ * platform so the switch springs back to the truth rather than staying where the user left it.
85
+ */
86
+ export declare function applyHarnessSwitch(configs: ConfigsByRoot, root: string, enabled: boolean, envFor: () => Promise<Record<string, string | undefined>>): void;
@@ -1,48 +1,69 @@
1
- /**
2
- * The harness switch, cached for a HUD that reads it inline.
3
- *
4
- * `fetchPlatformConfig` already asks the platform and parses the answer; this adds the one thing the
5
- * impact snapshot needs and the drive path does not — a SYNCHRONOUS read. The snapshot is rebuilt
6
- * dozens of times a session, the answer changes about as often as somebody opens a settings page,
7
- * and a panel that awaited the network on every repaint would be a panel that stutters.
8
- *
9
- * Deliberately the same shape as `harnessOfferSource` next door rather than a shared abstraction:
10
- * two callers with the same caching problem is not yet a pattern, and the day one of them needs a
11
- * different staleness rule the shared version becomes the awkward one.
12
- *
13
- * Every failure answers `undefined`, which the HUD must read as "we have not heard" and render as NO
14
- * control — never as "off". Showing a switch that cannot be honoured is worse than showing none.
15
- *
16
- * The loader arrives as a PORT rather than an import. Reading the platform lives in
17
- * `features/harness`, and a cloud-memory file reaching into a feature is the reach the directory
18
- * guard refuses — correctly, and for the same reason it refused the tool surface reaching the other
19
- * way. Whoever wires the daemon owns both sides and can hand one to the other.
20
- */
1
+ import { writeHarnessSwitch } from './harness-switch.js';
21
2
  /** How long a cached answer is trusted. A person who just changed it expects the panel to notice. */
22
3
  const FRESH_MS = 30 * 1_000;
4
+ const DAY_MS = 24 * 60 * 60 * 1_000;
5
+ /**
6
+ * The answer as the HUD is pushed it: the grant's end date becomes whole days left, counted on the
7
+ * daemon's clock (the HUD has none worth trusting for this). No end date, no days. Pure.
8
+ */
9
+ export function configForHud(config, now) {
10
+ if (config.credits === undefined)
11
+ return config;
12
+ const { endsAt, ...credits } = config.credits;
13
+ return {
14
+ ...config,
15
+ credits: endsAt === undefined
16
+ ? credits
17
+ : { ...credits, daysLeft: Math.max(0, Math.ceil((endsAt - now) / DAY_MS)) },
18
+ };
19
+ }
23
20
  export function harnessConfigSource(load, now = () => Date.now()) {
24
21
  let cached;
25
22
  // `undefined` rather than 0: "never asked" is a different state from "asked at the epoch", and
26
23
  // conflating them made a source with an injected clock never take its first read.
27
24
  let fetchedAt;
28
25
  let inFlight = false;
26
+ let queuedRefresh = false;
27
+ let revision = 0;
28
+ /** Set for a background poll, so an unchanged answer does not repaint every HUD. */
29
+ let quiet = false;
30
+ const listeners = new Set();
31
+ const notify = () => {
32
+ for (const listener of listeners)
33
+ listener();
34
+ };
29
35
  const refresh = () => {
30
36
  if (inFlight)
31
37
  return;
32
38
  inFlight = true;
39
+ const startedAtRevision = revision;
33
40
  void load()
34
41
  .then((cfg) => {
35
42
  // A failed read keeps the LAST good answer rather than blanking the control mid-session:
36
43
  // one dropped request is not evidence that somebody changed their mind.
37
- if (cfg !== undefined)
38
- cached = cfg;
39
- fetchedAt = now();
44
+ const before = JSON.stringify(cached);
45
+ if (startedAtRevision === revision) {
46
+ if (cfg !== undefined)
47
+ cached = cfg;
48
+ fetchedAt = now();
49
+ }
50
+ // A poll that learned nothing new repaints nothing; anything else is said at once.
51
+ if (!quiet || before !== JSON.stringify(cached))
52
+ notify();
53
+ quiet = false;
40
54
  })
41
55
  .catch(() => {
42
- fetchedAt = now();
56
+ if (startedAtRevision === revision)
57
+ fetchedAt = now();
58
+ quiet = false;
59
+ notify();
43
60
  })
44
61
  .finally(() => {
45
62
  inFlight = false;
63
+ if (queuedRefresh) {
64
+ queuedRefresh = false;
65
+ refresh();
66
+ }
46
67
  });
47
68
  };
48
69
  // Asked at construction, not first read: the daemon pushes a snapshot the instant a session
@@ -54,5 +75,75 @@ export function harnessConfigSource(load, now = () => Date.now()) {
54
75
  refresh();
55
76
  return cached;
56
77
  },
78
+ applyWrite(enabled) {
79
+ revision += 1;
80
+ if (cached !== undefined)
81
+ cached = { ...cached, harnessEnabled: enabled };
82
+ fetchedAt = now();
83
+ notify();
84
+ if (cached === undefined) {
85
+ if (inFlight)
86
+ queuedRefresh = true;
87
+ else
88
+ refresh();
89
+ }
90
+ },
91
+ recheck() {
92
+ notify(); // Roll back an optimistic HUD switch immediately, even if the GET is slow.
93
+ if (inFlight)
94
+ queuedRefresh = true;
95
+ else
96
+ refresh();
97
+ },
98
+ subscribe(listener) {
99
+ listeners.add(listener);
100
+ return () => listeners.delete(listener);
101
+ },
102
+ poll() {
103
+ if (inFlight)
104
+ return;
105
+ quiet = true;
106
+ refresh();
107
+ },
108
+ };
109
+ }
110
+ /**
111
+ * One live config source per project root, created on first ask; `onChange` hears every update.
112
+ *
113
+ * The platform read arrives as `load`, so this cache never reaches for the harness feature that
114
+ * performs it: the daemon, which owns both, joins them. It sat inline in `start` and `startDaemon`.
115
+ */
116
+ export function harnessConfigsByRoot(load, onChange) {
117
+ const sources = new Map();
118
+ return (root) => {
119
+ let source = sources.get(root);
120
+ if (source === undefined) {
121
+ source = harnessConfigSource(() => load(root));
122
+ if (onChange !== undefined) {
123
+ source.subscribe(() => onChange(root));
124
+ // The switch can be flipped anywhere: the console, another tab, the API. A HUD that only
125
+ // learned of it on its next tool call showed Harness ON over a drive that had stopped.
126
+ const live = source;
127
+ setInterval(() => live.poll(), FRESH_MS).unref();
128
+ }
129
+ sources.set(root, source);
130
+ }
131
+ return source;
57
132
  };
58
133
  }
134
+ /**
135
+ * The HUD's harness switch, written to the platform with this project's credential. Nothing is
136
+ * awaited: an accepted write updates the cache at once, and a refused or failed one re-reads the
137
+ * platform so the switch springs back to the truth rather than staying where the user left it.
138
+ */
139
+ export function applyHarnessSwitch(configs, root, enabled, envFor) {
140
+ void envFor()
141
+ .then((env) => writeHarnessSwitch(env, enabled))
142
+ .then((saved) => {
143
+ if (saved)
144
+ configs(root).applyWrite(enabled);
145
+ else
146
+ configs(root).recheck();
147
+ })
148
+ .catch(() => configs(root).recheck());
149
+ }
@@ -0,0 +1,21 @@
1
+ import { type HudNoticeEntry } from '@reticlehq/core/hud';
2
+ /**
3
+ * The largest body the daemon will read or keep. The real file is a few hundred bytes; anything near
4
+ * this is not a notices file, and the cache on disk must not grow with whatever the network sends.
5
+ */
6
+ export declare const MAX_NOTICES_BODY_BYTES: number;
7
+ export type NoticesLoad = (url: string, etag: string | undefined) => Promise<{
8
+ status: number;
9
+ etag?: string | undefined;
10
+ body?: string | undefined;
11
+ }>;
12
+ export interface NoticesSource {
13
+ /** The entries this daemon knows, unfiltered. Never throws, never waits. */
14
+ read(): HudNoticeEntry[];
15
+ }
16
+ export declare function hudNoticesSource(opts: {
17
+ cacheFile: string;
18
+ now?: () => number;
19
+ load?: NoticesLoad;
20
+ url?: string;
21
+ }): NoticesSource;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * The HUD rail's notices, as the daemon keeps them.
3
+ *
4
+ * Read synchronously (the snapshot is rebuilt many times a session), served from a disk cache that
5
+ * survives restarts, and revalidated in the background with the stored ETag, so an unchanged file
6
+ * costs a 304 and no body. A failed or garbled refresh keeps the last good copy: the rail is
7
+ * marketing, and nothing about it may block or break a session. See core `hud-notices.ts`.
8
+ */
9
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
10
+ import { dirname } from 'node:path';
11
+ import { ReticleEnv } from '@reticlehq/core';
12
+ import { HUD_NOTICES_URL, NOTICES_FILE_VERSION, parseHudNotices, } from '@reticlehq/core/hud';
13
+ /** How long a copy is trusted before it is revalidated. Notices change over days, not minutes. */
14
+ const FRESH_MS = 6 * 60 * 60 * 1_000;
15
+ const TIMEOUT_MS = 5_000;
16
+ /**
17
+ * The largest body the daemon will read or keep. The real file is a few hundred bytes; anything near
18
+ * this is not a notices file, and the cache on disk must not grow with whatever the network sends.
19
+ */
20
+ export const MAX_NOTICES_BODY_BYTES = 64 * 1_024;
21
+ /** Overrides the notices URL: self-hosting, staging, tests. */
22
+ const NOTICES_URL_ENV = 'RETICLE_HUD_NOTICES_URL';
23
+ /**
24
+ * The same opt-outs telemetry honours. The notices file carries nothing about anybody, but it is a
25
+ * request to reticle.sh, and somebody who switched Reticle's outbound calls off asked for none.
26
+ */
27
+ function outboundOff(env) {
28
+ const telemetry = (env[ReticleEnv.TELEMETRY] ?? '').toLowerCase();
29
+ const dnt = env[ReticleEnv.DO_NOT_TRACK];
30
+ return (['0', 'false', 'off'].includes(telemetry) ||
31
+ ('string' === typeof dnt && dnt !== '' && dnt !== '0'));
32
+ }
33
+ const defaultLoad = async (url, etag) => {
34
+ const res = await fetch(url, {
35
+ headers: etag === undefined ? {} : { 'if-none-match': etag },
36
+ signal: AbortSignal.timeout(TIMEOUT_MS),
37
+ });
38
+ return {
39
+ status: res.status,
40
+ etag: res.headers.get('etag') ?? undefined,
41
+ body: 304 === res.status ? undefined : await res.text(),
42
+ };
43
+ };
44
+ function readCache(path) {
45
+ try {
46
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
47
+ if ('object' !== typeof raw || null === raw)
48
+ return undefined;
49
+ const record = raw;
50
+ const fetchedAt = record['fetchedAt'];
51
+ const etag = record['etag'];
52
+ return {
53
+ fetchedAt: 'number' === typeof fetchedAt ? fetchedAt : 0,
54
+ ...('string' === typeof etag ? { etag } : {}),
55
+ file: record['file'],
56
+ };
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ }
62
+ function writeCache(path, cached) {
63
+ try {
64
+ mkdirSync(dirname(path), { recursive: true });
65
+ writeFileSync(path, JSON.stringify(cached));
66
+ }
67
+ catch {
68
+ /* a cache that cannot be written is a fetch next time, not an error */
69
+ }
70
+ }
71
+ export function hudNoticesSource(opts) {
72
+ const now = opts.now ?? (() => Date.now());
73
+ const load = opts.load ?? defaultLoad;
74
+ const url = opts.url ?? process.env[NOTICES_URL_ENV] ?? HUD_NOTICES_URL;
75
+ let cached = readCache(opts.cacheFile);
76
+ let entries = cached === undefined ? [] : parseHudNotices(cached.file);
77
+ let inFlight = false;
78
+ let askedAt;
79
+ const refresh = () => {
80
+ inFlight = true;
81
+ askedAt = now();
82
+ void load(url, cached?.etag)
83
+ .then((answer) => {
84
+ if (304 === answer.status && cached !== undefined) {
85
+ cached = { ...cached, fetchedAt: now() };
86
+ writeCache(opts.cacheFile, cached);
87
+ return;
88
+ }
89
+ if (200 !== answer.status || answer.body === undefined)
90
+ return;
91
+ if (MAX_NOTICES_BODY_BYTES < Buffer.byteLength(answer.body))
92
+ return;
93
+ let file;
94
+ try {
95
+ file = JSON.parse(answer.body);
96
+ }
97
+ catch {
98
+ return;
99
+ }
100
+ // An unreadable file keeps the last good notices rather than emptying the rail.
101
+ const parsed = parseHudNotices(file);
102
+ if (0 === parsed.length && 0 < entries.length)
103
+ return;
104
+ entries = parsed;
105
+ // The cache holds what VALIDATED, rebuilt from the schema's output, never the body itself:
106
+ // unknown fields and rejected entries in a network answer do not reach the disk.
107
+ cached = {
108
+ etag: answer.etag,
109
+ fetchedAt: now(),
110
+ file: { version: NOTICES_FILE_VERSION, notices: parsed },
111
+ };
112
+ writeCache(opts.cacheFile, cached);
113
+ })
114
+ .catch(() => undefined)
115
+ .finally(() => {
116
+ inFlight = false;
117
+ });
118
+ };
119
+ return {
120
+ read() {
121
+ const last = Math.max(cached?.fetchedAt ?? 0, askedAt ?? Number.NEGATIVE_INFINITY);
122
+ const stale = cached === undefined && askedAt === undefined ? true : FRESH_MS <= now() - last;
123
+ if (!inFlight && stale && !outboundOff(process.env))
124
+ refresh();
125
+ return entries;
126
+ },
127
+ };
128
+ }