@reticlehq/server 3.6.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 (614) hide show
  1. package/SKILL.md +122 -123
  2. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  3. package/dist/command/cli/adhoc-suite.js +42 -7
  4. package/dist/command/cli/adhoc-verdict.d.ts +18 -2
  5. package/dist/command/cli/adhoc-verdict.js +70 -6
  6. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  7. package/dist/command/cli/answers/gate-exit.js +45 -0
  8. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  9. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  10. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  11. package/dist/command/cli/auth/device-flow.js +17 -0
  12. package/dist/command/cli/cli-doctor.js +14 -0
  13. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  14. package/dist/command/cli/cli-flow-commands.js +28 -105
  15. package/dist/command/cli/cli-kill.js +3 -2
  16. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  17. package/dist/command/cli/cli-parse-grammar.js +75 -0
  18. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  19. package/dist/command/cli/cli-parse-verify.js +18 -0
  20. package/dist/command/cli/cli-parse.d.ts +19 -28
  21. package/dist/command/cli/cli-parse.js +82 -182
  22. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  23. package/dist/command/cli/cli-update-commands.js +61 -9
  24. package/dist/command/cli/cli-usage.d.ts +33 -0
  25. package/dist/command/cli/cli-usage.js +287 -0
  26. package/dist/command/cli/cli-verify.d.ts +34 -4
  27. package/dist/command/cli/cli-verify.js +81 -12
  28. package/dist/command/cli/cloud-cli.d.ts +13 -0
  29. package/dist/command/cli/cloud-cli.js +145 -333
  30. package/dist/command/cli/cloud-kit.d.ts +12 -0
  31. package/dist/command/cli/cloud-kit.js +41 -2
  32. package/dist/command/cli/cloud-link.d.ts +57 -0
  33. package/dist/command/cli/cloud-link.js +308 -0
  34. package/dist/command/cli/cloud-login.d.ts +15 -1
  35. package/dist/command/cli/cloud-login.js +67 -13
  36. package/dist/command/cli/context-command.d.ts +1 -0
  37. package/dist/command/cli/context-command.js +33 -0
  38. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  39. package/dist/command/cli/daemon-start-options.js +24 -3
  40. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  41. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  42. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  43. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  44. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  45. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  46. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  47. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  48. package/dist/command/cli/known-regression.d.ts +13 -0
  49. package/dist/command/cli/known-regression.js +34 -0
  50. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  51. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  52. package/dist/command/cli/lifecycle/daemon-lifecycle.js +11 -2
  53. package/dist/command/cli/mcp-command.d.ts +6 -0
  54. package/dist/command/cli/mcp-command.js +13 -5
  55. package/dist/command/cli/ports/port-holder.js +1 -1
  56. package/dist/command/cli/project-name.d.ts +29 -1
  57. package/dist/command/cli/project-name.js +107 -2
  58. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  59. package/dist/command/cli/setup-mcp-cli.js +29 -8
  60. package/dist/command/cli/status/status-lines.d.ts +1 -0
  61. package/dist/command/cli/status/status-lines.js +47 -2
  62. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  63. package/dist/command/cli/status/workspace-links.js +29 -0
  64. package/dist/command/cli/try-command.d.ts +96 -0
  65. package/dist/command/cli/try-command.js +362 -0
  66. package/dist/command/cli/tutorial.d.ts +0 -100
  67. package/dist/command/cli/tutorial.js +0 -178
  68. package/dist/command/cli/verify-results.d.ts +19 -0
  69. package/dist/command/cli/verify-results.js +29 -0
  70. package/dist/command/cli-onboarding.d.ts +0 -11
  71. package/dist/command/cli-onboarding.js +0 -15
  72. package/dist/command/cli.d.ts +14 -0
  73. package/dist/command/cli.js +103 -83
  74. package/dist/command/daemon/daemon-resilience.js +4 -4
  75. package/dist/command/daemon/daemon-resolve.d.ts +9 -1
  76. package/dist/command/daemon/daemon-resolve.js +49 -10
  77. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  78. package/dist/command/setup/bringup/bridge-port.js +13 -3
  79. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  80. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  81. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  82. package/dist/command/setup/init/agent-restart.js +28 -0
  83. package/dist/command/setup/init/init-port.d.ts +10 -1
  84. package/dist/command/setup/init/init-port.js +22 -2
  85. package/dist/command/setup/init/init-runtime.d.ts +12 -2
  86. package/dist/command/setup/init/init-runtime.js +96 -37
  87. package/dist/command/setup/node-effects.d.ts +2 -0
  88. package/dist/command/setup/node-effects.js +36 -8
  89. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  90. package/dist/command/setup/probe/existing-app.js +14 -0
  91. package/dist/command/setup/remaining-steps.js +1 -1
  92. package/dist/command/setup/run-setup.d.ts +29 -9
  93. package/dist/command/setup/run-setup.js +34 -28
  94. package/dist/command/setup/setup-command.d.ts +23 -0
  95. package/dist/command/setup/setup-command.js +57 -4
  96. package/dist/command/setup/setup-mcp.js +25 -2
  97. package/dist/command/setup/tauri-signing.d.ts +19 -0
  98. package/dist/command/setup/tauri-signing.js +79 -0
  99. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  100. package/dist/command/setup/terminal/listeners.js +37 -6
  101. package/dist/command/update/update-nudge.d.ts +9 -0
  102. package/dist/command/update/update-nudge.js +1 -1
  103. package/dist/command/update/updater.js +11 -15
  104. package/dist/command/version/version-nudge.js +3 -0
  105. package/dist/command/version/version-skew.d.ts +20 -1
  106. package/dist/command/version/version-skew.js +38 -2
  107. package/dist/features/crawl/crawl.js +14 -1
  108. package/dist/features/exhaust/ledger.d.ts +14 -14
  109. package/dist/features/harness/drive-report.d.ts +39 -5
  110. package/dist/features/harness/drive-report.js +271 -54
  111. package/dist/features/harness/drive-runs.d.ts +120 -0
  112. package/dist/features/harness/drive-runs.js +289 -0
  113. package/dist/features/harness/drivers.d.ts +1 -1
  114. package/dist/features/harness/drivers.js +1 -1
  115. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  116. package/dist/features/harness/explore/console-pages.js +146 -0
  117. package/dist/features/harness/explore/disparity.d.ts +19 -0
  118. package/dist/features/harness/explore/disparity.js +71 -0
  119. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  120. package/dist/features/harness/explore/fake-app.js +49 -0
  121. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  122. package/dist/features/harness/explore/goal-search.js +144 -0
  123. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  124. package/dist/features/harness/explore/page-tree.js +148 -0
  125. package/dist/features/harness/explore/site-map.d.ts +34 -0
  126. package/dist/features/harness/explore/site-map.js +150 -0
  127. package/dist/features/harness/goals.d.ts +68 -7
  128. package/dist/features/harness/goals.js +289 -36
  129. package/dist/features/harness/harness.d.ts +30 -1
  130. package/dist/features/harness/harness.js +141 -7
  131. package/dist/features/harness/platform/local-apps.d.ts +36 -3
  132. package/dist/features/harness/platform/local-apps.js +81 -5
  133. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  134. package/dist/features/harness/platform/persona-credentials.js +69 -0
  135. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  136. package/dist/features/harness/platform/platform-drives.js +114 -0
  137. package/dist/features/harness/platform/refusal.d.ts +52 -0
  138. package/dist/features/harness/platform/refusal.js +71 -0
  139. package/dist/features/harness/platform/remote-drive.d.ts +8 -2
  140. package/dist/features/harness/platform/remote-drive.js +22 -9
  141. package/dist/features/harness/platform/script.d.ts +57 -11
  142. package/dist/features/harness/platform/script.js +144 -12
  143. package/dist/features/harness/platform/server-driver.d.ts +17 -4
  144. package/dist/features/harness/platform/server-driver.js +29 -26
  145. package/dist/features/harness/platform-config.d.ts +38 -5
  146. package/dist/features/harness/platform-config.js +93 -8
  147. package/dist/features/harness/route-guess.d.ts +13 -0
  148. package/dist/features/harness/route-guess.js +49 -0
  149. package/dist/features/harness/script/script-run.d.ts +30 -1
  150. package/dist/features/harness/script/script-run.js +355 -48
  151. package/dist/features/license/license.d.ts +2 -2
  152. package/dist/features/visual/step-shots.d.ts +31 -0
  153. package/dist/features/visual/step-shots.js +231 -0
  154. package/dist/features/visual/visual-tools.js +22 -14
  155. package/dist/hooks/client-directory.d.ts +18 -0
  156. package/dist/hooks/client-directory.js +57 -0
  157. package/dist/hooks/coding-agents.d.ts +34 -0
  158. package/dist/hooks/coding-agents.js +117 -0
  159. package/dist/hooks/driven-by.d.ts +21 -2
  160. package/dist/hooks/driven-by.js +42 -2
  161. package/dist/hooks/hook-bus.d.ts +4 -0
  162. package/dist/hooks/hook-bus.js +18 -0
  163. package/dist/index.d.ts +1 -0
  164. package/dist/index.js +26 -183
  165. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  166. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  167. package/dist/judgement/capsule/causal-summary.js +33 -0
  168. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  169. package/dist/judgement/runs/artifact/build-verification-run.js +20 -4
  170. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  171. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  172. package/dist/judgement/runs/artifact/replay-mapping.js +25 -9
  173. package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
  174. package/dist/judgement/runs/artifact/run-store.js +175 -8
  175. package/dist/judgement/runs/context-tools.js +59 -1
  176. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  177. package/dist/judgement/runs/default-run-id.js +16 -0
  178. package/dist/judgement/runs/drive-run.d.ts +53 -5
  179. package/dist/judgement/runs/drive-run.js +234 -20
  180. package/dist/judgement/runs/resume.d.ts +44 -0
  181. package/dist/judgement/runs/resume.js +137 -0
  182. package/dist/judgement/runs/reticle-runner.js +5 -2
  183. package/dist/judgement/runs/runner-port.d.ts +5 -1
  184. package/dist/judgement/runs/runner-port.js +8 -2
  185. package/dist/judgement/runs/verification-sync.d.ts +2 -0
  186. package/dist/judgement/runs/verification-sync.js +36 -15
  187. package/dist/language/flows/decision.js +2 -1
  188. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  189. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  190. package/dist/language/flows/flow-anchor.d.ts +7 -2
  191. package/dist/language/flows/flow-anchor.js +10 -3
  192. package/dist/language/flows/flow-intent.d.ts +1 -0
  193. package/dist/language/flows/flow-journey.d.ts +6 -0
  194. package/dist/language/flows/flow-journey.js +20 -0
  195. package/dist/language/flows/flow-learning.d.ts +4 -0
  196. package/dist/language/flows/flow-learning.js +37 -3
  197. package/dist/language/flows/flow-replay-run.js +16 -18
  198. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  199. package/dist/language/flows/flow-replay.d.ts +18 -1
  200. package/dist/language/flows/flow-replay.js +22 -7
  201. package/dist/language/flows/flow-result.d.ts +22 -1
  202. package/dist/language/flows/flow-result.js +47 -2
  203. package/dist/language/flows/flow-step-runners.d.ts +2 -0
  204. package/dist/language/flows/flow-step-runners.js +12 -6
  205. package/dist/language/flows/flow-store-for-session.js +5 -1
  206. package/dist/language/flows/flow-tools.d.ts +10 -0
  207. package/dist/language/flows/flow-tools.js +61 -62
  208. package/dist/language/flows/flows.d.ts +16 -1
  209. package/dist/language/flows/flows.js +69 -10
  210. package/dist/language/flows/narrow-write.d.ts +7 -0
  211. package/dist/language/flows/narrow-write.js +36 -1
  212. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  213. package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
  214. package/dist/language/flows/recording/tape/recordings.js +60 -10
  215. package/dist/language/flows/replay.js +29 -6
  216. package/dist/language/flows/single-replay.d.ts +7 -0
  217. package/dist/language/flows/single-replay.js +26 -0
  218. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  219. package/dist/language/flows/verify-change-tools.js +200 -193
  220. package/dist/memory/cloud/cloud-config.d.ts +10 -1
  221. package/dist/memory/cloud/cloud-config.js +19 -5
  222. package/dist/memory/cloud/cloud-sync.js +3 -3
  223. package/dist/memory/cloud/harness-config.d.ts +49 -0
  224. package/dist/memory/cloud/harness-config.js +16 -20
  225. package/dist/memory/cloud/memory-scope.d.ts +17 -0
  226. package/dist/memory/cloud/memory-scope.js +22 -0
  227. package/dist/memory/cloud/sync-cycle.d.ts +32 -4
  228. package/dist/memory/cloud/sync-cycle.js +113 -12
  229. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  230. package/dist/memory/cloud/sync-daemon.js +114 -4
  231. package/dist/memory/cloud/sync-disk.js +26 -2
  232. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  233. package/dist/memory/cloud/sync-screenshots.js +105 -0
  234. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  235. package/dist/memory/cloud/unsynced-roots.js +166 -0
  236. package/dist/memory/impact/account-watch.d.ts +16 -1
  237. package/dist/memory/impact/account-watch.js +26 -1
  238. package/dist/memory/impact/impact-store.d.ts +1 -4
  239. package/dist/memory/impact/impact-store.js +32 -42
  240. package/dist/memory/intent/inline-intent.d.ts +1 -0
  241. package/dist/memory/intent/intent-shard-store.js +16 -4
  242. package/dist/memory/intent/intent-shard.d.ts +12 -0
  243. package/dist/memory/intent/intent-store.d.ts +1 -0
  244. package/dist/memory/intent/intent-tools.js +42 -2
  245. package/dist/memory/intent/open-intents.d.ts +6 -0
  246. package/dist/memory/intent/open-intents.js +10 -1
  247. package/dist/memory/intent/settled-words.d.ts +24 -0
  248. package/dist/memory/intent/settled-words.js +130 -0
  249. package/dist/memory/journal/drive-flow.d.ts +16 -0
  250. package/dist/memory/journal/drive-flow.js +34 -2
  251. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  252. package/dist/memory/journal/drive-run-flush.js +20 -5
  253. package/dist/memory/journal/journal-recorder.js +46 -3
  254. package/dist/memory/journal/on-disk/retention.d.ts +5 -0
  255. package/dist/memory/journal/on-disk/retention.js +27 -2
  256. package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
  257. package/dist/memory/journal/session-end.d.ts +15 -1
  258. package/dist/memory/journal/session-end.js +38 -7
  259. package/dist/memory/project/artifact-root-resolver.js +33 -5
  260. package/dist/memory/project/artifact-root.d.ts +4 -3
  261. package/dist/memory/project/artifact-root.js +2 -2
  262. package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
  263. package/dist/memory/project/dir/reticle-dir.js +23 -2
  264. package/dist/memory/project/link-directory.d.ts +15 -0
  265. package/dist/memory/project/link-directory.js +44 -0
  266. package/dist/memory/project/root-claims.d.ts +6 -0
  267. package/dist/memory/project/root-claims.js +39 -0
  268. package/dist/memory/project/session-root.d.ts +2 -0
  269. package/dist/memory/project/session-root.js +9 -1
  270. package/dist/memory/project/sync-status.d.ts +46 -0
  271. package/dist/memory/project/sync-status.js +135 -1
  272. package/dist/memory/recall/memory-tools.js +46 -3
  273. package/dist/memory/recall/platform-memory.d.ts +34 -0
  274. package/dist/memory/recall/platform-memory.js +139 -0
  275. package/dist/memory/recall/project-memory.js +36 -8
  276. package/dist/portal/bridge/bridge.d.ts +9 -5
  277. package/dist/portal/bridge/bridge.js +66 -23
  278. package/dist/portal/bridge/harness-request.d.ts +23 -0
  279. package/dist/portal/bridge/harness-request.js +27 -0
  280. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  281. package/dist/portal/bridge/wrong-path.js +35 -0
  282. package/dist/portal/input/network-mock-tools.js +11 -2
  283. package/dist/portal/input/real-input.d.ts +2 -0
  284. package/dist/portal/input/real-input.js +13 -10
  285. package/dist/portal/pool/browser-pool.d.ts +48 -0
  286. package/dist/portal/pool/browser-pool.js +120 -2
  287. package/dist/portal/pool/context-permissions.d.ts +33 -0
  288. package/dist/portal/pool/context-permissions.js +33 -0
  289. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  290. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  291. package/dist/portal/pool/playwright-launcher.d.ts +27 -5
  292. package/dist/portal/pool/playwright-launcher.js +59 -14
  293. package/dist/portal/pool/pool-contract.d.ts +21 -1
  294. package/dist/portal/session/agent-link.d.ts +8 -0
  295. package/dist/portal/session/agent-link.js +17 -0
  296. package/dist/portal/session/command-payload.js +6 -1
  297. package/dist/portal/session/daemon-answers.d.ts +3 -3
  298. package/dist/portal/session/daemon-answers.js +4 -2
  299. package/dist/portal/session/dev-server/dev-command.d.ts +9 -0
  300. package/dist/portal/session/dev-server/dev-command.js +27 -1
  301. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  302. package/dist/portal/session/facts/observed-state.js +46 -3
  303. package/dist/portal/session/human/live-control.d.ts +9 -2
  304. package/dist/portal/session/human/live-control.js +12 -3
  305. package/dist/portal/session/live-control-tools.js +82 -13
  306. package/dist/portal/session/narration-args.d.ts +5 -0
  307. package/dist/portal/session/narration-args.js +17 -0
  308. package/dist/portal/session/no-session-diagnosis.d.ts +1 -1
  309. package/dist/portal/session/no-session-diagnosis.js +31 -9
  310. package/dist/portal/session/no-session-next-action.d.ts +20 -0
  311. package/dist/portal/session/no-session-next-action.js +134 -61
  312. package/dist/portal/session/no-session-watch.js +179 -22
  313. package/dist/portal/session/presence/session-lease.js +1 -1
  314. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  315. package/dist/portal/session/recorded-gaps.js +251 -0
  316. package/dist/portal/session/session-health.d.ts +11 -0
  317. package/dist/portal/session/session-health.js +3 -1
  318. package/dist/portal/session/session-info.js +2 -1
  319. package/dist/portal/session/session-manager.d.ts +18 -0
  320. package/dist/portal/session/session-manager.js +54 -3
  321. package/dist/portal/session/session-successor.d.ts +8 -0
  322. package/dist/portal/session/session-successor.js +1 -1
  323. package/dist/portal/session/session.d.ts +15 -28
  324. package/dist/portal/session/session.js +60 -61
  325. package/dist/portal/session/timing/command-timeout.js +25 -1
  326. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  327. package/dist/portal/session/timing/wall-clock.js +1 -1
  328. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  329. package/dist/portal/session/zero-install-first-call.js +88 -0
  330. package/dist/start-options.d.ts +7 -1
  331. package/dist/start-wiring.d.ts +63 -0
  332. package/dist/start-wiring.js +169 -0
  333. package/dist/status-payload.d.ts +13 -1
  334. package/dist/status-payload.js +13 -1
  335. package/dist/surface/http-server.js +7 -1
  336. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  337. package/dist/surface/mcp/attach-memory.js +12 -1
  338. package/dist/surface/mcp/mcp-proxy.d.ts +4 -0
  339. package/dist/surface/mcp/mcp-proxy.js +29 -8
  340. package/dist/surface/mcp/mcp.d.ts +23 -0
  341. package/dist/surface/mcp/mcp.js +34 -4
  342. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  343. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  344. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  345. package/dist/surface/mcp/server-instructions.js +22 -14
  346. package/dist/surface/mcp/shared-params.js +1 -1
  347. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  348. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  349. package/dist/surface/tools/account-tool.d.ts +22 -0
  350. package/dist/surface/tools/account-tool.js +157 -0
  351. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  352. package/dist/surface/tools/act/act-danger.js +38 -1
  353. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  354. package/dist/surface/tools/act/act-observation.js +57 -0
  355. package/dist/surface/tools/act/act-preflight.js +25 -2
  356. package/dist/surface/tools/act/act-target.js +8 -3
  357. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  358. package/dist/surface/tools/act/resolve-target.js +18 -3
  359. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  360. package/dist/surface/tools/act/screen-request.js +113 -0
  361. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  362. package/dist/surface/tools/act/sequence-grade.js +13 -2
  363. package/dist/surface/tools/act-sequence-tool.js +136 -27
  364. package/dist/surface/tools/act-tools.d.ts +0 -9
  365. package/dist/surface/tools/act-tools.js +48 -34
  366. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  367. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  368. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  369. package/dist/surface/tools/agent/app-notes.js +48 -0
  370. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  371. package/dist/surface/tools/agent/build-staleness.js +62 -0
  372. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  373. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  374. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  375. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  376. package/dist/surface/tools/agent/notices.d.ts +50 -0
  377. package/dist/surface/tools/agent/notices.js +152 -0
  378. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  379. package/dist/surface/tools/agent/reteach.js +50 -0
  380. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  381. package/dist/surface/tools/args/alias-args.js +10 -0
  382. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  383. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  384. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  385. package/dist/surface/tools/assert/assert-source.js +40 -0
  386. package/dist/surface/tools/assert/assert-verdict.js +25 -15
  387. package/dist/surface/tools/browser-tools.js +43 -1
  388. package/dist/surface/tools/chat-drives.d.ts +75 -0
  389. package/dist/surface/tools/chat-drives.js +265 -21
  390. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  391. package/dist/surface/tools/coverage-tools.js +2 -53
  392. package/dist/surface/tools/dynamic-tools.js +29 -1
  393. package/dist/surface/tools/empty-session-list.d.ts +10 -0
  394. package/dist/surface/tools/empty-session-list.js +45 -5
  395. package/dist/surface/tools/error-recovery.d.ts +8 -0
  396. package/dist/surface/tools/error-recovery.js +69 -5
  397. package/dist/surface/tools/explore-tools.d.ts +23 -2
  398. package/dist/surface/tools/explore-tools.js +377 -74
  399. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  400. package/dist/surface/tools/feedback-tools.js +4 -3
  401. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  402. package/dist/surface/tools/gap-novelty.js +8 -1
  403. package/dist/surface/tools/harness-explore.d.ts +52 -73
  404. package/dist/surface/tools/harness-explore.js +177 -146
  405. package/dist/surface/tools/harness-gate.d.ts +88 -0
  406. package/dist/surface/tools/harness-gate.js +235 -0
  407. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  408. package/dist/surface/tools/harness-hunt.js +215 -0
  409. package/dist/surface/tools/harness-plan.d.ts +5 -0
  410. package/dist/surface/tools/harness-plan.js +7 -0
  411. package/dist/surface/tools/harness-script.d.ts +22 -0
  412. package/dist/surface/tools/harness-script.js +256 -38
  413. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  414. package/dist/surface/tools/harness-tab-guard.js +27 -0
  415. package/dist/surface/tools/harness-toolset.d.ts +8 -0
  416. package/dist/surface/tools/harness-toolset.js +27 -4
  417. package/dist/surface/tools/human-notes.d.ts +16 -0
  418. package/dist/surface/tools/human-notes.js +27 -0
  419. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  420. package/dist/surface/tools/invoke-tool.js +220 -93
  421. package/dist/surface/tools/lease-hint.js +26 -5
  422. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  423. package/dist/surface/tools/lease-permissions.js +73 -0
  424. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  425. package/dist/surface/tools/lease-readiness.js +57 -0
  426. package/dist/surface/tools/lease-seed.d.ts +20 -0
  427. package/dist/surface/tools/lease-seed.js +45 -1
  428. package/dist/surface/tools/lease-tools.d.ts +10 -1
  429. package/dist/surface/tools/lease-tools.js +119 -69
  430. package/dist/surface/tools/live-call-text.js +2 -2
  431. package/dist/surface/tools/merge-tools.js +42 -2
  432. package/dist/surface/tools/merged-name-redirect.js +4 -0
  433. package/dist/surface/tools/next-step.d.ts +11 -1
  434. package/dist/surface/tools/next-step.js +73 -18
  435. package/dist/surface/tools/observe-tools.js +43 -5
  436. package/dist/surface/tools/platform-moment.d.ts +60 -0
  437. package/dist/surface/tools/platform-moment.js +132 -4
  438. package/dist/surface/tools/read-tools.js +65 -14
  439. package/dist/surface/tools/reticle-result.d.ts +120 -0
  440. package/dist/surface/tools/reticle-result.js +364 -0
  441. package/dist/surface/tools/tool-kit.d.ts +68 -2
  442. package/dist/surface/tools/tool-kit.js +73 -1
  443. package/dist/surface/tools/tools.js +25 -13
  444. package/dist/telemetry/account-envelope.d.ts +7 -0
  445. package/dist/telemetry/account-envelope.js +61 -0
  446. package/dist/telemetry/agent-client.d.ts +15 -0
  447. package/dist/telemetry/agent-client.js +57 -0
  448. package/dist/telemetry/app-instrumented.js +9 -2
  449. package/dist/telemetry/argument-shape.d.ts +7 -0
  450. package/dist/telemetry/argument-shape.js +86 -1
  451. package/dist/telemetry/automation-hint.d.ts +2 -3
  452. package/dist/telemetry/automation-hint.js +33 -8
  453. package/dist/telemetry/cli-telemetry.js +7 -2
  454. package/dist/telemetry/daemon-telemetry.js +3 -0
  455. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  456. package/dist/telemetry/error-fingerprint.js +61 -5
  457. package/dist/telemetry/feedback-cli.d.ts +0 -13
  458. package/dist/telemetry/feedback-cli.js +0 -77
  459. package/dist/telemetry/feedback.d.ts +13 -0
  460. package/dist/telemetry/feedback.js +183 -17
  461. package/dist/telemetry/harness-run.d.ts +18 -0
  462. package/dist/telemetry/harness-run.js +80 -0
  463. package/dist/telemetry/hud-events.d.ts +16 -0
  464. package/dist/telemetry/hud-events.js +27 -0
  465. package/dist/telemetry/hud-metrics.d.ts +27 -6
  466. package/dist/telemetry/hud-metrics.js +99 -25
  467. package/dist/telemetry/init-telemetry.js +2 -2
  468. package/dist/telemetry/install-source.d.ts +13 -25
  469. package/dist/telemetry/install-source.js +44 -3
  470. package/dist/telemetry/mcp-connection.d.ts +0 -14
  471. package/dist/telemetry/mcp-connection.js +5 -1
  472. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  473. package/dist/telemetry/onboarding-firsts.js +81 -6
  474. package/dist/telemetry/platform-linked.d.ts +5 -0
  475. package/dist/telemetry/platform-linked.js +32 -0
  476. package/dist/telemetry/project-profile.js +5 -3
  477. package/dist/telemetry/proxy-telemetry.js +4 -1
  478. package/dist/telemetry/session-metrics.d.ts +15 -4
  479. package/dist/telemetry/session-metrics.js +88 -52
  480. package/dist/telemetry/telemetry.d.ts +26 -2
  481. package/dist/telemetry/telemetry.js +102 -21
  482. package/dist/telemetry/verification-of.d.ts +3 -1
  483. package/dist/telemetry/verification-of.js +12 -4
  484. package/dist/wire-journal.d.ts +2 -2
  485. package/dist/wire-journal.js +16 -5
  486. package/docs/README.md +2 -2
  487. package/docs/actions.mdx +6 -3
  488. package/docs/adapters.md +1 -1
  489. package/docs/agent-cheatsheet.md +24 -27
  490. package/docs/architecture.md +5 -5
  491. package/docs/autodrive.md +13 -12
  492. package/docs/benchmarks.md +5 -5
  493. package/docs/best-practices.mdx +27 -9
  494. package/docs/capabilities.mdx +14 -16
  495. package/docs/cli/affected.mdx +1 -1
  496. package/docs/cli/cloud.mdx +54 -75
  497. package/docs/cli/doctor.mdx +8 -3
  498. package/docs/cli/drive.mdx +12 -12
  499. package/docs/cli/feedback.mdx +3 -3
  500. package/docs/cli/gate.mdx +7 -2
  501. package/docs/cli/help.mdx +50 -55
  502. package/docs/cli/init.mdx +32 -15
  503. package/docs/cli/license.mdx +12 -8
  504. package/docs/cli/mcp.mdx +4 -4
  505. package/docs/cli/open.mdx +3 -3
  506. package/docs/cli/report.mdx +4 -2
  507. package/docs/cli/restart.mdx +2 -2
  508. package/docs/cli/rollback.mdx +14 -8
  509. package/docs/cli/serve.mdx +4 -4
  510. package/docs/cli/setup.mdx +23 -0
  511. package/docs/cli/status.mdx +13 -4
  512. package/docs/cli/stop.mdx +67 -8
  513. package/docs/cli/try.mdx +62 -0
  514. package/docs/cli/update.mdx +4 -3
  515. package/docs/cli/verify.mdx +17 -6
  516. package/docs/cli/version.mdx +3 -2
  517. package/docs/cli.mdx +110 -41
  518. package/docs/debugging.md +3 -3
  519. package/docs/deploy-checks.md +1 -1
  520. package/docs/desktop.mdx +5 -3
  521. package/docs/enterprise.md +11 -10
  522. package/docs/environment.mdx +5 -2
  523. package/docs/faq.mdx +3 -3
  524. package/docs/first-drive.md +5 -4
  525. package/docs/flows.md +35 -27
  526. package/docs/for-agents.md +4 -5
  527. package/docs/frameworks.mdx +32 -21
  528. package/docs/getting-started.md +66 -64
  529. package/docs/human-control.md +15 -14
  530. package/docs/index.mdx +15 -43
  531. package/docs/install-agentic.mdx +22 -37
  532. package/docs/install-manual.mdx +22 -12
  533. package/docs/instrumentation.mdx +5 -3
  534. package/docs/integration-patterns.md +7 -7
  535. package/docs/license-activation.mdx +1 -1
  536. package/docs/multi-agent-testing.md +24 -6
  537. package/docs/packages/babel-plugin.mdx +4 -2
  538. package/docs/packages/browser.mdx +16 -10
  539. package/docs/packages/core.mdx +12 -5
  540. package/docs/packages/electron.mdx +3 -2
  541. package/docs/packages/engine.mdx +1 -1
  542. package/docs/packages/eslint-plugin.mdx +18 -12
  543. package/docs/packages/next.mdx +8 -7
  544. package/docs/packages/open-verification.mdx +1 -1
  545. package/docs/packages/server.mdx +5 -5
  546. package/docs/packages/tauri.mdx +8 -8
  547. package/docs/packages/test.mdx +4 -10
  548. package/docs/packages/vite-plugin.mdx +11 -4
  549. package/docs/packages.mdx +11 -15
  550. package/docs/platform-integration.md +6 -5
  551. package/docs/predicates.mdx +40 -24
  552. package/docs/quickstart.mdx +58 -29
  553. package/docs/required-checks.md +8 -7
  554. package/docs/reticle-manual.md +15 -5
  555. package/docs/skill-file.mdx +17 -79
  556. package/docs/skill-setup.md +9 -9
  557. package/docs/skill.md +200 -0
  558. package/docs/system-map.md +7 -7
  559. package/docs/telemetry.md +22 -24
  560. package/docs/testing.md +4 -4
  561. package/docs/token-efficiency.md +12 -12
  562. package/docs/tools/act-and-wait.mdx +9 -2
  563. package/docs/tools/act-sequence.mdx +6 -7
  564. package/docs/tools/act.mdx +2 -2
  565. package/docs/tools/assert.mdx +18 -17
  566. package/docs/tools/console.mdx +9 -9
  567. package/docs/tools/inspect.mdx +16 -7
  568. package/docs/tools/look.mdx +24 -0
  569. package/docs/tools/navigate.mdx +5 -3
  570. package/docs/tools/network.mdx +2 -2
  571. package/docs/tools/observe.mdx +6 -6
  572. package/docs/tools/overview.mdx +34 -33
  573. package/docs/tools/query.mdx +5 -5
  574. package/docs/tools/session-and-feedback.mdx +13 -4
  575. package/docs/tools/sessions.mdx +8 -8
  576. package/docs/tools/snapshot.mdx +6 -5
  577. package/docs/tools/state.mdx +9 -9
  578. package/docs/tools/tools-and-run.mdx +26 -24
  579. package/docs/tools/verify.mdx +28 -0
  580. package/docs/tools/wait-for.mdx +8 -4
  581. package/docs/troubleshooting.mdx +21 -6
  582. package/docs/usage.md +51 -45
  583. package/docs/use-cases.mdx +3 -3
  584. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  585. package/docs/vs-playwright-mcp.mdx +3 -1
  586. package/docs/what-is-recorded.md +7 -5
  587. package/docs/what-is-reticle.mdx +2 -2
  588. package/docs/why-reticle.mdx +1 -1
  589. package/package.json +6 -5
  590. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  591. package/dist/command/cli/demo/demo-page.js +0 -249
  592. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  593. package/dist/command/cli/demo/demo-run.js +0 -138
  594. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  595. package/dist/judgement/hunt/hunt-report.js +0 -84
  596. package/dist/language/flows/buddy-status.d.ts +0 -25
  597. package/dist/language/flows/buddy-status.js +0 -32
  598. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  599. package/dist/language/flows/change/watch-batcher.js +0 -19
  600. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  601. package/dist/memory/cloud/harness-offer.js +0 -145
  602. package/dist/surface/tools/feature-capture.d.ts +0 -151
  603. package/dist/surface/tools/feature-capture.js +0 -235
  604. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  605. package/dist/surface/tools/tool-hit-rate.js +0 -90
  606. package/dist/telemetry/harness-drive.d.ts +0 -4
  607. package/dist/telemetry/harness-drive.js +0 -35
  608. package/dist/telemetry/identify.d.ts +0 -22
  609. package/dist/telemetry/identify.js +0 -73
  610. package/docs/cli/capsules.mdx +0 -70
  611. package/docs/cli/hunt.mdx +0 -73
  612. package/docs/cli/identify.mdx +0 -76
  613. package/docs/cli/kill.mdx +0 -91
  614. package/docs/cli/watch.mdx +0 -62
@@ -1,26 +1,22 @@
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
- */
21
1
  import { writeHarnessSwitch } from './harness-switch.js';
22
2
  /** How long a cached answer is trusted. A person who just changed it expects the panel to notice. */
23
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
+ }
24
20
  export function harnessConfigSource(load, now = () => Date.now()) {
25
21
  let cached;
26
22
  // `undefined` rather than 0: "never asked" is a different state from "asked at the epoch", and
@@ -61,6 +61,23 @@ export interface MemoryReadScope {
61
61
  projectId: string | null | undefined;
62
62
  subject?: string | undefined;
63
63
  }
64
+ /**
65
+ * Who a memory read is for. An agent's read names the agent and the platform counts it as a
66
+ * consultation; the daemon's sync names its purpose and is never counted as one.
67
+ */
68
+ export declare const MemoryReadHeader: {
69
+ readonly AGENT: "x-reticle-agent";
70
+ readonly PURPOSE: "x-reticle-read-purpose";
71
+ };
72
+ export declare const MemoryReadPurpose: {
73
+ readonly SYNC: "sync";
74
+ };
75
+ /**
76
+ * The headers of an agent's memory read: the key, and the agent whose call made the read. A replay's
77
+ * read went without the agent, and the platform credited it to "an agent that did not name itself".
78
+ * No agent is named when no single agent made the call: a guess would credit the wrong one.
79
+ */
80
+ export declare function memoryReadHeaders(apiKey: string): Record<string, string>;
64
81
  /**
65
82
  * The URL for one memory read.
66
83
  *
@@ -37,6 +37,7 @@
37
37
  * constants live, and because both readers already reach this directory: a home under `recall/` would
38
38
  * make `flows` reach a directory it never needed.
39
39
  */
40
+ import { callingClientName } from '../../hooks/coding-agents.js';
40
41
  /**
41
42
  * The path this module builds, spelled once, for the same reason as the names below.
42
43
  *
@@ -71,6 +72,27 @@ export const MemoryScopeField = {
71
72
  * a cast dressed up as a conversion.
72
73
  */
73
74
  const projectToName = (projectId) => 'string' === typeof projectId && projectId.length > 0 ? projectId : undefined;
75
+ /**
76
+ * Who a memory read is for. An agent's read names the agent and the platform counts it as a
77
+ * consultation; the daemon's sync names its purpose and is never counted as one.
78
+ */
79
+ export const MemoryReadHeader = {
80
+ AGENT: 'x-reticle-agent',
81
+ PURPOSE: 'x-reticle-read-purpose',
82
+ };
83
+ export const MemoryReadPurpose = { SYNC: 'sync' };
84
+ /**
85
+ * The headers of an agent's memory read: the key, and the agent whose call made the read. A replay's
86
+ * read went without the agent, and the platform credited it to "an agent that did not name itself".
87
+ * No agent is named when no single agent made the call: a guess would credit the wrong one.
88
+ */
89
+ export function memoryReadHeaders(apiKey) {
90
+ const agent = callingClientName();
91
+ return {
92
+ authorization: `Bearer ${apiKey}`,
93
+ ...(agent === undefined ? {} : { [MemoryReadHeader.AGENT]: agent }),
94
+ };
95
+ }
74
96
  /**
75
97
  * The URL for one memory read.
76
98
  *
@@ -1,3 +1,4 @@
1
+ import { type ScreenshotSyncState } from './sync-screenshots.js';
1
2
  /**
2
3
  * The derived records that ride along with runs, and the file each one lives in.
3
4
  *
@@ -34,18 +35,20 @@ export interface SyncSource {
34
35
  runId: string;
35
36
  payload: unknown;
36
37
  }>;
37
- /** Every saved flow. Small, upserted by name, so they ride along whenever anything else does. */
38
+ /** Every saved flow. Upserted by name, so the set is sent only when it changed. */
38
39
  flows: () => readonly unknown[];
39
40
  /**
40
41
  * Every bug capsule on disk — the minimal failing flow that reproduces a defect, plus its evidence.
41
42
  *
42
- * Rides along with flows, and for the same reason: small, upserted by id, and worth nothing on the
43
+ * Sent like flows, only when the set changed: upserted by id, and worth nothing on the
43
44
  * machine that found the bug. A verdict count tells a dashboard THAT something broke; the capsule
44
45
  * is the only artifact that lets somebody else make it break again.
45
46
  */
46
47
  capsules: () => readonly unknown[];
47
48
  /** One derived record, or undefined when the file is absent. */
48
49
  derived: (kind: DerivedKind) => unknown;
50
+ /** One step screenshot of a run. Absent when this project keeps its screenshots local. */
51
+ screenshot?: (runId: string, file: string) => Uint8Array | undefined;
49
52
  }
50
53
  /** What the machine writes back. Separated from reads so a dry run is a source with no sink. */
51
54
  export interface SyncSink {
@@ -66,7 +69,7 @@ export interface PulledIssues {
66
69
  triage: Record<string, PulledIssue>;
67
70
  }
68
71
  /** `.reticle/cloud-state.json`. This machine's side of the conversation, never git-checked. */
69
- export interface CloudSyncState {
72
+ export interface CloudSyncState extends ScreenshotSyncState {
70
73
  /** Opaque. Handed back to the server verbatim; the machine must never parse or invent one. */
71
74
  cursor?: string;
72
75
  lastPushAt?: number;
@@ -104,6 +107,21 @@ export interface CloudSyncState {
104
107
  */
105
108
  sentFlowsHash?: string;
106
109
  sentCapsulesHash?: string;
110
+ /**
111
+ * The hash of each derived record the platform last ACCEPTED from here. A platform that reports
112
+ * a hash of its own form of a record never matches ours, so the same record went every cycle.
113
+ */
114
+ sentDerivedHashes?: Record<string, string>;
115
+ /** The names of the flows the platform last took from here: one gone from disk is deleted there. */
116
+ sentFlowNames?: string[];
117
+ /**
118
+ * The link everything above was kept for: cloud, workspace and project (`credentialSlot`). A
119
+ * folder re-linked elsewhere starts a fresh record, so the new link gets the flows the old one
120
+ * already had, and none of the old link's runs.
121
+ */
122
+ link?: string;
123
+ /** When this folder was re-linked: runs made before it stay here unless the person moves them. */
124
+ linkedAt?: number;
107
125
  /**
108
126
  * A flow or capsule set the platform refused, kept so the refusal stays visible on the cycles that
109
127
  * do not resend it, and so the set is offered again once it changes or the platform reads more.
@@ -131,6 +149,8 @@ export interface SyncReport {
131
149
  ok: boolean;
132
150
  /** Runs the server accepted this cycle. */
133
151
  runsSent: number;
152
+ /** Step screenshots the server took this cycle, for runs it holds. */
153
+ screenshotsSent?: number;
134
154
  /** Runs it refused, with the reason, so a bad artifact is visible rather than silently stuck. */
135
155
  runsRejected: Array<{
136
156
  index: number;
@@ -189,6 +209,12 @@ interface SyncDeps {
189
209
  url: string;
190
210
  apiKey: string;
191
211
  };
212
+ /** The link this cycle sends for (`credentialSlot`); absent for an env-only key (CI). */
213
+ link?: string;
214
+ /** Send runs made under a previous link too: only ever because the person asked. */
215
+ moveHistory?: boolean;
216
+ /** The project flows are synced for. Absent when this cycle does not send flows: none is deleted. */
217
+ projectId?: string;
192
218
  source: SyncSource;
193
219
  sink: SyncSink;
194
220
  state: CloudSyncState;
@@ -210,7 +236,9 @@ export declare const MSG_RUNS_UNCONFIRMED = "sync 200 without a runs result: the
210
236
  * Run one cycle. Never throws: the local record is already safe on disk, and a sync that can take
211
237
  * down the thing it is backing up is worse than no sync.
212
238
  */
213
- export declare function runSyncCycle(deps: SyncDeps): Promise<SyncReport>;
239
+ /** The command that moves a folder's earlier runs to the link it has now. */
240
+ export declare const MOVE_HISTORY_COMMAND = "reticle sync --move-history";
241
+ export declare function runSyncCycle(given: SyncDeps): Promise<SyncReport>;
214
242
  /** One line a human can read, for the CLI and the daemon log. */
215
243
  export declare function describeSync(report: SyncReport): string;
216
244
  export {};
@@ -30,12 +30,14 @@
30
30
  * Every dependency is injected — the clock, the fetch, the reads and writes — because this is the
31
31
  * one piece of Reticle that talks to a network AND to a disk, and it must be provable without either.
32
32
  */
33
- import { FlowErrorCode, ReticleDir, SYNC_BATCH_LIMITS } from '@reticlehq/core';
33
+ import { FlowErrorCode, ReticleDir, SYNC_BATCH_LIMITS, flowJsonReplacer } from '@reticlehq/core';
34
34
  import { hashPayload } from './sync-hash.js';
35
+ import { syncScreenshots } from './sync-screenshots.js';
35
36
  /** The server's own doors. Kept beside the code that calls them, like the other cloud paths. */
36
37
  const SYNC_PATH = '/v1/sync';
37
38
  const SYNC_STATUS_PATH = '/v1/sync/status';
38
39
  const SYNC_PULL_PATH = '/v1/sync/pull';
40
+ const FLOWS_PATH = '/v1/flows';
39
41
  /**
40
42
  * The derived records that ride along with runs, and the file each one lives in.
41
43
  *
@@ -131,7 +133,29 @@ function batchRuns(runs) {
131
133
  * Run one cycle. Never throws: the local record is already safe on disk, and a sync that can take
132
134
  * down the thing it is backing up is worse than no sync.
133
135
  */
134
- export async function runSyncCycle(deps) {
136
+ /** The command that moves a folder's earlier runs to the link it has now. */
137
+ export const MOVE_HISTORY_COMMAND = 'reticle sync --move-history';
138
+ /**
139
+ * The record this cycle keeps, for this link. Re-linked to another cloud, workspace or project, it
140
+ * starts afresh from now: what the old link was sent says nothing about the new one, and the runs
141
+ * made under the old link are that workspace's (a person's email can be in their steps), so they go
142
+ * only when the person moves them. A first link, or a record from before links were kept, is
143
+ * adopted as it is.
144
+ */
145
+ function stateForLink(deps) {
146
+ const { state, link } = deps;
147
+ if (link === undefined)
148
+ return state;
149
+ if (state.link === undefined || state.link === link) {
150
+ const { linkedAt, ...rest } = state;
151
+ return true === deps.moveHistory || linkedAt === undefined
152
+ ? { ...rest, link }
153
+ : { ...rest, link, linkedAt };
154
+ }
155
+ return { link, ...(true === deps.moveHistory ? {} : { linkedAt: deps.now() }) };
156
+ }
157
+ export async function runSyncCycle(given) {
158
+ const deps = { ...given, state: stateForLink(given) };
135
159
  const empty = {
136
160
  ok: false,
137
161
  runsSent: 0,
@@ -237,7 +261,14 @@ export async function runSyncCycle(deps) {
237
261
  notRetried.push({ runId: run.runId, reason: prior.reason });
238
262
  return false;
239
263
  });
264
+ // Made before this folder was linked here: the previous link's, kept until the person moves it.
265
+ const linkedAt = deps.state.linkedAt;
266
+ const earlier = unsent.filter((run) => linkedAt !== undefined && !((numberAt(run.payload, 'createdAt') ?? 0) >= linkedAt));
267
+ if (0 < earlier.length)
268
+ heldBack.push(`${String(earlier.length)} run${1 === earlier.length ? '' : 's'} made before this folder was linked to this workspace stay${1 === earlier.length ? 's' : ''} on this machine (recorded under its previous link): run \`${MOVE_HISTORY_COMMAND}\` to send ${1 === earlier.length ? 'it' : 'them'} here`);
240
269
  const sendable = unsent.filter((run) => {
270
+ if (earlier.includes(run))
271
+ return false;
241
272
  const version = numberAt(run.payload, 'schemaVersion');
242
273
  if (runVersions === undefined || version === undefined || runVersions.includes(version))
243
274
  return true;
@@ -248,25 +279,51 @@ export async function runSyncCycle(deps) {
248
279
  const derivedOffered = [];
249
280
  const unsupported = [];
250
281
  const bundle = {};
282
+ // A folder re-linked elsewhere keeps what it derived under the old link (its counts, defects,
283
+ // notes) here with the runs: those records add up the whole history and cannot be split by time.
284
+ // ponytail: held until `--move-history`; a per-link reset of the counters would let new ones go.
285
+ const derivedHeld = [];
251
286
  for (const { kind } of DERIVED_RECORDS) {
252
287
  const payload = deps.source.derived(kind);
253
288
  if (payload === undefined)
254
289
  continue;
290
+ if (linkedAt !== undefined) {
291
+ derivedHeld.push(kind);
292
+ continue;
293
+ }
255
294
  if (!acceptedKinds.has(kind)) {
256
295
  unsupported.push(kind);
257
296
  continue;
258
297
  }
259
- // The one comparison the whole protocol rests on. Same hash, do not send it.
260
- if (hashPayload(payload) === hashes[kind])
298
+ // The one comparison the whole protocol rests on. Same hash, do not send it: the platform's,
299
+ // or the one it accepted from here while it still holds the record (a null means it does not).
300
+ const hash = hashPayload(payload);
301
+ if (hash === hashes[kind])
302
+ continue;
303
+ if ('string' === typeof hashes[kind] && hash === deps.state.sentDerivedHashes?.[kind])
261
304
  continue;
262
305
  bundle[kind] = payload;
263
306
  derivedOffered.push(kind);
264
307
  }
265
308
  if (unsupported.length > 0)
266
309
  heldBack.push(`this platform does not accept ${unsupported.join(', ')} yet`);
310
+ if (0 < derivedHeld.length)
311
+ heldBack.push(`the ${derivedHeld.join(', ')} record${1 === derivedHeld.length ? '' : 's'} made under this folder's previous link stay${1 === derivedHeld.length ? 's' : ''} on this machine: run \`${MOVE_HISTORY_COMMAND}\` to send ${1 === derivedHeld.length ? 'it' : 'them'} here`);
267
312
  // Flows and capsules are upserted by name/id, so the whole set goes whenever it differs from the
268
- // set the platform last answered for, and rides along with anything else being sent.
269
- const flows = deps.source.flows().filter((flow, index) => {
313
+ // set the platform last answered for — and only then. Riding along with every run push re-sent
314
+ // ~1.3 MB per push on a real repo, and a POST that size timed out and failed the run with it.
315
+ // Made before this folder was linked here, like the runs: the previous link's, kept until moved.
316
+ // A flow carries the steps of whoever drove it, so it is that workspace's as much as a run is.
317
+ // One read for both halves: the disk source rebuilds every flow per read, so a second read's
318
+ // objects are never `includes` of the first's, and every held-back flow went out anyway.
319
+ const flowsAll = deps.source.flows();
320
+ const madeBefore = (flow) => linkedAt !== undefined && !((numberAt(flow, 'createdAt') ?? 0) >= linkedAt);
321
+ const flowsBefore = flowsAll.filter(madeBefore);
322
+ if (0 < flowsBefore.length)
323
+ heldBack.push(`${String(flowsBefore.length)} flow${1 === flowsBefore.length ? '' : 's'} made before this folder was linked to this workspace stay${1 === flowsBefore.length ? 's' : ''} on this machine: run \`${MOVE_HISTORY_COMMAND}\` to send ${1 === flowsBefore.length ? 'it' : 'them'} here`);
324
+ const flows = flowsAll.filter((flow, index) => {
325
+ if (madeBefore(flow))
326
+ return false;
270
327
  const version = numberAt(flow, 'version');
271
328
  if (flowVersions === undefined || version === undefined || flowVersions.includes(version))
272
329
  return true;
@@ -296,10 +353,9 @@ export async function runSyncCycle(deps) {
296
353
  };
297
354
  const flowsChanged = due('flow', flowsHash, flows.length, deps.state.sentFlowsHash);
298
355
  const capsulesChanged = due('capsule', capsulesHash, capsulesAll.length, deps.state.sentCapsulesHash);
299
- const ridesAlong = sendable.length > 0 || derivedOffered.length > 0 || flowsChanged || capsulesChanged;
300
- if (ridesAlong && flows.length > 0)
356
+ if (flowsChanged)
301
357
  bundle['flows'] = flows;
302
- const capsules = ridesAlong ? capsulesAll : [];
358
+ const capsules = capsulesChanged ? capsulesAll : [];
303
359
  if (capsules.length > 0)
304
360
  bundle['capsules'] = capsules;
305
361
  let runsSent = 0;
@@ -321,7 +377,11 @@ export async function runSyncCycle(deps) {
321
377
  const body = 0 === i ? { ...bundle } : {};
322
378
  if (batch.length > 0)
323
379
  body['runs'] = batch.map((r) => r.payload);
324
- const pushed = await call(SYNC_PATH, { method: 'POST', body: JSON.stringify(body) });
380
+ // The flows ride here too: a default flag stays out of them, as on disk.
381
+ const pushed = await call(SYNC_PATH, {
382
+ method: 'POST',
383
+ body: JSON.stringify(body, flowJsonReplacer),
384
+ });
325
385
  if (200 !== pushed.status) {
326
386
  pushError = `sync ${String(pushed.status)}: ${pushed.text.slice(0, 200)}`;
327
387
  break;
@@ -388,18 +448,40 @@ export async function runSyncCycle(deps) {
388
448
  const state = isRecord(answer['state']) ? answer['state'] : {};
389
449
  for (const kind of derivedOffered) {
390
450
  const verdict = state[kind];
391
- if ('accepted' === verdict)
451
+ if ('accepted' === verdict) {
392
452
  derivedSent.push(kind);
453
+ nextState.sentDerivedHashes = {
454
+ ...nextState.sentDerivedHashes,
455
+ [kind]: hashPayload(bundle[kind]),
456
+ };
457
+ }
393
458
  else if ('string' === typeof verdict)
394
459
  refused.push({ part: kind, reason: `${kind}: ${verdict}` });
395
460
  }
396
461
  }
462
+ // A flow the platform took from here and that is gone from disk is deleted there by name: it
463
+ // does not infer a deletion from a missing name, since another clone may still hold the flow.
464
+ const onDisk = new Set(deps.source.flows().map(flowName));
465
+ const kept = [];
466
+ for (const name of deps.projectId === undefined ? [] : (deps.state.sentFlowNames ?? [])) {
467
+ if (onDisk.has(name)) {
468
+ kept.push(name);
469
+ continue;
470
+ }
471
+ const gone = await call(`${FLOWS_PATH}/${encodeURIComponent(name)}?projectId=${encodeURIComponent(deps.projectId ?? '')}`, { method: 'DELETE' });
472
+ if (2 !== Math.floor(gone.status / 100) && 404 !== gone.status)
473
+ kept.push(name);
474
+ }
475
+ if (deps.projectId !== undefined)
476
+ nextState.sentFlowNames = kept;
397
477
  if (requests > 0 && pushError === undefined) {
398
478
  nextState.lastPushAt = deps.now();
399
479
  // The platform answered for these sets, refusals included (reported above, and not re-offered
400
480
  // until the set changes — the same rule as a refused run).
401
- if (ridesAlong && flows.length > 0)
481
+ if (flowsChanged)
402
482
  nextState.sentFlowsHash = flowsHash;
483
+ if (flowsChanged && deps.projectId !== undefined)
484
+ nextState.sentFlowNames = [...new Set([...kept, ...flows.map(flowName)])];
403
485
  if (capsules.length > 0)
404
486
  nextState.sentCapsulesHash = capsulesHash;
405
487
  }
@@ -429,6 +511,22 @@ export async function runSyncCycle(deps) {
429
511
  */
430
512
  nextState.sentRunIds = allRuns.map((r) => r.runId).filter((id) => known.has(id));
431
513
  nextState.sentRunHashes = heldHashes(allRuns, recorded);
514
+ // 2b. The step screenshots of every run the platform now holds, once each.
515
+ let screenshotsSent = 0;
516
+ const readImage = deps.source.screenshot;
517
+ if (readImage !== undefined) {
518
+ const shots = await syncScreenshots({
519
+ runs: allRuns,
520
+ accepted: (runId) => known.has(runId),
521
+ readImage,
522
+ state: deps.state,
523
+ post: (path, body) => call(path, { method: 'POST', body }),
524
+ });
525
+ screenshotsSent = shots.sent;
526
+ Object.assign(nextState, shots.state);
527
+ if (shots.error !== undefined)
528
+ heldBack.push(shots.error);
529
+ }
432
530
  // 3. COLLECT — always, even when there was nothing to send.
433
531
  const query = nextState.cursor === undefined ? '' : `?since=${encodeURIComponent(nextState.cursor)}`;
434
532
  const pull = await call(`${SYNC_PULL_PATH}${query}`);
@@ -477,6 +575,7 @@ export async function runSyncCycle(deps) {
477
575
  0 === setsNotRetried.length &&
478
576
  !heldArtifacts,
479
577
  runsSent,
578
+ ...(0 === screenshotsSent ? {} : { screenshotsSent }),
480
579
  runsRejected,
481
580
  flowsSent,
482
581
  capsulesSent,
@@ -550,6 +649,8 @@ export function describeSync(report) {
550
649
  sent.push(`${String(report.flowsSent)} flow(s)`);
551
650
  if (report.capsulesSent > 0)
552
651
  sent.push(`${String(report.capsulesSent)} capsule(s)`);
652
+ if ((report.screenshotsSent ?? 0) > 0)
653
+ sent.push(`${String(report.screenshotsSent)} screenshot(s)`);
553
654
  if (report.derivedSent.length > 0)
554
655
  sent.push(report.derivedSent.join(', '));
555
656
  /*
@@ -1,5 +1,6 @@
1
1
  import { type SyncReport } from './sync-cycle.js';
2
2
  import { type ProjectCloud } from './cloud-config.js';
3
+ import { type UnsyncedRoot } from './unsynced-roots.js';
3
4
  import type { FileSystemPort } from '../project/fs/fs-port.js';
4
5
  interface SyncDaemonDeps {
5
6
  reticleRoot: string;
@@ -20,6 +21,11 @@ interface SyncDaemonDeps {
20
21
  cloudFor?: (root: string) => Promise<ProjectCloud>;
21
22
  now?: () => number;
22
23
  intervalMs?: number;
24
+ /**
25
+ * Call `onChange` when this root's link file changes; returns how to stop. A re-link was read only
26
+ * on the next idle tick, so a daemon kept syncing to the old link for up to a minute.
27
+ */
28
+ watchLink?: (onChange: () => void) => () => void;
23
29
  /** Injected for the test; the real one is `fetch`. */
24
30
  request?: (url: string, init: {
25
31
  method: string;
@@ -58,6 +64,11 @@ export interface SyncDaemon {
58
64
  * time — the artifact is still on disk and the next daemon for this project sends it.
59
65
  */
60
66
  flush: () => Promise<void>;
67
+ /**
68
+ * Every root this daemon knows with runs the platform does not have, as of the last cycle — linked
69
+ * or not. An unlinked one is the case nothing will ever send, and it used to be skipped silently.
70
+ */
71
+ unsyncedRoots: () => readonly UnsyncedRoot[];
61
72
  }
62
73
  /**
63
74
  * Start the loop. Safe to call for an UNLINKED project: it resolves the link on every tick and does