@reticlehq/server 3.7.0 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (578) hide show
  1. package/SKILL.md +59 -68
  2. package/bin/reticle.js +9 -2
  3. package/dist/command/cli/adhoc-suite.js +1 -1
  4. package/dist/command/cli/adhoc-verdict.d.ts +12 -0
  5. package/dist/command/cli/adhoc-verdict.js +62 -4
  6. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  7. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  8. package/dist/command/cli/auth/cloud-session.d.ts +11 -19
  9. package/dist/command/cli/auth/cloud-session.js +23 -0
  10. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  11. package/dist/command/cli/cli-doctor.js +66 -21
  12. package/dist/command/cli/cli-flow-commands.js +53 -11
  13. package/dist/command/cli/cli-kill.d.ts +8 -0
  14. package/dist/command/cli/cli-kill.js +43 -3
  15. package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
  16. package/dist/command/cli/cli-parse-feedback.js +13 -1
  17. package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
  18. package/dist/command/cli/cli-parse-grammar.js +1 -6
  19. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  20. package/dist/command/cli/cli-parse-serve.js +124 -0
  21. package/dist/command/cli/cli-parse.d.ts +12 -11
  22. package/dist/command/cli/cli-parse.js +100 -123
  23. package/dist/command/cli/cli-usage.d.ts +0 -11
  24. package/dist/command/cli/cli-usage.js +43 -16
  25. package/dist/command/cli/cli-verify.d.ts +1 -1
  26. package/dist/command/cli/cli-verify.js +29 -14
  27. package/dist/command/cli/cloud-cli.js +27 -9
  28. package/dist/command/cli/cloud-kit.js +3 -3
  29. package/dist/command/cli/cloud-link.d.ts +1 -20
  30. package/dist/command/cli/cloud-link.js +2 -0
  31. package/dist/command/cli/cloud-login.d.ts +6 -2
  32. package/dist/command/cli/cloud-login.js +13 -41
  33. package/dist/command/cli/config/checkout.d.ts +10 -0
  34. package/dist/command/cli/config/checkout.js +78 -0
  35. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  36. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  37. package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
  38. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  39. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  40. package/dist/command/cli/drive/drive-attach.d.ts +5 -0
  41. package/dist/command/cli/drive/drive-attach.js +21 -1
  42. package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
  43. package/dist/command/cli/hook/codex-transcript.js +224 -0
  44. package/dist/command/cli/hook/episode-structure.d.ts +24 -0
  45. package/dist/command/cli/hook/episode-structure.js +138 -0
  46. package/dist/command/cli/hook/hook-command.d.ts +9 -0
  47. package/dist/command/cli/hook/hook-command.js +211 -0
  48. package/dist/command/cli/hook/hook-fast.d.ts +31 -0
  49. package/dist/command/cli/hook/hook-fast.js +136 -0
  50. package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
  51. package/dist/command/cli/hook/prompt-hook.js +199 -0
  52. package/dist/command/cli/hook/tool-hook.d.ts +21 -0
  53. package/dist/command/cli/hook/tool-hook.js +259 -0
  54. package/dist/command/cli/launch/cli-launch.d.ts +2 -0
  55. package/dist/command/cli/launch/cli-launch.js +22 -2
  56. package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
  57. package/dist/command/cli/mcp-command.d.ts +9 -0
  58. package/dist/command/cli/mcp-command.js +127 -41
  59. package/dist/command/cli/open-navigate.d.ts +43 -0
  60. package/dist/command/cli/open-navigate.js +85 -0
  61. package/dist/command/cli/ports/port-holder.d.ts +16 -4
  62. package/dist/command/cli/ports/port-holder.js +58 -12
  63. package/dist/command/cli/ports/resolve/cli-port.js +18 -2
  64. package/dist/command/cli/project-name.d.ts +1 -7
  65. package/dist/command/cli/project-name.js +1 -0
  66. package/dist/command/cli/report-command.d.ts +8 -2
  67. package/dist/command/cli/report-command.js +95 -18
  68. package/dist/command/cli/status-fields.d.ts +9 -2
  69. package/dist/command/cli/status-fields.js +148 -4
  70. package/dist/command/cli/try-command.d.ts +3 -4
  71. package/dist/command/cli/try-command.js +6 -11
  72. package/dist/command/cli/verify-results.d.ts +4 -1
  73. package/dist/command/cli/verify-results.js +3 -1
  74. package/dist/command/cli.d.ts +1 -7
  75. package/dist/command/cli.js +79 -160
  76. package/dist/command/daemon/daemon-resilience.d.ts +6 -1
  77. package/dist/command/daemon/daemon-resilience.js +31 -18
  78. package/dist/command/daemon/daemon.d.ts +11 -0
  79. package/dist/command/daemon/daemon.js +70 -2
  80. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
  81. package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
  82. package/dist/command/daemon/wake-decision.js +4 -2
  83. package/dist/command/daemon/win32-escape.d.ts +32 -0
  84. package/dist/command/daemon/win32-escape.js +119 -0
  85. package/dist/command/setup/agent-configs.d.ts +9 -0
  86. package/dist/command/setup/agent-configs.js +9 -0
  87. package/dist/command/setup/auto-approve.d.ts +10 -3
  88. package/dist/command/setup/auto-approve.js +51 -3
  89. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  90. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  91. package/dist/command/setup/bringup/ensure-daemon.js +4 -7
  92. package/dist/command/setup/init/init-host.js +6 -0
  93. package/dist/command/setup/init/init-port.js +5 -4
  94. package/dist/command/setup/init/init-runtime.js +7 -1
  95. package/dist/command/setup/node-effects.d.ts +8 -0
  96. package/dist/command/setup/node-effects.js +36 -4
  97. package/dist/command/setup/probe/dev-port.d.ts +26 -0
  98. package/dist/command/setup/probe/dev-port.js +117 -0
  99. package/dist/command/setup/probe/page-probe.d.ts +1 -1
  100. package/dist/command/setup/probe/page-probe.js +11 -3
  101. package/dist/command/setup/remaining-steps.d.ts +0 -7
  102. package/dist/command/setup/remaining-steps.js +3 -2
  103. package/dist/command/setup/run-setup.d.ts +11 -0
  104. package/dist/command/setup/run-setup.js +33 -5
  105. package/dist/command/setup/setup-command.d.ts +2 -0
  106. package/dist/command/setup/setup-command.js +22 -4
  107. package/dist/command/update/updater.d.ts +1 -6
  108. package/dist/command/update/updater.js +4 -5
  109. package/dist/command/update/version-seen.d.ts +24 -0
  110. package/dist/command/update/version-seen.js +65 -0
  111. package/dist/command/version/peer-announce.d.ts +9 -1
  112. package/dist/command/version/peer-announce.js +25 -2
  113. package/dist/command/version/sdk-fix.d.ts +5 -6
  114. package/dist/command/version/sdk-fix.js +17 -32
  115. package/dist/command/version/version-skew.d.ts +16 -1
  116. package/dist/command/version/version-skew.js +84 -10
  117. package/dist/features/crawl/crawl-tools.js +2 -2
  118. package/dist/features/crawl/crawl.js +2 -0
  119. package/dist/features/exhaust/ledger.d.ts +15 -96
  120. package/dist/features/exhaust/ledger.js +3 -3
  121. package/dist/features/harness/drive-runs.d.ts +28 -4
  122. package/dist/features/harness/drive-runs.js +99 -7
  123. package/dist/features/harness/drivers.d.ts +1 -1
  124. package/dist/features/harness/drivers.js +1 -1
  125. package/dist/features/harness/harness.d.ts +5 -0
  126. package/dist/features/harness/harness.js +24 -12
  127. package/dist/features/harness/platform/platform-drives.d.ts +7 -1
  128. package/dist/features/harness/platform/platform-drives.js +12 -7
  129. package/dist/features/harness/platform/refusal.d.ts +1 -1
  130. package/dist/features/harness/platform/refusal.js +4 -4
  131. package/dist/features/harness/platform/remote-drive.js +70 -28
  132. package/dist/features/harness/platform/server-driver.js +22 -1
  133. package/dist/features/harness/platform-config.d.ts +1 -10
  134. package/dist/features/harness/platform-config.js +0 -20
  135. package/dist/features/license/license.d.ts +2 -14
  136. package/dist/features/visual/step-shots.d.ts +33 -1
  137. package/dist/features/visual/step-shots.js +155 -1
  138. package/dist/features/visual/visual-tools.js +12 -4
  139. package/dist/hooks/coding-agents.d.ts +6 -0
  140. package/dist/hooks/coding-agents.js +24 -3
  141. package/dist/hooks/episode-stamp.d.ts +32 -0
  142. package/dist/hooks/episode-stamp.js +61 -0
  143. package/dist/hooks/hook-commands.js +19 -9
  144. package/dist/index.d.ts +5 -1
  145. package/dist/index.js +66 -24
  146. package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
  147. package/dist/judgement/app-graph/journal-steps.js +92 -0
  148. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  149. package/dist/judgement/domain/domain-model.js +1 -10
  150. package/dist/judgement/domain/domain-tools.js +4 -2
  151. package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
  152. package/dist/judgement/runs/artifact/run-store.js +153 -28
  153. package/dist/judgement/runs/default-run-id.d.ts +3 -1
  154. package/dist/judgement/runs/default-run-id.js +15 -3
  155. package/dist/judgement/runs/drive-run.d.ts +3 -3
  156. package/dist/judgement/runs/drive-run.js +11 -7
  157. package/dist/judgement/runs/run-ledger.d.ts +21 -0
  158. package/dist/judgement/runs/run-ledger.js +143 -0
  159. package/dist/judgement/runs/runner-port.d.ts +1 -1
  160. package/dist/judgement/runs/runner-port.js +8 -2
  161. package/dist/judgement/runs/verification-sync.d.ts +4 -3
  162. package/dist/judgement/runs/verification-sync.js +27 -5
  163. package/dist/language/flows/affected-tools.js +2 -1
  164. package/dist/language/flows/annotate-notes/annotate.js +8 -3
  165. package/dist/language/flows/annotate-tools.js +1 -1
  166. package/dist/language/flows/change/affected.d.ts +8 -0
  167. package/dist/language/flows/change/affected.js +20 -7
  168. package/dist/language/flows/decision.js +19 -4
  169. package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
  170. package/dist/language/flows/fields/flow-secret-field.js +67 -5
  171. package/dist/language/flows/flow-anchor.d.ts +5 -0
  172. package/dist/language/flows/flow-anchor.js +4 -0
  173. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  174. package/dist/language/flows/flow-cross-step.js +9 -0
  175. package/dist/language/flows/flow-expect-grammar.js +15 -10
  176. package/dist/language/flows/flow-intent.js +6 -1
  177. package/dist/language/flows/flow-journey.d.ts +8 -0
  178. package/dist/language/flows/flow-journey.js +13 -0
  179. package/dist/language/flows/flow-lease.d.ts +27 -0
  180. package/dist/language/flows/flow-lease.js +59 -0
  181. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  182. package/dist/language/flows/flow-replay-run.js +111 -310
  183. package/dist/language/flows/flow-replay.js +21 -19
  184. package/dist/language/flows/flow-replayable.d.ts +38 -0
  185. package/dist/language/flows/flow-replayable.js +179 -0
  186. package/dist/language/flows/flow-start-path.d.ts +108 -0
  187. package/dist/language/flows/flow-start-path.js +313 -0
  188. package/dist/language/flows/flow-step-runners.d.ts +23 -2
  189. package/dist/language/flows/flow-step-runners.js +191 -32
  190. package/dist/language/flows/flow-store-for-session.d.ts +8 -1
  191. package/dist/language/flows/flow-store-for-session.js +6 -0
  192. package/dist/language/flows/flow-tools.d.ts +2 -23
  193. package/dist/language/flows/flow-tools.js +63 -113
  194. package/dist/language/flows/flows.d.ts +4 -6
  195. package/dist/language/flows/flows.js +90 -15
  196. package/dist/language/flows/heal-run.d.ts +10 -4
  197. package/dist/language/flows/heal-run.js +26 -9
  198. package/dist/language/flows/recording/flake.d.ts +3 -27
  199. package/dist/language/flows/recording/flake.js +1 -1
  200. package/dist/language/flows/recording/recording-backtrack.js +1 -4
  201. package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
  202. package/dist/language/flows/recording/tape/recordings.js +9 -3
  203. package/dist/language/flows/replay.d.ts +25 -5
  204. package/dist/language/flows/replay.js +83 -16
  205. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  206. package/dist/language/flows/suite/coverage.d.ts +9 -0
  207. package/dist/language/flows/suite/coverage.js +12 -1
  208. package/dist/language/flows/suite-selection.d.ts +25 -0
  209. package/dist/language/flows/suite-selection.js +41 -9
  210. package/dist/machine/git-tracks.d.ts +6 -0
  211. package/dist/machine/git-tracks.js +36 -0
  212. package/dist/memory/cloud/background-sync.d.ts +25 -0
  213. package/dist/memory/cloud/background-sync.js +79 -0
  214. package/dist/memory/cloud/cloud-config.d.ts +12 -1
  215. package/dist/memory/cloud/cloud-config.js +39 -13
  216. package/dist/memory/cloud/cloud-sync.d.ts +3 -24
  217. package/dist/memory/cloud/cloud-sync.js +5 -2
  218. package/dist/memory/cloud/harness-config.d.ts +0 -7
  219. package/dist/memory/cloud/memory-scope.d.ts +19 -0
  220. package/dist/memory/cloud/memory-scope.js +48 -0
  221. package/dist/memory/cloud/sync-answer.d.ts +43 -0
  222. package/dist/memory/cloud/sync-answer.js +42 -0
  223. package/dist/memory/cloud/sync-cycle.d.ts +40 -10
  224. package/dist/memory/cloud/sync-cycle.js +97 -144
  225. package/dist/memory/cloud/sync-daemon.d.ts +50 -3
  226. package/dist/memory/cloud/sync-daemon.js +473 -83
  227. package/dist/memory/cloud/sync-describe.d.ts +28 -0
  228. package/dist/memory/cloud/sync-describe.js +92 -0
  229. package/dist/memory/cloud/sync-disk.d.ts +9 -1
  230. package/dist/memory/cloud/sync-disk.js +137 -33
  231. package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
  232. package/dist/memory/cloud/sync-flow-versions.js +42 -0
  233. package/dist/memory/impact/impact-store.js +32 -15
  234. package/dist/memory/intent/intent-shard.d.ts +41 -266
  235. package/dist/memory/intent/intent-tools.js +20 -61
  236. package/dist/memory/intent/record-request.d.ts +27 -0
  237. package/dist/memory/intent/record-request.js +88 -0
  238. package/dist/memory/intent/settled-words.js +9 -1
  239. package/dist/memory/journal/drive-flow.d.ts +3 -0
  240. package/dist/memory/journal/drive-flow.js +11 -41
  241. package/dist/memory/journal/envelope-store.js +1 -1
  242. package/dist/memory/journal/envelope.d.ts +6 -154
  243. package/dist/memory/journal/episode-log.d.ts +107 -0
  244. package/dist/memory/journal/episode-log.js +302 -0
  245. package/dist/memory/journal/journal-recorder.d.ts +7 -0
  246. package/dist/memory/journal/journal-recorder.js +22 -9
  247. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  248. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  249. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
  250. package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
  251. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
  252. package/dist/memory/journal/self-observation.js +3 -1
  253. package/dist/memory/journal/session-end.js +23 -9
  254. package/dist/memory/journal/session-journal.js +39 -20
  255. package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
  256. package/dist/memory/project/artifact-root-resolver.js +68 -23
  257. package/dist/memory/project/artifact-root.d.ts +17 -3
  258. package/dist/memory/project/artifact-root.js +47 -9
  259. package/dist/memory/project/fs/fs-port.d.ts +5 -0
  260. package/dist/memory/project/fs/fs-port.js +13 -0
  261. package/dist/memory/project/learned-routes.d.ts +3 -4
  262. package/dist/memory/project/learned-routes.js +3 -11
  263. package/dist/memory/project/link-directory.js +5 -2
  264. package/dist/memory/project/root-claims.d.ts +3 -1
  265. package/dist/memory/project/root-claims.js +41 -7
  266. package/dist/memory/project/session-root.d.ts +1 -1
  267. package/dist/memory/project/session-root.js +1 -15
  268. package/dist/memory/project/sync-status.js +5 -6
  269. package/dist/memory/recall/memory-tools.js +2 -2
  270. package/dist/memory/recall/platform-memory.d.ts +3 -1
  271. package/dist/memory/recall/platform-memory.js +9 -1
  272. package/dist/memory/recall/project-memory.js +15 -19
  273. package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
  274. package/dist/portal/bridge/auth-failure-reason.js +19 -0
  275. package/dist/portal/bridge/bridge.d.ts +19 -4
  276. package/dist/portal/bridge/bridge.js +150 -177
  277. package/dist/portal/bridge/harness-request.d.ts +15 -0
  278. package/dist/portal/bridge/harness-request.js +19 -0
  279. package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
  280. package/dist/portal/bridge/origin/origin-follow.js +110 -0
  281. package/dist/portal/bridge/pairing-token.d.ts +6 -0
  282. package/dist/portal/bridge/pairing-token.js +47 -16
  283. package/dist/portal/bridge/protocol-skew.d.ts +27 -2
  284. package/dist/portal/bridge/protocol-skew.js +66 -2
  285. package/dist/portal/bridge/session-nonces.d.ts +46 -0
  286. package/dist/portal/bridge/session-nonces.js +72 -0
  287. package/dist/portal/input/viewport-tools.d.ts +31 -0
  288. package/dist/portal/input/viewport-tools.js +106 -15
  289. package/dist/portal/pool/bounded-close.d.ts +23 -0
  290. package/dist/portal/pool/bounded-close.js +38 -0
  291. package/dist/portal/pool/browser-pool.d.ts +44 -39
  292. package/dist/portal/pool/browser-pool.js +247 -95
  293. package/dist/portal/pool/context-permissions.d.ts +9 -1
  294. package/dist/portal/pool/context-permissions.js +26 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +37 -0
  296. package/dist/portal/pool/lease-emulation.js +29 -0
  297. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  298. package/dist/portal/pool/playwright-launcher.js +74 -7
  299. package/dist/portal/pool/pool-contract.d.ts +23 -1
  300. package/dist/portal/pool/pool-lease.d.ts +128 -0
  301. package/dist/portal/pool/pool-lease.js +49 -0
  302. package/dist/portal/pool/zero-install.d.ts +8 -1
  303. package/dist/portal/pool/zero-install.js +24 -2
  304. package/dist/portal/production/production-activation.d.ts +136 -0
  305. package/dist/portal/production/production-activation.js +173 -0
  306. package/dist/portal/production/production-drive.d.ts +52 -0
  307. package/dist/portal/production/production-drive.js +301 -0
  308. package/dist/portal/production/production-hello.d.ts +23 -0
  309. package/dist/portal/production/production-hello.js +23 -0
  310. package/dist/portal/realm/web-realm.js +42 -15
  311. package/dist/portal/session/control-envelope.d.ts +1 -1
  312. package/dist/portal/session/dev-server/served-document.d.ts +0 -5
  313. package/dist/portal/session/dev-server/served-document.js +6 -8
  314. package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
  315. package/dist/portal/session/first-run-wiring.d.ts +3 -36
  316. package/dist/portal/session/first-run-wiring.js +10 -103
  317. package/dist/portal/session/live-control-tools.js +61 -19
  318. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  319. package/dist/portal/session/no-session-next-action.js +40 -15
  320. package/dist/portal/session/no-session-watch.d.ts +7 -0
  321. package/dist/portal/session/no-session-watch.js +67 -23
  322. package/dist/portal/session/output-budget.d.ts +10 -0
  323. package/dist/portal/session/output-budget.js +16 -0
  324. package/dist/portal/session/presence/session-lease.d.ts +2 -0
  325. package/dist/portal/session/presence/session-lease.js +8 -0
  326. package/dist/portal/session/recorded-gaps.d.ts +15 -11
  327. package/dist/portal/session/recorded-gaps.js +39 -18
  328. package/dist/portal/session/serving-directory.d.ts +24 -2
  329. package/dist/portal/session/serving-directory.js +93 -5
  330. package/dist/portal/session/session-info.d.ts +26 -0
  331. package/dist/portal/session/session-info.js +20 -0
  332. package/dist/portal/session/session-manager.d.ts +35 -3
  333. package/dist/portal/session/session-manager.js +69 -14
  334. package/dist/portal/session/session-successor.js +1 -9
  335. package/dist/portal/session/session-tools.js +22 -4
  336. package/dist/portal/session/session.d.ts +10 -10
  337. package/dist/portal/session/session.js +37 -29
  338. package/dist/portal/session/zero-install-first-call.d.ts +7 -2
  339. package/dist/portal/session/zero-install-first-call.js +43 -20
  340. package/dist/start-wiring.d.ts +2 -2
  341. package/dist/start-wiring.js +17 -3
  342. package/dist/status-payload.d.ts +11 -1
  343. package/dist/status-payload.js +7 -1
  344. package/dist/surface/agent-presence-grace.d.ts +11 -0
  345. package/dist/surface/agent-presence-grace.js +34 -0
  346. package/dist/surface/http-server.d.ts +12 -1
  347. package/dist/surface/http-server.js +64 -15
  348. package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
  349. package/dist/surface/mcp/faults/mcp-outage.js +19 -1
  350. package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
  351. package/dist/surface/mcp/mcp-proxy.js +194 -267
  352. package/dist/surface/mcp/mcp.d.ts +20 -3
  353. package/dist/surface/mcp/mcp.js +88 -25
  354. package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
  355. package/dist/surface/mcp/proxy/drive-calls.js +114 -5
  356. package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
  357. package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
  358. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
  359. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
  360. package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
  361. package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
  362. package/dist/surface/mcp/server-instructions.js +35 -16
  363. package/dist/surface/mcp/shared-params.d.ts +8 -0
  364. package/dist/surface/mcp/shared-params.js +15 -1
  365. package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
  366. package/dist/surface/mcp/sse-frame-parser.js +18 -0
  367. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  368. package/dist/surface/mcp/surface-vocabulary.js +13 -0
  369. package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
  370. package/dist/surface/mcp/tool-catalog-cache.js +14 -4
  371. package/dist/surface/tools/account-tool.d.ts +4 -3
  372. package/dist/surface/tools/account-tool.js +20 -31
  373. package/dist/surface/tools/act/act-danger.d.ts +2 -0
  374. package/dist/surface/tools/act/act-danger.js +41 -14
  375. package/dist/surface/tools/act/act-observation.d.ts +11 -0
  376. package/dist/surface/tools/act/act-observation.js +33 -0
  377. package/dist/surface/tools/act/act-preflight.js +10 -3
  378. package/dist/surface/tools/act/act-sequence-retry.js +2 -1
  379. package/dist/surface/tools/act/act-target.js +19 -5
  380. package/dist/surface/tools/act/durable.js +1 -1
  381. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
  382. package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
  383. package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
  384. package/dist/surface/tools/act/unsettled-find.js +71 -0
  385. package/dist/surface/tools/act-sequence-tool.js +53 -24
  386. package/dist/surface/tools/act-tools.d.ts +2 -3
  387. package/dist/surface/tools/act-tools.js +49 -47
  388. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  389. package/dist/surface/tools/agent/for-the-agent.js +41 -3
  390. package/dist/surface/tools/assert/assert-grade.js +8 -3
  391. package/dist/surface/tools/assert/assert-verdict.js +4 -2
  392. package/dist/surface/tools/browser-tools.js +7 -4
  393. package/dist/surface/tools/chat-drives.js +50 -25
  394. package/dist/surface/tools/coverage-tools.js +1 -1
  395. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  396. package/dist/surface/tools/dynamic-tools.js +89 -34
  397. package/dist/surface/tools/empty-session-list.d.ts +18 -25
  398. package/dist/surface/tools/empty-session-list.js +67 -38
  399. package/dist/surface/tools/error-recovery.d.ts +17 -7
  400. package/dist/surface/tools/error-recovery.js +53 -20
  401. package/dist/surface/tools/explore-tools.d.ts +10 -0
  402. package/dist/surface/tools/explore-tools.js +72 -19
  403. package/dist/surface/tools/feedback-tools.js +23 -2
  404. package/dist/surface/tools/gap-novelty.d.ts +6 -0
  405. package/dist/surface/tools/gap-novelty.js +9 -0
  406. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  407. package/dist/surface/tools/harness-explore.d.ts +1 -1
  408. package/dist/surface/tools/harness-explore.js +6 -4
  409. package/dist/surface/tools/harness-gate.d.ts +43 -21
  410. package/dist/surface/tools/harness-gate.js +55 -81
  411. package/dist/surface/tools/harness-script.d.ts +2 -0
  412. package/dist/surface/tools/harness-script.js +11 -6
  413. package/dist/surface/tools/harness-toolset.js +3 -4
  414. package/dist/surface/tools/invoke-tool.d.ts +0 -8
  415. package/dist/surface/tools/invoke-tool.js +164 -178
  416. package/dist/surface/tools/lease-hint.d.ts +9 -0
  417. package/dist/surface/tools/lease-hint.js +22 -3
  418. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  419. package/dist/surface/tools/lease-readiness.d.ts +55 -0
  420. package/dist/surface/tools/lease-readiness.js +150 -2
  421. package/dist/surface/tools/lease-tools.d.ts +3 -75
  422. package/dist/surface/tools/lease-tools.js +124 -188
  423. package/dist/surface/tools/map-tools.d.ts +20 -0
  424. package/dist/surface/tools/map-tools.js +145 -0
  425. package/dist/surface/tools/merge-tools.js +11 -7
  426. package/dist/surface/tools/next-step.js +6 -3
  427. package/dist/surface/tools/observe-tools.js +46 -35
  428. package/dist/surface/tools/platform-moment.d.ts +3 -12
  429. package/dist/surface/tools/platform-moment.js +12 -24
  430. package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
  431. package/dist/surface/tools/read/complete-snapshot.js +13 -2
  432. package/dist/surface/tools/read/query-paginate.js +6 -0
  433. package/dist/surface/tools/read/query-shape.d.ts +9 -0
  434. package/dist/surface/tools/read/query-shape.js +15 -0
  435. package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
  436. package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
  437. package/dist/surface/tools/read-tools.js +5 -5
  438. package/dist/surface/tools/real-input-attempt.d.ts +11 -0
  439. package/dist/surface/tools/real-input-attempt.js +206 -38
  440. package/dist/surface/tools/reconcile-tools.js +21 -8
  441. package/dist/surface/tools/reticle-result.d.ts +3 -0
  442. package/dist/surface/tools/reticle-result.js +8 -1
  443. package/dist/surface/tools/run-report.d.ts +22 -0
  444. package/dist/surface/tools/run-report.js +141 -0
  445. package/dist/surface/tools/session-ports.d.ts +57 -0
  446. package/dist/surface/tools/session-ports.js +102 -0
  447. package/dist/surface/tools/tool-kit.d.ts +58 -4
  448. package/dist/surface/tools/tool-kit.js +140 -6
  449. package/dist/surface/tools/tool-surface.d.ts +2 -0
  450. package/dist/surface/tools/tool-surface.js +45 -0
  451. package/dist/surface/tools/tools.js +49 -87
  452. package/dist/telemetry/automation-hint.d.ts +5 -0
  453. package/dist/telemetry/automation-hint.js +7 -0
  454. package/dist/telemetry/cli-telemetry.d.ts +22 -0
  455. package/dist/telemetry/cli-telemetry.js +80 -11
  456. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  457. package/dist/telemetry/daemon-telemetry.js +9 -2
  458. package/dist/telemetry/feedback-cli.d.ts +1 -1
  459. package/dist/telemetry/feedback-cli.js +8 -3
  460. package/dist/telemetry/feedback.d.ts +1 -1
  461. package/dist/telemetry/feedback.js +51 -4
  462. package/dist/telemetry/harness-run.d.ts +3 -3
  463. package/dist/telemetry/harness-run.js +18 -7
  464. package/dist/telemetry/hud-events.d.ts +1 -1
  465. package/dist/telemetry/hud-metrics.d.ts +6 -3
  466. package/dist/telemetry/hud-metrics.js +20 -8
  467. package/dist/telemetry/install-source.js +1 -1
  468. package/dist/telemetry/mcp-connection.d.ts +1 -1
  469. package/dist/telemetry/mcp-connection.js +21 -2
  470. package/dist/telemetry/onboarding-firsts.d.ts +6 -1
  471. package/dist/telemetry/onboarding-firsts.js +41 -1
  472. package/dist/telemetry/proxy-telemetry.d.ts +42 -0
  473. package/dist/telemetry/proxy-telemetry.js +70 -1
  474. package/dist/telemetry/session-metrics.d.ts +1 -3
  475. package/dist/telemetry/session-metrics.js +16 -12
  476. package/dist/telemetry/telemetry.d.ts +9 -1
  477. package/dist/telemetry/telemetry.js +16 -1
  478. package/dist/telemetry/verification-of.d.ts +3 -1
  479. package/dist/telemetry/verification-of.js +7 -1
  480. package/dist/wire-journal.js +12 -2
  481. package/docs/README.md +4 -2
  482. package/docs/actions.mdx +7 -6
  483. package/docs/adapters.md +2 -1
  484. package/docs/agent-cheatsheet.md +19 -5
  485. package/docs/architecture.md +13 -10
  486. package/docs/autodrive.md +6 -5
  487. package/docs/benchmarks.md +2 -2
  488. package/docs/capabilities.mdx +1 -1
  489. package/docs/cli/affected.mdx +1 -1
  490. package/docs/cli/cloud.mdx +6 -6
  491. package/docs/cli/doctor.mdx +3 -1
  492. package/docs/cli/feedback.mdx +11 -7
  493. package/docs/cli/gate.mdx +1 -1
  494. package/docs/cli/help.mdx +1 -1
  495. package/docs/cli/init.mdx +20 -16
  496. package/docs/cli/mcp.mdx +5 -2
  497. package/docs/cli/open.mdx +5 -2
  498. package/docs/cli/report.mdx +1 -1
  499. package/docs/cli/restart.mdx +1 -1
  500. package/docs/cli/rollback.mdx +4 -4
  501. package/docs/cli/serve.mdx +7 -5
  502. package/docs/cli/setup.mdx +1 -1
  503. package/docs/cli/status.mdx +6 -2
  504. package/docs/cli/stop.mdx +3 -3
  505. package/docs/cli/telemetry.mdx +5 -1
  506. package/docs/cli/try.mdx +8 -8
  507. package/docs/cli/update.mdx +8 -5
  508. package/docs/cli/verify.mdx +12 -5
  509. package/docs/cli/version.mdx +1 -1
  510. package/docs/cli.mdx +10 -6
  511. package/docs/debugging.md +1 -1
  512. package/docs/deploy-checks.md +8 -6
  513. package/docs/desktop.mdx +14 -18
  514. package/docs/enterprise.md +6 -6
  515. package/docs/environment.mdx +5 -3
  516. package/docs/faq.mdx +9 -6
  517. package/docs/first-drive.md +19 -9
  518. package/docs/flows.md +3 -4
  519. package/docs/for-agents.md +1 -1
  520. package/docs/frameworks.mdx +34 -11
  521. package/docs/getting-started.md +46 -29
  522. package/docs/http-transport.md +2 -2
  523. package/docs/human-control.md +8 -8
  524. package/docs/index.mdx +2 -2
  525. package/docs/install-agentic.mdx +18 -19
  526. package/docs/install-manual.mdx +8 -4
  527. package/docs/integration-patterns.md +5 -5
  528. package/docs/multi-agent-testing.md +7 -5
  529. package/docs/packages/browser.mdx +34 -2
  530. package/docs/packages/core.mdx +2 -1
  531. package/docs/packages/electron.mdx +15 -3
  532. package/docs/packages/eslint-plugin.mdx +1 -1
  533. package/docs/packages/next.mdx +17 -5
  534. package/docs/packages/react.mdx +8 -1
  535. package/docs/packages/server.mdx +3 -3
  536. package/docs/packages/tauri.mdx +3 -3
  537. package/docs/packages/vite-plugin.mdx +1 -1
  538. package/docs/packages.mdx +19 -6
  539. package/docs/platform-integration.md +12 -4
  540. package/docs/predicates.mdx +18 -7
  541. package/docs/production-mode.md +108 -0
  542. package/docs/prompt-capture.md +99 -0
  543. package/docs/quickstart.mdx +14 -12
  544. package/docs/recipes.mdx +9 -8
  545. package/docs/required-checks.md +3 -2
  546. package/docs/skill-file.mdx +4 -3
  547. package/docs/skill-setup.md +2 -2
  548. package/docs/skill.md +62 -70
  549. package/docs/state-files.md +1 -0
  550. package/docs/state-management.mdx +11 -9
  551. package/docs/system-map.md +14 -13
  552. package/docs/telemetry.md +32 -24
  553. package/docs/testing.md +9 -5
  554. package/docs/tools/act-and-wait.mdx +17 -13
  555. package/docs/tools/act-sequence.mdx +40 -66
  556. package/docs/tools/act.mdx +7 -5
  557. package/docs/tools/assert.mdx +1 -1
  558. package/docs/tools/look.mdx +1 -1
  559. package/docs/tools/navigate.mdx +1 -1
  560. package/docs/tools/network.mdx +13 -11
  561. package/docs/tools/overview.mdx +3 -3
  562. package/docs/tools/query.mdx +3 -3
  563. package/docs/tools/session-and-feedback.mdx +9 -6
  564. package/docs/tools/sessions.mdx +7 -0
  565. package/docs/tools/snapshot.mdx +9 -7
  566. package/docs/tools/tools-and-run.mdx +11 -10
  567. package/docs/tools/verify.mdx +1 -1
  568. package/docs/troubleshooting.mdx +21 -9
  569. package/docs/usage.md +58 -43
  570. package/docs/use-cases.mdx +2 -2
  571. package/docs/vs-chrome-devtools-mcp.mdx +5 -5
  572. package/docs/vs-playwright-mcp.mdx +5 -4
  573. package/docs/what-is-recorded.md +12 -7
  574. package/docs/what-is-reticle.mdx +2 -2
  575. package/docs/why-reticle.mdx +1 -1
  576. package/package.json +9 -12
  577. package/dist/command/dev/stale-issue-guard.d.ts +0 -34
  578. package/dist/command/dev/stale-issue-guard.js +0 -69
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What a sync cycle says about itself: one line for the CLI and the daemon log, and the failure a
3
+ * person reads in `reticle whoami`. Kept beside the cycle, apart from it, because the cycle is the
4
+ * protocol and this is only how it is reported.
5
+ */
6
+ import type { SyncReport } from './sync-cycle.js';
7
+ /**
8
+ * Say WHICH host failed and WHY.
9
+ *
10
+ * Node's fetch rejects with the bare string "fetch failed" and hides the real reason — a refused
11
+ * connection, a bad hostname, an expired certificate — one level down in `cause`. A machine that
12
+ * has quietly stopped syncing shows that string in `reticle whoami`, and on its own it is
13
+ * indistinguishable from every other network problem, so the person reading it learns nothing and
14
+ * checks nothing. Naming the origin and the underlying code turns it into one thing to look at.
15
+ */
16
+ export declare function describeTransportError(error: unknown, url: string): string;
17
+ /** One line a human can read, for the CLI and the daemon log. */
18
+ export declare function describeSync(report: SyncReport): string;
19
+ /**
20
+ * What went wrong, one phrase per kind of problem.
21
+ *
22
+ * One reason, not a count. A rejection count tells somebody they have a problem and nothing about
23
+ * which problem — and these arrive from a BACKGROUND daemon, so the summary line is often the only
24
+ * place anybody ever sees it. Rejections in one cycle almost always share a cause (a version skew
25
+ * refuses every payload the same way), so the first reason plus the count is the whole story
26
+ * without printing a line per item; `reticle sync` still lists them all.
27
+ */
28
+ export declare function problemsOf(report: SyncReport): string[];
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Say WHICH host failed and WHY.
3
+ *
4
+ * Node's fetch rejects with the bare string "fetch failed" and hides the real reason — a refused
5
+ * connection, a bad hostname, an expired certificate — one level down in `cause`. A machine that
6
+ * has quietly stopped syncing shows that string in `reticle whoami`, and on its own it is
7
+ * indistinguishable from every other network problem, so the person reading it learns nothing and
8
+ * checks nothing. Naming the origin and the underlying code turns it into one thing to look at.
9
+ */
10
+ export function describeTransportError(error, url) {
11
+ if (!(error instanceof Error))
12
+ return String(error);
13
+ const cause = error.cause;
14
+ if (!(cause instanceof Error))
15
+ return `${error.message} (${url})`;
16
+ const code = cause.code;
17
+ // The code and the message are each sometimes empty — an aggregate DNS failure carries a code and
18
+ // no text, a TLS failure the reverse. Joined only when both are there, so the line never trails
19
+ // off into a dangling separator.
20
+ const parts = ['string' === typeof code && code.length > 0 ? code : '', cause.message].filter((part) => part.length > 0);
21
+ const detail = parts.join(': ');
22
+ return 0 === detail.length
23
+ ? `${error.message} (${url})`
24
+ : `${error.message} — ${detail} (${url})`;
25
+ }
26
+ /** One line a human can read, for the CLI and the daemon log. */
27
+ export function describeSync(report) {
28
+ if (report.error !== undefined)
29
+ return `sync failed — ${report.error}`;
30
+ const sent = [];
31
+ if (report.runsSent > 0)
32
+ sent.push(`${String(report.runsSent)} run(s)`);
33
+ if (report.flowsSent > 0)
34
+ sent.push(`${String(report.flowsSent)} flow(s)`);
35
+ if (report.capsulesSent > 0)
36
+ sent.push(`${String(report.capsulesSent)} capsule(s)`);
37
+ if ((report.screenshotsSent ?? 0) > 0)
38
+ sent.push(`${String(report.screenshotsSent)} screenshot(s)`);
39
+ if (report.derivedSent.length > 0)
40
+ sent.push(report.derivedSent.join(', '));
41
+ /*
42
+ * "Nothing to send" is a statement about the QUEUE, and it is false the moment the queue was full
43
+ * and the server threw it away. Built from what was accepted, the sentence used to read "nothing
44
+ * to send, 3 rejected" — something was very much sent, and the reader is told both that it was
45
+ * not and nothing about why.
46
+ */
47
+ const rejectedCount = report.runsRejected.length + report.refused.length;
48
+ const push = sent.length > 0
49
+ ? `sent ${sent.join(' + ')}`
50
+ : rejectedCount > 0
51
+ ? 'nothing accepted'
52
+ : true === report.localIsEmpty
53
+ ? // Not the same statement as "nothing to send", which describes a repo that is simply up
54
+ // to date. This one has never recorded anything, which for a LINKED repo usually means
55
+ // the app announces no projectId and its runs are landing under a different root.
56
+ 'nothing recorded here yet — if this app has been driven, it is reporting somewhere else'
57
+ : 'nothing to send';
58
+ const pull = 0 === report.pulled
59
+ ? ''
60
+ : `, pulled ${String(report.pulled)} decision(s)${report.morePending ? ' (more waiting)' : ''}`;
61
+ return `${push}${pull}${problemsOf(report)
62
+ .map((problem) => `, ${problem}`)
63
+ .join('')}`;
64
+ }
65
+ /**
66
+ * What went wrong, one phrase per kind of problem.
67
+ *
68
+ * One reason, not a count. A rejection count tells somebody they have a problem and nothing about
69
+ * which problem — and these arrive from a BACKGROUND daemon, so the summary line is often the only
70
+ * place anybody ever sees it. Rejections in one cycle almost always share a cause (a version skew
71
+ * refuses every payload the same way), so the first reason plus the count is the whole story
72
+ * without printing a line per item; `reticle sync` still lists them all.
73
+ */
74
+ export function problemsOf(report) {
75
+ const problems = [];
76
+ const count = report.runsRejected.length + report.refused.length;
77
+ if (count > 0) {
78
+ const first = report.runsRejected[0]?.reason ?? report.refused[0]?.reason ?? 'no reason given';
79
+ problems.push(`${String(count)} rejected — ${first}`);
80
+ }
81
+ const firstRefusal = report.notRetried[0];
82
+ if (firstRefusal !== undefined)
83
+ problems.push(`refused, not retried: ${String(report.notRetried.length)} run(s) (${firstRefusal.reason})`);
84
+ for (const set of report.setsNotRetried)
85
+ problems.push(`refused, not retried: ${String(set.count)} ${set.part}(s) (${set.reason})`);
86
+ if (report.held.length > 0)
87
+ problems.push(`not sent: ${report.held.join('; ')}`);
88
+ const copies = report.flowConflicts ?? [];
89
+ if (copies.length > 0)
90
+ problems.push(`${String(copies.length)} flow conflict(s): another machine saved first, so this edit is kept as ${copies.join(', ')}; merge or delete it`);
91
+ return problems;
92
+ }
@@ -1,6 +1,14 @@
1
1
  import { type CloudSyncState, type PulledIssues, type SyncSink, type SyncSource } from './sync-cycle.js';
2
2
  /** What the cycle reads, backed by a real `.reticle` directory. */
3
- export declare function diskSource(reticleRoot: string): SyncSource;
3
+ export declare function diskSource(reticleRoot: string, env?: NodeJS.ProcessEnv): SyncSource;
4
+ /**
5
+ * The screenshot reader a sync policy allows: none with `screenshots` off, and none for a frame with
6
+ * `video` off. A frame held back this way is offered again each cycle, so turning video on sends it.
7
+ */
8
+ export declare function policyScreenshots(read: SyncSource['screenshot'], policy: {
9
+ screenshots: boolean;
10
+ video: boolean;
11
+ }): Pick<SyncSource, 'screenshot'>;
4
12
  /** What the cycle writes back into `.reticle/`. */
5
13
  export declare function diskSink(reticleRoot: string): SyncSink;
6
14
  /** This machine's side of the conversation, or a blank one on first run. */
@@ -11,10 +11,12 @@
11
11
  * error — the file will be rewritten on the next tool call anyway.
12
12
  */
13
13
  import { shareableRun } from '@reticlehq/core/artifacts';
14
+ import { agentContextFor } from '../journal/episode-log.js';
15
+ import { agentCaptureOff, agentCaptureOffIn, sharesRequests, } from '../intent/record-request.js';
14
16
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from 'node:fs';
15
17
  import { basename, dirname, join } from 'node:path';
16
18
  import { stepShotDir } from '../project/dir/reticle-dir.js';
17
- import { IntentDir, ReticleDir } from '@reticlehq/core';
19
+ import { IntentDir, ReticleDir, STEP_SCREENSHOT } from '@reticlehq/core';
18
20
  import { DERIVED_RECORDS, } from './sync-cycle.js';
19
21
  import { subjectFor } from '../intent/intent-subject.js';
20
22
  const JSON_SUFFIX = '.json';
@@ -47,8 +49,9 @@ function writeJson(path, value) {
47
49
  /** Every `*.json` directly inside a directory, parsed. Absent directory reads as empty. */
48
50
  function readJsonDir(dir) {
49
51
  try {
50
- if (!existsSync(dir))
52
+ if (!existsSync(dir)) {
51
53
  return [];
54
+ }
52
55
  return readdirSync(dir)
53
56
  .filter((f) => f.endsWith(JSON_SUFFIX))
54
57
  .map((f) => readJson(join(dir, f)))
@@ -62,25 +65,52 @@ function readJsonDir(dir) {
62
65
  * Flows: one directory deeper under the app's own project id, and also flat in `.reticle/flows/`,
63
66
  * which the flow store still saves and loads (a flow saved with no project id, or from before flows
64
67
  * were kept per project). Reading only the subfolders skipped every flat flow while the cycle
65
- * reported ok.
68
+ * reported ok. At any depth: a namespaced name (`onboarding/signup`) is a folder of its own, and
69
+ * reading one level down left every such flow on the machine.
66
70
  */
67
- function readFlows(root) {
68
- const dir = join(root, ReticleDir.FLOWS_SUBDIR);
69
- try {
70
- if (!existsSync(dir))
71
+ function readFlowFiles(root) {
72
+ const walk = (dir) => {
73
+ try {
74
+ return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
75
+ const path = join(dir, entry.name);
76
+ if (entry.isDirectory()) {
77
+ return walk(path);
78
+ }
79
+ if (!entry.name.endsWith(JSON_SUFFIX)) {
80
+ return [];
81
+ }
82
+ const flow = readJson(path);
83
+ return flow === undefined ? [] : [{ path, flow }];
84
+ });
85
+ }
86
+ catch {
71
87
  return [];
72
- return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
73
- if (entry.isDirectory())
74
- return readJsonDir(join(dir, entry.name));
75
- if (!entry.name.endsWith(JSON_SUFFIX))
76
- return [];
77
- const flow = readJson(join(dir, entry.name));
78
- return flow === undefined ? [] : [flow];
79
- });
88
+ }
89
+ };
90
+ return walk(join(root, ReticleDir.FLOWS_SUBDIR));
91
+ }
92
+ const readFlows = (root) => readFlowFiles(root).map(({ flow }) => flow);
93
+ /**
94
+ * Keep this machine's edit of `name` as `<name>-conflict-<n>` in a file beside it, and write the
95
+ * platform's version in its place. Answers the copy's name, or undefined when the flow is not here.
96
+ */
97
+ function keepConflictCopy(root, name, theirs) {
98
+ const held = readFlowFiles(root).find(({ flow }) => 'object' === typeof flow && null !== flow && flow.name === name);
99
+ if (held === undefined || 'object' !== typeof theirs || null === theirs) {
100
+ return undefined;
80
101
  }
81
- catch {
82
- return [];
102
+ const stem = held.path.slice(0, -JSON_SUFFIX.length);
103
+ let n = 1;
104
+ while (existsSync(`${stem}-conflict-${String(n)}${JSON_SUFFIX}`)) {
105
+ n += 1;
83
106
  }
107
+ const copy = `${name}-conflict-${String(n)}`;
108
+ writeJson(`${stem}-conflict-${String(n)}${JSON_SUFFIX}`, {
109
+ ...held.flow,
110
+ name: copy,
111
+ });
112
+ writeJson(held.path, theirs);
113
+ return copy;
84
114
  }
85
115
  const DERIVED_FILE = Object.fromEntries(DERIVED_RECORDS.map((record) => [record.kind, record.file]));
86
116
  /** The directory the sharded intent store writes into, beside the legacy flat file. */
@@ -112,8 +142,9 @@ function readIntent(reticleRoot) {
112
142
  };
113
143
  let shards = 0;
114
144
  for (const entry of safeReaddir(join(reticleRoot, INTENT_SUBDIR))) {
115
- if (INTENT_INDEX === entry)
145
+ if (INTENT_INDEX === entry) {
116
146
  continue;
147
+ }
117
148
  // `<subject>/intent.json` is the layout; a bare `<subject>.json` is an interim shard the store
118
149
  // has not migrated yet, and is still this project's memory until it has.
119
150
  const path = entry.endsWith(JSON_SUFFIX)
@@ -121,14 +152,17 @@ function readIntent(reticleRoot) {
121
152
  : join(reticleRoot, INTENT_SUBDIR, entry, IntentDir.SHARD_FILE);
122
153
  const shard = readJson(path);
123
154
  // A hand-edited or half-written shard costs one subject, never the whole sync.
124
- if (shard?.intents === undefined)
155
+ if (shard?.intents === undefined) {
125
156
  continue;
157
+ }
126
158
  shards++;
127
- for (const [id, record] of Object.entries(shard.intents))
159
+ for (const [id, record] of Object.entries(shard.intents)) {
128
160
  merged[id] = record;
161
+ }
129
162
  }
130
- if (legacy === undefined && 0 === shards)
163
+ if (legacy === undefined && 0 === shards) {
131
164
  return undefined;
165
+ }
132
166
  /*
133
167
  * Stamp the SUBJECT before sending, on anything that does not already carry one.
134
168
  *
@@ -153,8 +187,9 @@ function readIntent(reticleRoot) {
153
187
  ...('string' === typeof run && 0 < run.length ? { provedBy: run } : {}),
154
188
  };
155
189
  const held = record;
156
- if ('string' === typeof held.subject && held.subject.length > 0)
190
+ if ('string' === typeof held.subject && held.subject.length > 0) {
157
191
  return [id, record];
192
+ }
158
193
  const subject = subjectFor({
159
194
  surface: held.surface,
160
195
  binding: held.binding,
@@ -172,18 +207,68 @@ function safeReaddir(dir) {
172
207
  return [];
173
208
  }
174
209
  }
210
+ /**
211
+ * A run with the agent's model and the claim that closed its turn, from the agent hooks' records
212
+ * (see `agentContextFor`). Filled only where the run says nothing. The claim goes into the prompt
213
+ * context, so it leaves the machine under the same share decision as the request: a context the
214
+ * run did not have takes the project's setting.
215
+ */
216
+ function withAgentContext(payload, reticleRoot) {
217
+ if ('object' !== typeof payload || null === payload) {
218
+ return payload;
219
+ }
220
+ const run = payload;
221
+ const found = agentContextFor(reticleRoot, run);
222
+ let out = { ...run };
223
+ if (found.model !== undefined && run.agent !== undefined && run.agent.model === undefined) {
224
+ out = { ...out, agent: { ...run.agent, model: found.model } };
225
+ }
226
+ if (found.claim !== undefined && run.context?.closingClaim === undefined) {
227
+ const shared = 'boolean' === typeof run.context?.shared
228
+ ? run.context.shared
229
+ : sharesRequests(dirname(reticleRoot), reticleRoot);
230
+ out = {
231
+ ...out,
232
+ context: {
233
+ statements: [],
234
+ ...run.context,
235
+ closingClaim: found.claim.text,
236
+ closingClaimAt: found.claim.at,
237
+ shared,
238
+ },
239
+ };
240
+ }
241
+ return out;
242
+ }
243
+ /**
244
+ * A run with nothing the agent hooks kept: no prompt context. Agent capture is off, so the files
245
+ * that the hooks wrote before the switch went off do not leave the machine either.
246
+ */
247
+ function withoutAgentCapture(payload) {
248
+ if ('object' !== typeof payload || null === payload) {
249
+ return payload;
250
+ }
251
+ const { context: _context, ...rest } = payload;
252
+ return rest;
253
+ }
175
254
  /** What the cycle reads, backed by a real `.reticle` directory. */
176
- export function diskSource(reticleRoot) {
255
+ export function diskSource(reticleRoot, env = process.env) {
177
256
  return {
178
- runs: () => readJsonDir(join(reticleRoot, ReticleDir.RUNS_SUBDIR))
179
- .map((payload) => {
180
- const id = payload?.runId;
181
- // The prompt context leaves the machine only when the project opted in.
182
- return 'string' === typeof id ? { runId: id, payload: shareableRun(payload) } : undefined;
183
- })
184
- // A run artifact with no id cannot be diffed against the server's list, so sending it would
185
- // mean re-sending it every cycle forever. Dropped rather than uploaded repeatedly.
186
- .filter((r) => r !== undefined),
257
+ runs: () => {
258
+ const captureOff = agentCaptureOff(env) || agentCaptureOffIn(dirname(reticleRoot));
259
+ return (readJsonDir(join(reticleRoot, ReticleDir.RUNS_SUBDIR))
260
+ .map((payload) => {
261
+ const id = payload?.runId;
262
+ // The prompt context leaves the machine only when the project opted in.
263
+ const sent = captureOff
264
+ ? withoutAgentCapture(payload)
265
+ : shareableRun(withAgentContext(payload, reticleRoot));
266
+ return 'string' === typeof id ? { runId: id, payload: sent } : undefined;
267
+ })
268
+ // A run artifact with no id cannot be diffed against the server's list, so sending it
269
+ // would mean re-sending it every cycle forever. Dropped rather than uploaded repeatedly.
270
+ .filter((r) => r !== undefined));
271
+ },
187
272
  flows: () => readFlows(reticleRoot),
188
273
  // Flat directory of `<id>.json`, which is exactly what readJsonDir walks — unlike flows, which
189
274
  // sit one level deeper under the app's project id.
@@ -194,8 +279,9 @@ export function diskSource(reticleRoot) {
194
279
  // own directory before it is read.
195
280
  screenshot: (runId, file) => {
196
281
  try {
197
- if (basename(file) !== file)
282
+ if (basename(file) !== file) {
198
283
  return undefined;
284
+ }
199
285
  return new Uint8Array(readFileSync(join(stepShotDir(reticleRoot, runId), file)));
200
286
  }
201
287
  catch {
@@ -204,6 +290,23 @@ export function diskSource(reticleRoot) {
204
290
  },
205
291
  };
206
292
  }
293
+ /** A frame's file name ends in its tool: `<seq>-frame.jpg`. */
294
+ const FRAME_FILE_SUFFIX = `-${STEP_SCREENSHOT.FRAME_TOOL}.jpg`;
295
+ /**
296
+ * The screenshot reader a sync policy allows: none with `screenshots` off, and none for a frame with
297
+ * `video` off. A frame held back this way is offered again each cycle, so turning video on sends it.
298
+ */
299
+ export function policyScreenshots(read, policy) {
300
+ if (!policy.screenshots || read === undefined) {
301
+ return {};
302
+ }
303
+ if (policy.video) {
304
+ return { screenshot: read };
305
+ }
306
+ return {
307
+ screenshot: (runId, file) => (file.endsWith(FRAME_FILE_SUFFIX) ? undefined : read(runId, file)),
308
+ };
309
+ }
207
310
  /** What the cycle writes back into `.reticle/`. */
208
311
  export function diskSink(reticleRoot) {
209
312
  return {
@@ -218,6 +321,7 @@ export function diskSink(reticleRoot) {
218
321
  writeState: (state) => {
219
322
  writeJson(join(reticleRoot, ReticleDir.CLOUD_STATE_FILE), state);
220
323
  },
324
+ resolveFlowConflict: (name, theirs) => keepConflictCopy(reticleRoot, name, theirs),
221
325
  };
222
326
  }
223
327
  /** This machine's side of the conversation, or a blank one on first run. */
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Compare-and-set for flows. Each pushed flow names the platform version it was based on; a push based
3
+ * on a version another machine has since replaced comes back as a conflict carrying the platform's
4
+ * version. This machine then keeps its own edit as a named copy beside the flow and takes the
5
+ * platform's, so nothing is lost and nothing diverges silently. Kept apart from the cycle, which is the
6
+ * protocol; this is the one rule about flow versions.
7
+ */
8
+ /** The platform's code for a flow pushed on a version it no longer holds (its HTTP 409). */
9
+ export declare const FLOW_CONFLICT_CODE = "conflict";
10
+ /** Versions by name, as kept in the state: only strings count. */
11
+ export declare function versionsIn(value: unknown): Record<string, string>;
12
+ /**
13
+ * What each pending flow was based on: the version last taken here; null for a flow this machine never
14
+ * sent; nothing for one an older client sent without a version (stored unconditionally, as it was).
15
+ */
16
+ export declare function flowBases(pending: ReadonlyArray<{
17
+ name: string;
18
+ }>, versions: Record<string, string>, sentHashes: Record<string, string>): Record<string, string | null>;
19
+ /** A refusal that is a conflict this machine can settle, with the platform's version. */
20
+ export declare function conflictOf(r: {
21
+ code: unknown;
22
+ current: unknown;
23
+ }): {
24
+ version: string;
25
+ flow: unknown;
26
+ } | undefined;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Compare-and-set for flows. Each pushed flow names the platform version it was based on; a push based
3
+ * on a version another machine has since replaced comes back as a conflict carrying the platform's
4
+ * version. This machine then keeps its own edit as a named copy beside the flow and takes the
5
+ * platform's, so nothing is lost and nothing diverges silently. Kept apart from the cycle, which is the
6
+ * protocol; this is the one rule about flow versions.
7
+ */
8
+ /** The platform's code for a flow pushed on a version it no longer holds (its HTTP 409). */
9
+ export const FLOW_CONFLICT_CODE = 'conflict';
10
+ const isRecord = (v) => 'object' === typeof v && null !== v;
11
+ /** Versions by name, as kept in the state: only strings count. */
12
+ export function versionsIn(value) {
13
+ const out = {};
14
+ if (isRecord(value))
15
+ for (const [name, v] of Object.entries(value))
16
+ if ('string' === typeof v)
17
+ out[name] = v;
18
+ return out;
19
+ }
20
+ /**
21
+ * What each pending flow was based on: the version last taken here; null for a flow this machine never
22
+ * sent; nothing for one an older client sent without a version (stored unconditionally, as it was).
23
+ */
24
+ export function flowBases(pending, versions, sentHashes) {
25
+ const out = {};
26
+ for (const { name } of pending) {
27
+ const v = versions[name];
28
+ if (v !== undefined)
29
+ out[name] = v;
30
+ else if (sentHashes[name] === undefined)
31
+ out[name] = null;
32
+ }
33
+ return out;
34
+ }
35
+ /** A refusal that is a conflict this machine can settle, with the platform's version. */
36
+ export function conflictOf(r) {
37
+ const current = isRecord(r.current) ? r.current : undefined;
38
+ const version = current?.['version'];
39
+ return FLOW_CONFLICT_CODE === r.code && 'string' === typeof version
40
+ ? { version, flow: current?.['flow'] }
41
+ : undefined;
42
+ }
@@ -2,6 +2,7 @@ import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
2
  import { SyncStatus, dashboardRunUrl, describeSync, keyRefusalAtLastSync, overallStatus, readSyncSummary, } from '../project/sync-status.js';
3
3
  import { describeUnsynced, unsentFlowCount, unsentRunCount, } from '../cloud/unsynced-roots.js';
4
4
  import { readDashboardUrl } from '../project/sync-status.js';
5
+ import { mayWriteIntoRoot } from '../project/artifact-root-resolver.js';
5
6
  import { dirname, join } from 'node:path';
6
7
  import { homedir } from 'node:os';
7
8
  import { readAccountState } from '../cloud/account-state.js';
@@ -107,10 +108,12 @@ function streakEndingAtLatest(sortedDates) {
107
108
  let later;
108
109
  for (let i = sortedDates.length - 1; i >= 0; i -= 1) {
109
110
  const date = sortedDates[i];
110
- if (date === undefined)
111
+ if (date === undefined) {
111
112
  break;
112
- if (later !== undefined && !isNextDay(date, later))
113
+ }
114
+ if (later !== undefined && !isNextDay(date, later)) {
113
115
  break;
116
+ }
114
117
  streak += 1;
115
118
  later = date;
116
119
  }
@@ -131,8 +134,9 @@ export function applyDelta(scope, delta, now, meta = {}) {
131
134
  byDate.set(today, todayCounts);
132
135
  const dates = [...byDate.keys()].sort();
133
136
  const days = dates.map((date) => ({ date, counts: byDate.get(date) ?? emptyImpactCounts() }));
134
- while (days.length > IMPACT_DAILY_BUCKETS)
137
+ while (days.length > IMPACT_DAILY_BUCKETS) {
135
138
  days.shift();
139
+ }
136
140
  const records = { ...scope.records };
137
141
  records.bestVerdictDay = Math.max(records.bestVerdictDay, todayCounts.verdicts);
138
142
  records.bestDefectDay = Math.max(records.bestDefectDay, todayCounts.failed);
@@ -165,8 +169,9 @@ export function applyDelta(scope, delta, now, meta = {}) {
165
169
  /** The larger of two counters, key by key. */
166
170
  function maxEach(a, b) {
167
171
  const out = { ...a };
168
- for (const key of Object.keys(b))
172
+ for (const key of Object.keys(b)) {
169
173
  out[key] = Math.max(a[key] ?? 0, b[key] ?? 0);
174
+ }
170
175
  return out;
171
176
  }
172
177
  /**
@@ -254,8 +259,9 @@ export class ImpactStore {
254
259
  }
255
260
  #syncStatus(dashboardUrl) {
256
261
  const now = this.#now();
257
- if (this.#sync !== undefined && now - this.#sync.at < SYNC_STATUS_EVERY_MS)
262
+ if (this.#sync !== undefined && now - this.#sync.at < SYNC_STATUS_EVERY_MS) {
258
263
  return this.#sync.value;
264
+ }
259
265
  // Not linked: one line when runs or flows sit here that nothing will send, and nothing otherwise.
260
266
  // `pending` counts both, so the HUD's existing "N not sent" includes a flow saved with no run.
261
267
  if (dashboardUrl === undefined) {
@@ -312,18 +318,21 @@ export class ImpactStore {
312
318
  project: this.#project,
313
319
  global: atLeastProject(this.#global, this.#project),
314
320
  };
315
- if (this.#projectName !== undefined)
321
+ if (this.#projectName !== undefined) {
316
322
  snap.projectName = this.#projectName;
323
+ }
317
324
  // Re-read, like the account: `reticle link` runs in another terminal while this store lives as
318
325
  // long as the daemon, so a construction-time read said "Not linked" until a restart.
319
326
  this.#dashboardUrl = readDashboardUrl(this.#root);
320
- if (this.#dashboardUrl !== undefined)
327
+ if (this.#dashboardUrl !== undefined) {
321
328
  snap.dashboardUrl = this.#dashboardUrl;
329
+ }
322
330
  snap.account = this.#account();
323
331
  // Absent stays absent: the HUD reads that as "we have not heard" and renders no control.
324
332
  const cfg = this.#config.read();
325
- if (cfg !== undefined)
333
+ if (cfg !== undefined) {
326
334
  snap.harnessConfig = configForHud(cfg, this.#now());
335
+ }
327
336
  // Chosen here, where the account and the entitlement are both known. Absent when nothing applies,
328
337
  // so the HUD falls back to the slides bundled with the SDK.
329
338
  const notices = selectNotices(this.#notices.read(), {
@@ -332,16 +341,19 @@ export class ImpactStore {
332
341
  sdkVersion: this.#sdkVersion,
333
342
  now: this.#now(),
334
343
  });
335
- if (0 < notices.length)
344
+ if (0 < notices.length) {
336
345
  snap.notices = notices;
346
+ }
337
347
  const coverage = this.#coverage?.();
338
- if (coverage !== undefined)
348
+ if (coverage !== undefined) {
339
349
  snap.coverage = coverage;
350
+ }
340
351
  // Only for a linked project: an unlinked one has nothing on the platform, and the HUD already
341
352
  // offers the way to link it.
342
353
  const sync = this.#syncStatus(this.#dashboardUrl);
343
- if (sync !== undefined)
354
+ if (sync !== undefined) {
344
355
  snap.sync = sync;
356
+ }
345
357
  return snap;
346
358
  }
347
359
  /** Write now (process exit, tests). */
@@ -350,8 +362,11 @@ export class ImpactStore {
350
362
  clearTimeout(this.#timer);
351
363
  this.#timer = undefined;
352
364
  }
353
- // One writer: the in-memory copy IS the truth.
354
- writeScope(this.#paths.project, this.#project);
365
+ // One writer: the in-memory copy IS the truth. A project with no Reticle wiring gets no
366
+ // `.reticle/`: its scope stays in memory, and the first flush after `init` writes all of it.
367
+ if (mayWriteIntoRoot(this.#root)) {
368
+ writeScope(this.#paths.project, this.#project);
369
+ }
355
370
  this.#flushGlobal();
356
371
  }
357
372
  /**
@@ -367,16 +382,18 @@ export class ImpactStore {
367
382
  * plus a stale timeout) if the counters are ever load-bearing for anything but the HUD.
368
383
  */
369
384
  #flushGlobal() {
370
- if (0 === this.#pendingGlobal.length)
385
+ if (0 === this.#pendingGlobal.length) {
371
386
  return;
387
+ }
372
388
  const merged = this.#pendingGlobal.reduce((scope, p) => applyDelta(scope, p.delta, p.now, p.meta), readScope(this.#paths.global, this.#now()));
373
389
  writeScope(this.#paths.global, merged);
374
390
  this.#global = merged;
375
391
  this.#pendingGlobal = [];
376
392
  }
377
393
  #scheduleFlush() {
378
- if (this.#timer !== undefined)
394
+ if (this.#timer !== undefined) {
379
395
  return;
396
+ }
380
397
  this.#timer = setTimeout(() => {
381
398
  this.#timer = undefined;
382
399
  this.flush();