@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
@@ -10,7 +10,9 @@
10
10
  * the thin Playwright adapter that satisfies these interfaces lives separately.
11
11
  */
12
12
  import { unreachableUrlIn } from '@reticlehq/core';
13
- import { seedStorageInto } from './storage-seed.js';
13
+ import { seedStorageInto, targetOriginOf } from './storage-seed.js';
14
+ import { installLeaseMarker, leaseMarkerOf } from './lease-marker-stamp.js';
15
+ import { grantLeasePermissions, NOTIFICATION_PERMISSION_READ, NOTIFICATION_READ_TIMEOUT_MS, } from './context-permissions.js';
14
16
  /** Default lease time-to-live: a lease untouched for this long is presumed orphaned and reclaimed. */
15
17
  export const DEFAULT_LEASE_TTL_MS = 5 * 60_000;
16
18
  /** Default cap on how long a lease's initial navigation may take before it fails (frees the slot). */
@@ -22,6 +24,13 @@ const DEFAULT_NAV_TIMEOUT_MS = 30_000;
22
24
  const MAX_REMEMBERED_REAPED_LEASES = 64;
23
25
  /** What a headed lease is refused with where no window can be opened. */
24
26
  export const NO_HEADED_BROWSER = 'no headed browser can be opened here';
27
+ /**
28
+ * What an acquire that asked for an init script is refused with when the page cannot run one.
29
+ *
30
+ * A refusal rather than a lease: the caller asked for a stub of the bindings a desktop shell
31
+ * injects, and a tab opened without it would throw in the app's view and read as a broken app.
32
+ */
33
+ const INIT_SCRIPT_UNSUPPORTED = 'Init script failed: this page does not support init scripts, so the requested stub would not be there';
25
34
  /**
26
35
  * Owns a headless browser (and, when asked, a headed one) and leases isolated contexts out of them,
27
36
  * capped at `maxContexts` across both.
@@ -181,6 +190,15 @@ export class BrowserPool {
181
190
  #leaseIdOf(sessionId) {
182
191
  return this.#active.has(sessionId) ? sessionId : (this.#aliases.get(sessionId) ?? sessionId);
183
192
  }
193
+ /**
194
+ * Whether `sessionId` is a live lease that `owner` may let go of: one it took, or one taken by a
195
+ * caller with no id, which cannot be told apart from it. Another agent's lease is never this
196
+ * caller's to close (#1226).
197
+ */
198
+ heldBy(sessionId, owner) {
199
+ const lease = this.#active.get(this.#leaseIdOf(sessionId));
200
+ return lease !== undefined && (lease.owner === undefined || lease.owner === owner);
201
+ }
184
202
  /** Mark a lease as still in use (called on agent activity) so the reaper doesn't reclaim it. */
185
203
  touch(sessionId) {
186
204
  const lease = this.#active.get(this.#leaseIdOf(sessionId));
@@ -215,6 +233,28 @@ export class BrowserPool {
215
233
  return undefined;
216
234
  }
217
235
  }
236
+ /** The URL a lease was opened on — the one that carries its Reticle identity. */
237
+ leaseUrl(sessionId) {
238
+ return this.#active.get(this.#leaseIdOf(sessionId))?.url;
239
+ }
240
+ /**
241
+ * Navigate a leased page through the browser. For a lease whose page has no SDK to take the
242
+ * command — a navigate to an image left the lease unreachable, and the next navigate answered "no
243
+ * connected session". False when this is not a lease or the page would not go.
244
+ */
245
+ async gotoLease(sessionId, url, timeoutMs) {
246
+ const lease = this.#active.get(this.#leaseIdOf(sessionId));
247
+ if (lease === undefined)
248
+ return false;
249
+ this.touch(sessionId);
250
+ try {
251
+ await lease.page.goto(url, timeoutMs === undefined ? {} : { timeoutMs });
252
+ return true;
253
+ }
254
+ catch {
255
+ return false;
256
+ }
257
+ }
218
258
  /**
219
259
  * Move the real pointer on a leased page, or false when this session is not a lease or cannot
220
260
  * hover. Same optional-capability contract as screenshotLease: absence must read as "could not
@@ -275,6 +315,52 @@ export class BrowserPool {
275
315
  return false;
276
316
  }
277
317
  }
318
+ /** What a lease was granted when it opened, or undefined for a session that is not a lease. */
319
+ permissionsOf(sessionId) {
320
+ return this.#active.get(this.#leaseIdOf(sessionId))?.permissions;
321
+ }
322
+ /**
323
+ * Whether this lease's page runs a caller-supplied init script — a stub of the bindings a desktop
324
+ * shell injects. Alias-resolved like every agent-facing lookup, and false for any session that is
325
+ * not a lease with a stub, so a verdict can say when it was measured against a fake shell.
326
+ */
327
+ stubInstalled(sessionId) {
328
+ return this.#active.get(this.#leaseIdOf(sessionId))?.hostStub !== undefined;
329
+ }
330
+ /**
331
+ * The init script this lease installed, or undefined when it runs none. Alias-resolved like
332
+ * `stubInstalled`. The lease tool compares it to the script a caller asks for: the same text means
333
+ * the held tab already is what was asked for, so it is reused rather than released and remade.
334
+ */
335
+ hostStubScript(sessionId) {
336
+ return this.#active.get(this.#leaseIdOf(sessionId))?.hostStubScript;
337
+ }
338
+ /**
339
+ * What the leased page's `Notification.permission` says, or undefined when it cannot be asked.
340
+ *
341
+ * Read back rather than inferred from the grant, because the headless shell answers `denied`
342
+ * after a notifications grant — see context-permissions.ts. Bounded, so a page that never answers
343
+ * reads as "could not ask" instead of holding the caller.
344
+ */
345
+ async notificationPermission(sessionId) {
346
+ const lease = this.#active.get(this.#leaseIdOf(sessionId));
347
+ if (lease === undefined || lease.page.evaluate === undefined)
348
+ return undefined;
349
+ let timer;
350
+ const gaveUp = new Promise((resolve) => {
351
+ timer = setTimeout(() => resolve(undefined), NOTIFICATION_READ_TIMEOUT_MS);
352
+ });
353
+ try {
354
+ const value = await Promise.race([lease.page.evaluate(NOTIFICATION_PERMISSION_READ), gaveUp]);
355
+ return 'string' === typeof value ? value : undefined;
356
+ }
357
+ catch {
358
+ return undefined;
359
+ }
360
+ finally {
361
+ clearTimeout(timer);
362
+ }
363
+ }
278
364
  async sweepExpired() {
279
365
  const now = this.#now();
280
366
  const expired = [...this.#active.entries()]
@@ -336,8 +422,21 @@ export class BrowserPool {
336
422
  let pendingDialogMessage;
337
423
  try {
338
424
  const browser = await this.#ensureBrowser(slot);
339
- context = await browser.newContext();
425
+ context = await browser.newContext(true === opts.ignoreHTTPSErrors ? { ignoreHTTPSErrors: true } : undefined);
426
+ if (opts.permissions !== undefined)
427
+ await grantLeasePermissions(context, opts.permissions, url);
340
428
  const page = await context.newPage();
429
+ // A caller-supplied init script is a stub of the bindings a desktop shell injects, and it has
430
+ // to exist before the app's first module runs. Installed here — before goto — so the very
431
+ // first document gets it, and kept for the lease (see hostStub) so a reload keeps it too.
432
+ let hostStub;
433
+ if (opts.initScript !== undefined) {
434
+ const added = await page.addInitScript?.(opts.initScript);
435
+ if (added === undefined || 'function' !== typeof added.dispose) {
436
+ throw new Error(INIT_SCRIPT_UNSUPPORTED);
437
+ }
438
+ hostStub = added;
439
+ }
341
440
  // Per-page crash isolation: if THIS renderer dies, reclaim only this lease — the shared browser
342
441
  // and every other agent's context keep running. (A full browser death is handled by #onCrash.)
343
442
  page.onCrash(() => {
@@ -367,6 +466,10 @@ export class BrowserPool {
367
466
  pendingDialogMessage = dialog.message;
368
467
  void dialog.dismiss();
369
468
  });
469
+ const marker = leaseMarkerOf(url);
470
+ if (marker?.session === sessionId) {
471
+ await installLeaseMarker(page, sessionId, targetOriginOf(url), marker.project);
472
+ }
370
473
  let seedHandle;
371
474
  let checkSeedError;
372
475
  if (opts.seedStorage !== undefined) {
@@ -390,6 +493,9 @@ export class BrowserPool {
390
493
  // no longer the live browser, bail — the catch below closes the context and returns the slot.
391
494
  if (slot.browser !== browser)
392
495
  throw new Error('browser crashed during navigation');
496
+ // Foreground it: a page opened beside other tabs can start hidden (#1351). Best-effort — a tab
497
+ // that stays hidden is reported by name at the lease, which failing here would lose.
498
+ await page.bringToFront?.().catch(() => undefined);
393
499
  let navStatus;
394
500
  if (null !== navRes && 'object' === typeof navRes && 'status' in navRes) {
395
501
  const s = navRes.status;
@@ -414,8 +520,13 @@ export class BrowserPool {
414
520
  url,
415
521
  ...(opts.owner === undefined ? {} : { owner: opts.owner }),
416
522
  touchedAt: this.#now(),
523
+ permissions: opts.permissions ?? [],
524
+ ignoresHTTPSErrors: true === opts.ignoreHTTPSErrors,
417
525
  ...(pending === undefined ? {} : { dialFailureUrl: pending }),
418
526
  ...(pendingDialogMessage === undefined ? {} : { lastDialogMessage: pendingDialogMessage }),
527
+ ...(hostStub === undefined || opts.initScript === undefined
528
+ ? {}
529
+ : { hostStub, hostStubScript: opts.initScript }),
419
530
  });
420
531
  return {
421
532
  sessionId,
@@ -492,6 +603,9 @@ export class BrowserPool {
492
603
  if (leaseId === sessionId)
493
604
  this.#aliases.delete(registered);
494
605
  }
606
+ // Disposed with the lease, which is what "for that lease only" means. Best-effort: a context
607
+ // that is already gone (a crash) makes the disposal moot, not a reason to fail the release.
608
+ await lease.hostStub?.dispose().catch(() => undefined);
495
609
  await lease.context.close().catch(() => undefined);
496
610
  this.#releaseSlot();
497
611
  }
@@ -597,6 +711,10 @@ export class BrowserPool {
597
711
  for (const waiter of this.#waiters.splice(0))
598
712
  waiter(); // let them re-claim + relaunch
599
713
  }
714
+ /** Whether this lease's context skips certificate checks. A context cannot change it later. */
715
+ ignoresHTTPSErrors(sessionId) {
716
+ return true === this.#active.get(this.#leaseIdOf(sessionId))?.ignoresHTTPSErrors;
717
+ }
600
718
  /** Whether this lease lives in the headed browser. */
601
719
  isHeaded(sessionId) {
602
720
  return true === this.#active.get(this.#leaseIdOf(sessionId))?.headed;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Browser permissions on a leased context: granted before the first navigation, and read back where
3
+ * the browser can contradict the grant.
4
+ *
5
+ * Never changed on a lease that is already open. Acquire hands an origin's live lease to whoever asks
6
+ * for that origin, so the lease may be another agent's tab mid-flow, and nothing here knows whose it
7
+ * is. A different set means a fresh lease.
8
+ *
9
+ * Each grant is scoped to the origin the lease was opened on, so a third-party frame the app embeds
10
+ * is not handed the same grant as the app.
11
+ *
12
+ * Notifications are why the read-back exists. Playwright's headless shell — what the pool launches
13
+ * when Playwright's own Chromium is installed — has no notification support: after a grant,
14
+ * `navigator.permissions.query` reports `granted` while `Notification.permission` still reads
15
+ * `denied`. A page that gates its UI on the second never sees the grant, so a lease that reported
16
+ * "granted" there would be reporting something the page cannot see.
17
+ */
18
+ import type { PooledContext } from './pool-contract.js';
19
+ /** The permission whose grant the headless shell does not pass on to `Notification.permission`. */
20
+ export declare const NOTIFICATIONS_PERMISSION = "notifications";
21
+ /** Evaluated in the leased page. A string, because the pool's page surface evaluates scripts. */
22
+ export declare const NOTIFICATION_PERMISSION_READ = "typeof Notification === 'undefined' ? 'unsupported' : Notification.permission";
23
+ /**
24
+ * How long a read-back may take. Bounded because acquire waits on it, and a wedged renderer never
25
+ * answers an evaluation: an unbounded one would turn "this tab is stuck" into "acquire hangs".
26
+ */
27
+ export declare const NOTIFICATION_READ_TIMEOUT_MS = 1500;
28
+ /** A permission could not be granted or cleared. Its message is written for the agent. */
29
+ export declare class LeasePermissionError extends Error {
30
+ readonly name = "LeasePermissionError";
31
+ }
32
+ /** Grant `permissions` on the origin of `url`. Nothing to grant is a no-op, not a refusal. */
33
+ export declare function grantLeasePermissions(context: PooledContext, permissions: readonly string[], url: string): Promise<void>;
@@ -0,0 +1,33 @@
1
+ /** The permission whose grant the headless shell does not pass on to `Notification.permission`. */
2
+ export const NOTIFICATIONS_PERMISSION = 'notifications';
3
+ /** Evaluated in the leased page. A string, because the pool's page surface evaluates scripts. */
4
+ export const NOTIFICATION_PERMISSION_READ = "typeof Notification === 'undefined' ? 'unsupported' : Notification.permission";
5
+ /**
6
+ * How long a read-back may take. Bounded because acquire waits on it, and a wedged renderer never
7
+ * answers an evaluation: an unbounded one would turn "this tab is stuck" into "acquire hangs".
8
+ */
9
+ export const NOTIFICATION_READ_TIMEOUT_MS = 1_500;
10
+ /** Playwright prefixes its errors with the call that failed; the agent needs only the reason. */
11
+ const PLAYWRIGHT_CALL_PREFIX = /^browserContext\.\w+:\s*/;
12
+ /** A permission could not be granted or cleared. Its message is written for the agent. */
13
+ export class LeasePermissionError extends Error {
14
+ name = 'LeasePermissionError';
15
+ }
16
+ function reasonOf(err) {
17
+ const message = err instanceof Error ? err.message : String(err);
18
+ return (message.split('\n')[0] ?? message).replace(PLAYWRIGHT_CALL_PREFIX, '');
19
+ }
20
+ /** Grant `permissions` on the origin of `url`. Nothing to grant is a no-op, not a refusal. */
21
+ export async function grantLeasePermissions(context, permissions, url) {
22
+ if (0 === permissions.length)
23
+ return;
24
+ if (context.grantPermissions === undefined) {
25
+ throw new LeasePermissionError('this browser context cannot grant permissions');
26
+ }
27
+ try {
28
+ await context.grantPermissions([...permissions], { origin: new URL(url).origin });
29
+ }
30
+ catch (err) {
31
+ throw new LeasePermissionError(`could not grant ${permissions.join(', ')}: ${reasonOf(err)}`);
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ import type { PooledPage } from './pool-contract.js';
2
+ interface LeaseMarkerArg {
3
+ session: string;
4
+ project?: string | undefined;
5
+ targetOrigin: string;
6
+ sessionParam: string;
7
+ projectParam: string;
8
+ }
9
+ /**
10
+ * Init script restoring the marker a server redirect dropped, so the SDK registers under the lease id.
11
+ * It runs only in pages of the lease's own browser context, so a person's tab at the same URL never
12
+ * carries the marker and is never adopted. It writes only in the top frame, only on the lease's own
13
+ * target origin (never an identity provider's or any third party's URL), and the pool installs it
14
+ * only when the navigated URL's marker matches this lease's id. Must stay self-contained: Playwright
15
+ * serialises the function source into the page.
16
+ */
17
+ export declare function stampLeaseMarker(arg: LeaseMarkerArg): void;
18
+ export declare function installLeaseMarker(page: PooledPage, leaseId: string, targetOrigin: string | undefined, project: string | undefined): Promise<void>;
19
+ export declare function leaseMarkerOf(url: string): {
20
+ session: string;
21
+ project: string | undefined;
22
+ } | undefined;
23
+ export {};
@@ -0,0 +1,49 @@
1
+ import { RETICLE_URL_PARAM } from '@reticlehq/core';
2
+ /**
3
+ * Init script restoring the marker a server redirect dropped, so the SDK registers under the lease id.
4
+ * It runs only in pages of the lease's own browser context, so a person's tab at the same URL never
5
+ * carries the marker and is never adopted. It writes only in the top frame, only on the lease's own
6
+ * target origin (never an identity provider's or any third party's URL), and the pool installs it
7
+ * only when the navigated URL's marker matches this lease's id. Must stay self-contained: Playwright
8
+ * serialises the function source into the page.
9
+ */
10
+ export function stampLeaseMarker(arg) {
11
+ const win = globalThis.window;
12
+ if (win === undefined || win.top !== win || win.location.origin !== arg.targetOrigin)
13
+ return;
14
+ try {
15
+ const url = new URL(win.location.href);
16
+ if (url.searchParams.has(arg.sessionParam))
17
+ return;
18
+ url.searchParams.set(arg.sessionParam, arg.session);
19
+ if (arg.project !== undefined && !url.searchParams.has(arg.projectParam)) {
20
+ url.searchParams.set(arg.projectParam, arg.project);
21
+ }
22
+ win.history.replaceState(null, '', url.toString());
23
+ }
24
+ catch {
25
+ return;
26
+ }
27
+ }
28
+ export async function installLeaseMarker(page, leaseId, targetOrigin, project) {
29
+ if (page.addInitScript === undefined || targetOrigin === undefined)
30
+ return;
31
+ await page.addInitScript(stampLeaseMarker, {
32
+ session: leaseId,
33
+ project,
34
+ targetOrigin,
35
+ sessionParam: RETICLE_URL_PARAM.SESSION,
36
+ projectParam: RETICLE_URL_PARAM.PROJECT,
37
+ });
38
+ }
39
+ export function leaseMarkerOf(url) {
40
+ try {
41
+ const params = new URL(url).searchParams;
42
+ const session = params.get(RETICLE_URL_PARAM.SESSION) ?? '';
43
+ const project = params.get(RETICLE_URL_PARAM.PROJECT) ?? '';
44
+ return '' === session ? undefined : { session, project: '' === project ? undefined : project };
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
@@ -7,18 +7,40 @@
7
7
  */
8
8
  import type { Launcher } from './browser-pool.js';
9
9
  import type { ScreenshotOptions } from './pool-contract.js';
10
- /** Reticle's own panel, kept out of a picture of the app: it is ours, not what the app shows. */
11
- export declare const HIDE_RETICLE_CHROME_CSS = "[data-reticle-overlay]{display:none !important}";
12
10
  /**
13
- * How Playwright captures a leased tab. A live picture (JPEG) leaves Reticle's panel out, as the
14
- * visual captures do; a plain PNG capture is unchanged, so no existing baseline moves.
11
+ * Reticle paints its own UI (presenter HUD, glow, annotator marks, tour) into the page. It is
12
+ * time-varying, since the activity log and border state change with every command, so capturing it
13
+ * makes a fresh screenshot of an unchanged page differ from its baseline. Playwright applies `style`
14
+ * for the shot only and then reverts it, so the page under test is never changed. Disabling animations
15
+ * settles any remaining transitions. Shared by every capture path, driven and leased, so both hide
16
+ * the same set: core's `RETICLE_OVERLAY_SELECTOR`.
17
+ */
18
+ export declare const SCREENSHOT_DETERMINISM: {
19
+ readonly style: "[data-reticle-overlay],[data-reticle-cursor],[data-reticle-hud],[data-reticle-glow],[data-reticle-mark],[data-reticle-blocker],[data-reticle-tour]{display:none !important}";
20
+ readonly animations: "disabled";
21
+ };
22
+ /**
23
+ * How Playwright captures a leased tab: a PNG by default, a JPEG for a live picture. Every capture
24
+ * hides Reticle's own UI with `SCREENSHOT_DETERMINISM`, the same as the driven path, so a lease
25
+ * baseline shows the app and not the HUD.
15
26
  */
16
27
  export declare function screenshotOptions(opts: ScreenshotOptions): {
17
28
  fullPage: boolean;
29
+ style?: string;
30
+ animations?: 'disabled';
18
31
  type?: 'jpeg';
19
32
  quality?: number;
20
- style?: string;
33
+ scale?: 'css';
21
34
  };
35
+ /**
36
+ * A step screenshot with Reticle's own UI out of it. The step path injects nothing into the page
37
+ * (no stylesheet, no fast-forwarded animation), so the HUD covered a third of every picture. Only
38
+ * our own hosts change, by their own inline `visibility`, for this one capture, and are put back
39
+ * whatever the capture did: the app's DOM, styles and events are not touched.
40
+ */
41
+ export declare function captureWithChromeHidden(page: {
42
+ evaluate: (script: string) => Promise<unknown>;
43
+ }, capture: () => Promise<Uint8Array>): Promise<Uint8Array>;
22
44
  /**
23
45
  * How a leased tab navigates. Pure, and exported, because the decision in it is worth a test while
24
46
  * the rest of this file needs a real Chromium.
@@ -6,26 +6,60 @@
6
6
  * Headless by default — the pool exists for fault-tolerant headless multi-agent testing.
7
7
  */
8
8
  import { BrowserLaunchKind } from '@reticlehq/core/telemetry';
9
+ import { HIDE_RETICLE_CHROME_CSS, RETICLE_OVERLAY_SELECTOR } from '@reticlehq/core';
9
10
  import { launchChromium } from '../../launch-chromium.js';
10
11
  import { getSessionMetrics } from '../../telemetry/session-metrics.js';
11
12
  import { classifyConnectFailure } from '../../telemetry/connect-failure.js';
12
13
  import { chromiumInstallCommand, chromiumInstallDepsCommand, bundledPlaywrightVersion, } from '../../command/cli/doctor/browser/chromium-hint.js';
13
14
  import { installNetworkMocks } from '../input/network-mock.js';
14
- /** Reticle's own panel, kept out of a picture of the app: it is ours, not what the app shows. */
15
- export const HIDE_RETICLE_CHROME_CSS = '[data-reticle-overlay]{display:none !important}';
16
15
  /**
17
- * How Playwright captures a leased tab. A live picture (JPEG) leaves Reticle's panel out, as the
18
- * visual captures do; a plain PNG capture is unchanged, so no existing baseline moves.
16
+ * Reticle paints its own UI (presenter HUD, glow, annotator marks, tour) into the page. It is
17
+ * time-varying, since the activity log and border state change with every command, so capturing it
18
+ * makes a fresh screenshot of an unchanged page differ from its baseline. Playwright applies `style`
19
+ * for the shot only and then reverts it, so the page under test is never changed. Disabling animations
20
+ * settles any remaining transitions. Shared by every capture path, driven and leased, so both hide
21
+ * the same set: core's `RETICLE_OVERLAY_SELECTOR`.
22
+ */
23
+ export const SCREENSHOT_DETERMINISM = {
24
+ style: HIDE_RETICLE_CHROME_CSS,
25
+ animations: 'disabled',
26
+ };
27
+ /**
28
+ * How Playwright captures a leased tab: a PNG by default, a JPEG for a live picture. Every capture
29
+ * hides Reticle's own UI with `SCREENSHOT_DETERMINISM`, the same as the driven path, so a lease
30
+ * baseline shows the app and not the HUD.
19
31
  */
20
32
  export function screenshotOptions(opts) {
33
+ // A step screenshot is evidence about the page, so it must not change it: `animations: disabled`
34
+ // fast-forwards running animations to their end and fires their events in the app under test.
35
+ if (true === opts.cssScale && opts.jpegQuality !== undefined) {
36
+ return { fullPage: false, type: 'jpeg', quality: opts.jpegQuality, scale: 'css' };
37
+ }
38
+ const base = { ...SCREENSHOT_DETERMINISM, fullPage: true === opts.fullPage };
21
39
  return opts.jpegQuality === undefined
22
- ? { fullPage: true === opts.fullPage }
23
- : {
24
- fullPage: true === opts.fullPage,
25
- type: 'jpeg',
26
- quality: opts.jpegQuality,
27
- style: HIDE_RETICLE_CHROME_CSS,
28
- };
40
+ ? base
41
+ : { ...base, type: 'jpeg', quality: opts.jpegQuality };
42
+ }
43
+ /** Where the hidden hosts' own visibility waits to be put back, on the page's window. */
44
+ const SHOT_HIDDEN_KEY = '__reticleShotHidden';
45
+ /** A string literal safe to splice into a script: JSON plus the characters that end one early. */
46
+ const scriptLiteral = (value) => JSON.stringify(value).replace(/[<>/\u2028\u2029]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
47
+ const HIDE_CHROME_SCRIPT = `(() => { const held = []; for (const el of document.querySelectorAll(${scriptLiteral(RETICLE_OVERLAY_SELECTOR)})) { held.push([el, el.style.visibility]); el.style.visibility = 'hidden'; } window.${SHOT_HIDDEN_KEY} = held; })()`;
48
+ const RESTORE_CHROME_SCRIPT = `(() => { for (const [el, was] of window.${SHOT_HIDDEN_KEY} ?? []) el.style.visibility = was; delete window.${SHOT_HIDDEN_KEY}; })()`;
49
+ /**
50
+ * A step screenshot with Reticle's own UI out of it. The step path injects nothing into the page
51
+ * (no stylesheet, no fast-forwarded animation), so the HUD covered a third of every picture. Only
52
+ * our own hosts change, by their own inline `visibility`, for this one capture, and are put back
53
+ * whatever the capture did: the app's DOM, styles and events are not touched.
54
+ */
55
+ export async function captureWithChromeHidden(page, capture) {
56
+ await page.evaluate(HIDE_CHROME_SCRIPT);
57
+ try {
58
+ return await capture();
59
+ }
60
+ finally {
61
+ await page.evaluate(RESTORE_CHROME_SCRIPT).catch(() => undefined);
62
+ }
29
63
  }
30
64
  /**
31
65
  * How a leased tab navigates. Pure, and exported, because the decision in it is worth a test while
@@ -49,8 +83,8 @@ export function gotoOptions(timeoutMs) {
49
83
  function wrapBrowser(browser) {
50
84
  return {
51
85
  isConnected: () => browser.isConnected(),
52
- newContext: async () => {
53
- const context = await browser.newContext();
86
+ newContext: async (opts) => {
87
+ const context = await browser.newContext(true === opts?.ignoreHTTPSErrors ? { ignoreHTTPSErrors: true } : undefined);
54
88
  return {
55
89
  newPage: async () => {
56
90
  const page = await context.newPage();
@@ -59,7 +93,15 @@ function wrapBrowser(browser) {
59
93
  close: () => page.close(),
60
94
  evaluate: (script) => page.evaluate(script),
61
95
  // Playwright returns a Buffer; Uint8Array is what the visual store and differ take.
62
- screenshot: async (opts) => new Uint8Array(await page.screenshot(screenshotOptions(opts ?? {}))),
96
+ // Same determinism as the driven path's capturePage: without it a lease baseline caught
97
+ // the HUD, its activity log and the toolbar, and a HUD change read as a regression (#1355).
98
+ screenshot: async (opts) => {
99
+ const shoot = async () => new Uint8Array(await page.screenshot(screenshotOptions(opts ?? {})));
100
+ // A step capture injects no stylesheet, so our own hosts are hidden another way.
101
+ return true === opts?.cssScale
102
+ ? captureWithChromeHidden({ evaluate: (script) => page.evaluate(script) }, shoot)
103
+ : shoot();
104
+ },
63
105
  // Three moves, same as performGesture: a single move to the center can be a no-op if
64
106
  // the pointer was already there, and CSS :hover needs a native hit-test to apply.
65
107
  hover: async (x, y) => {
@@ -69,6 +111,7 @@ function wrapBrowser(browser) {
69
111
  },
70
112
  installMocks: (rules) => installNetworkMocks(page, [...rules]),
71
113
  setViewport: (size) => page.setViewportSize(size),
114
+ bringToFront: () => page.bringToFront(),
72
115
  onCrash: (handler) => page.on('crash', handler),
73
116
  onConsole: (handler) => page.on('console', (msg) => handler(msg.text())),
74
117
  onDialog: (handler) => page.on('dialog', (dialog) => handler({ message: dialog.message(), dismiss: () => dialog.dismiss() })),
@@ -83,6 +126,8 @@ function wrapBrowser(browser) {
83
126
  };
84
127
  },
85
128
  addCookies: (cookies) => context.addCookies(cookies),
129
+ grantPermissions: (permissions, opts) => context.grantPermissions(permissions, opts),
130
+ clearPermissions: () => context.clearPermissions(),
86
131
  close: () => context.close(),
87
132
  };
88
133
  },
@@ -64,6 +64,11 @@ export interface PooledPage {
64
64
  * existed short of restarting the daemon), because nothing in the stack ever answered it.
65
65
  */
66
66
  onDialog?(handler: (dialog: PooledDialog) => void): void;
67
+ /**
68
+ * Make this the visible tab. OPTIONAL, like `onDialog`: a page opened beside others can start
69
+ * hidden, and a hidden tab throttles timers and rAF so nothing on it verifies (#1351).
70
+ */
71
+ bringToFront?(): Promise<void>;
67
72
  }
68
73
  /** A native dialog the page opened, handed to the pool so it can be dismissed instead of left blocking. */
69
74
  export interface PooledDialog {
@@ -103,11 +108,24 @@ export interface PooledContext {
103
108
  newPage(): Promise<PooledPage>;
104
109
  close(): Promise<void>;
105
110
  addCookies?(cookies: PooledCookie[]): Promise<void>;
111
+ /**
112
+ * Grant browser permissions on this context. OPTIONAL, like `addCookies`: a context that cannot
113
+ * grant makes a lease that asked for permissions refuse, rather than open with none granted while
114
+ * the caller believes otherwise.
115
+ */
116
+ grantPermissions?(permissions: string[], opts?: {
117
+ origin?: string;
118
+ }): Promise<void>;
119
+ /** Drop every permission granted on this context. OPTIONAL, for the same reason. */
120
+ clearPermissions?(): Promise<void>;
106
121
  }
107
122
  /** The launched browser. Real Playwright `Browser` satisfies this. */
108
123
  export interface PooledBrowser {
109
124
  isConnected(): boolean;
110
- newContext(): Promise<PooledContext>;
125
+ /** `ignoreHTTPSErrors` accepts a self-signed or local-CA certificate for this context only. */
126
+ newContext(opts?: {
127
+ ignoreHTTPSErrors?: boolean;
128
+ }): Promise<PooledContext>;
111
129
  close(): Promise<void>;
112
130
  /** Fires when the browser process dies/crashes so the pool can relaunch on the next acquire. */
113
131
  onDisconnected(handler: () => void): void;
@@ -118,4 +136,6 @@ export type Launcher = () => Promise<PooledBrowser>;
118
136
  export interface ScreenshotOptions {
119
137
  fullPage?: boolean;
120
138
  jpegQuality?: number;
139
+ /** One image pixel per CSS pixel, so a high-density display does not double a step screenshot. */
140
+ cssScale?: boolean;
121
141
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * What the HUD shows about the coding agent: who is attached, and this tab's latest notes to it with
3
+ * whether an agent's tool call has taken each one. Read from the session's own inbox history, so
4
+ * "Seen" is shown only for a note that was actually handed to an agent.
5
+ */
6
+ import { type AgentLink } from '@reticlehq/core';
7
+ import type { InboxMessage } from './human/live-control.js';
8
+ export declare function agentLinkOf(history: readonly InboxMessage[]): AgentLink;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * What the HUD shows about the coding agent: who is attached, and this tab's latest notes to it with
3
+ * whether an agent's tool call has taken each one. Read from the session's own inbox history, so
4
+ * "Seen" is shown only for a note that was actually handed to an agent.
5
+ */
6
+ import { AGENT_NOTE_MAX, AGENT_NOTES_SHOWN } from '@reticlehq/core';
7
+ import { connectedAgents } from '../../hooks/coding-agents.js';
8
+ export function agentLinkOf(history) {
9
+ return {
10
+ agents: connectedAgents(),
11
+ notes: history.slice(-AGENT_NOTES_SHOWN).map((message) => ({
12
+ text: message.text.slice(0, AGENT_NOTE_MAX),
13
+ seen: true === message.seen,
14
+ ...(message.by === undefined ? {} : { by: message.by }),
15
+ })),
16
+ };
17
+ }
@@ -1,5 +1,5 @@
1
1
  import { CommandActor, MessageKind } from '@reticlehq/core';
2
- import { currentDrivenBy } from '../../hooks/driven-by.js';
2
+ import { currentDrivenBy, harnessOutwardAllowed } from '../../hooks/driven-by.js';
3
3
  /**
4
4
  * The command a session sends its page, as wire JSON.
5
5
  *
@@ -15,5 +15,10 @@ export function commandPayload(id, sessionId, name, args) {
15
15
  name,
16
16
  args,
17
17
  ...(currentDrivenBy() === undefined ? {} : { by: CommandActor.HARNESS }),
18
+ // The page presses no outward control (invite, send, delete, pay…) the journey did not ask for.
19
+ ...outwardField(harnessOutwardAllowed()),
18
20
  });
19
21
  }
22
+ function outwardField(allowed) {
23
+ return allowed === undefined ? {} : { outward: { allowed } };
24
+ }
@@ -1,5 +1,4 @@
1
1
  import { log } from '../../log.js';
2
- import { bindSpanContext } from '../../trace.js';
3
2
  /**
4
3
  * What the daemon answers when the rules that decide a verdict ask it for something.
5
4
  *
@@ -15,6 +14,7 @@ import { bindSpanContext } from '../../trace.js';
15
14
  export declare const noteToDaemonLog: typeof log;
16
15
  /**
17
16
  * Keep a callback belonging to the call that created it, so a re-check scheduled for later still
18
- * traces back to the wait that asked for it instead of looking like work starting from nowhere.
17
+ * traces back to the wait that asked for it instead of looking like work starting from nowhere, and
18
+ * is still the Harness's when the Harness made the call: the HUD files it by who drove it.
19
19
  */
20
- export declare const keepCallerContextInDaemon: typeof bindSpanContext;
20
+ export declare const keepCallerContextInDaemon: <A extends unknown[]>(fn: (...args: A) => void) => ((...args: A) => void);
@@ -1,5 +1,6 @@
1
1
  import { log } from '../../log.js';
2
2
  import { bindSpanContext } from '../../trace.js';
3
+ import { bindDrivenBy } from '../../hooks/driven-by.js';
3
4
  /**
4
5
  * What the daemon answers when the rules that decide a verdict ask it for something.
5
6
  *
@@ -15,6 +16,7 @@ import { bindSpanContext } from '../../trace.js';
15
16
  export const noteToDaemonLog = log;
16
17
  /**
17
18
  * Keep a callback belonging to the call that created it, so a re-check scheduled for later still
18
- * traces back to the wait that asked for it instead of looking like work starting from nowhere.
19
+ * traces back to the wait that asked for it instead of looking like work starting from nowhere, and
20
+ * is still the Harness's when the Harness made the call: the HUD files it by who drove it.
19
21
  */
20
- export const keepCallerContextInDaemon = bindSpanContext;
22
+ export const keepCallerContextInDaemon = (fn) => bindDrivenBy(bindSpanContext(fn));
@@ -36,3 +36,12 @@ export declare function detectDevCommand(directory: string, read?: (path: string
36
36
  * package manager, because a workspace package usually has no lockfile of its own.
37
37
  */
38
38
  export declare function detectDevCommandInProject(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[]): DevCommand | undefined;
39
+ /**
40
+ * The command that wires THIS project for good: `init`, in the app's own folder, through the
41
+ * one-off runner the project's package manager ships.
42
+ *
43
+ * Handed to an agent whose install never ran `init` (an MCP-only route), so it has to be right first
44
+ * time: `init` run in a folder that is not the app stops on a missing package.json, and a runner the
45
+ * machine does not have is "command not found". npx whenever there is doubt — it ships with Node.
46
+ */
47
+ export declare function initCommandIn(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[]): string;