@poolzin/pool-bot 2026.2.24 → 2026.2.26

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 (646) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/acp/client.js +207 -18
  3. package/dist/acp/event-mapper.js +87 -22
  4. package/dist/acp/meta.js +12 -6
  5. package/dist/acp/secret-file.js +22 -0
  6. package/dist/agents/agent-paths.js +8 -9
  7. package/dist/agents/agent-scope.js +17 -5
  8. package/dist/agents/auth-profiles/oauth.js +148 -64
  9. package/dist/agents/auth-profiles/session-override.js +13 -7
  10. package/dist/agents/bash-process-registry.test-helpers.js +29 -0
  11. package/dist/agents/bash-tools.exec-approval-request.js +20 -0
  12. package/dist/agents/bash-tools.exec-host-gateway.js +240 -0
  13. package/dist/agents/bash-tools.exec-host-node.js +235 -0
  14. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  15. package/dist/agents/bash-tools.exec-types.js +1 -0
  16. package/dist/agents/bash-tools.process.js +224 -218
  17. package/dist/agents/bedrock-discovery.js +3 -1
  18. package/dist/agents/byteplus-models.js +97 -0
  19. package/dist/agents/chutes-oauth.js +1 -0
  20. package/dist/agents/cli-runner/helpers.js +4 -0
  21. package/dist/agents/compaction.js +41 -14
  22. package/dist/agents/content-blocks.js +16 -0
  23. package/dist/agents/doubao-models.js +121 -0
  24. package/dist/agents/failover-error.js +2 -0
  25. package/dist/agents/huggingface-models.js +5 -3
  26. package/dist/agents/live-model-filter.js +5 -0
  27. package/dist/agents/minimax-vlm.js +10 -8
  28. package/dist/agents/model-auth.js +6 -0
  29. package/dist/agents/model-catalog.js +3 -1
  30. package/dist/agents/model-fallback.js +96 -101
  31. package/dist/agents/model-selection.js +7 -1
  32. package/dist/agents/models-config.providers.js +364 -165
  33. package/dist/agents/ollama-stream.js +117 -4
  34. package/dist/agents/opencode-zen-models.js +22 -11
  35. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  36. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  37. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  38. package/dist/agents/pi-embedded-helpers.js +1 -1
  39. package/dist/agents/pi-embedded-payloads.js +1 -0
  40. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  41. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  42. package/dist/agents/pi-embedded-runner/google.js +20 -8
  43. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  44. package/dist/agents/pi-embedded-runner/run.js +71 -12
  45. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
  46. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  47. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  48. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  49. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  50. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  51. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  52. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  53. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  54. package/dist/agents/pi-embedded-subscribe.js +9 -4
  55. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  56. package/dist/agents/pi-embedded-utils.js +3 -0
  57. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  58. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  59. package/dist/agents/pi-settings.js +40 -0
  60. package/dist/agents/pi-tools.policy.js +2 -1
  61. package/dist/agents/provider/config-loader.js +1 -1
  62. package/dist/agents/sandbox/browser.js +170 -33
  63. package/dist/agents/sandbox/config-hash.js +14 -27
  64. package/dist/agents/sandbox/config.js +21 -2
  65. package/dist/agents/sandbox/constants.js +2 -0
  66. package/dist/agents/sandbox/docker.js +16 -2
  67. package/dist/agents/sandbox/novnc-auth.js +62 -0
  68. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  69. package/dist/agents/sandbox/shared.js +10 -6
  70. package/dist/agents/sandbox-paths.js +24 -11
  71. package/dist/agents/schema/clean-for-gemini.js +132 -85
  72. package/dist/agents/session-slug.js +10 -5
  73. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  74. package/dist/agents/session-tool-result-guard.js +3 -1
  75. package/dist/agents/session-transcript-repair.js +40 -6
  76. package/dist/agents/skills/bundled-dir.js +19 -5
  77. package/dist/agents/skills/env-overrides.js +124 -43
  78. package/dist/agents/skills/frontmatter.js +6 -6
  79. package/dist/agents/skills/plugin-skills.js +14 -7
  80. package/dist/agents/skills/workspace.js +1 -0
  81. package/dist/agents/skills.test-helpers.js +13 -0
  82. package/dist/agents/stable-stringify.js +12 -0
  83. package/dist/agents/subagent-announce.js +251 -49
  84. package/dist/agents/subagent-lifecycle-events.js +19 -0
  85. package/dist/agents/subagent-registry-cleanup.js +31 -0
  86. package/dist/agents/subagent-registry-completion.js +68 -0
  87. package/dist/agents/subagent-registry-queries.js +117 -0
  88. package/dist/agents/subagent-registry-state.js +46 -0
  89. package/dist/agents/subagent-registry.js +252 -221
  90. package/dist/agents/subagent-registry.mocks.shared.js +12 -0
  91. package/dist/agents/subagent-registry.store.js +1 -0
  92. package/dist/agents/subagent-registry.types.js +1 -0
  93. package/dist/agents/subagent-spawn.js +195 -7
  94. package/dist/agents/system-prompt.js +22 -6
  95. package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
  96. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  97. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  98. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
  99. package/dist/agents/timeout.js +18 -6
  100. package/dist/agents/tool-call-id.js +1 -1
  101. package/dist/agents/tool-display-common.js +162 -29
  102. package/dist/agents/tool-images.js +82 -9
  103. package/dist/agents/tool-policy-shared.js +108 -0
  104. package/dist/agents/tool-policy.js +51 -26
  105. package/dist/agents/tools/browser-tool.js +160 -54
  106. package/dist/agents/tools/canvas-tool.js +27 -1
  107. package/dist/agents/tools/common.js +45 -0
  108. package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
  109. package/dist/agents/tools/discord-actions-guild.js +4 -1
  110. package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
  111. package/dist/agents/tools/gateway-tool.js +3 -1
  112. package/dist/agents/tools/image-tool.js +214 -99
  113. package/dist/agents/tools/nodes-utils.js +1 -10
  114. package/dist/agents/tools/sessions-history-tool.js +140 -108
  115. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  116. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  117. package/dist/agents/tools/subagents-tool.js +2 -1
  118. package/dist/agents/tools/whatsapp-actions.js +10 -2
  119. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  120. package/dist/agents/transcript-policy.js +22 -8
  121. package/dist/agents/venice-models.js +11 -3
  122. package/dist/agents/workspace.js +222 -46
  123. package/dist/auto-reply/commands-registry.data.js +51 -0
  124. package/dist/auto-reply/commands-registry.js +19 -21
  125. package/dist/auto-reply/fallback-state.js +114 -0
  126. package/dist/auto-reply/group-activation.js +10 -5
  127. package/dist/auto-reply/inbound-debounce.js +10 -5
  128. package/dist/auto-reply/model-runtime.js +68 -0
  129. package/dist/auto-reply/reply/abort.js +1 -1
  130. package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
  131. package/dist/auto-reply/reply/agent-runner.js +165 -39
  132. package/dist/auto-reply/reply/bash-command.js +41 -39
  133. package/dist/auto-reply/reply/command-gates.js +25 -0
  134. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  135. package/dist/auto-reply/reply/commands-bash.js +6 -5
  136. package/dist/auto-reply/reply/commands-config.js +30 -28
  137. package/dist/auto-reply/reply/commands-core.js +2 -1
  138. package/dist/auto-reply/reply/commands-info.js +1 -0
  139. package/dist/auto-reply/reply/commands-models.js +65 -14
  140. package/dist/auto-reply/reply/commands-session.js +237 -82
  141. package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
  142. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  143. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  144. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  145. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  146. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  147. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  148. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  149. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  150. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  151. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  152. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  153. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  154. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  155. package/dist/auto-reply/reply/commands-tts.js +10 -5
  156. package/dist/auto-reply/reply/config-value.js +10 -5
  157. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  158. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  159. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  160. package/dist/auto-reply/reply/followup-runner.js +1 -0
  161. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  162. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  163. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  164. package/dist/auto-reply/reply/get-reply.js +71 -12
  165. package/dist/auto-reply/reply/model-selection.js +80 -39
  166. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  167. package/dist/auto-reply/reply/queue/state.js +13 -12
  168. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  169. package/dist/auto-reply/reply/reply-reference.js +9 -8
  170. package/dist/auto-reply/reply/route-reply.js +15 -8
  171. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  172. package/dist/auto-reply/reply/session.js +22 -6
  173. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  174. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  175. package/dist/auto-reply/reply/typing.js +46 -21
  176. package/dist/auto-reply/send-policy.js +14 -7
  177. package/dist/auto-reply/status.js +140 -16
  178. package/dist/auto-reply/templating.js +10 -5
  179. package/dist/auto-reply/thinking.js +7 -16
  180. package/dist/auto-reply/tokens.js +21 -5
  181. package/dist/browser/bridge-server.js +36 -20
  182. package/dist/browser/cdp.helpers.js +7 -14
  183. package/dist/browser/cdp.js +35 -15
  184. package/dist/browser/chrome.profile-decoration.js +7 -4
  185. package/dist/browser/config.js +30 -0
  186. package/dist/browser/extension-relay-auth.js +55 -0
  187. package/dist/browser/extension-relay.js +74 -29
  188. package/dist/browser/navigation-guard.js +39 -0
  189. package/dist/browser/paths.js +77 -0
  190. package/dist/browser/profiles.js +13 -8
  191. package/dist/browser/pw-ai-module.js +10 -5
  192. package/dist/browser/pw-session.js +76 -39
  193. package/dist/browser/pw-tools-core.interactions.js +14 -7
  194. package/dist/browser/pw-tools-core.state.js +12 -6
  195. package/dist/browser/routes/agent.act.js +431 -424
  196. package/dist/browser/routes/agent.shared.js +47 -3
  197. package/dist/browser/routes/agent.snapshot.js +122 -116
  198. package/dist/browser/routes/agent.storage.js +303 -297
  199. package/dist/browser/routes/tabs.js +154 -100
  200. package/dist/browser/server-context.js +7 -0
  201. package/dist/browser/server-lifecycle.js +37 -0
  202. package/dist/build-info.json +3 -3
  203. package/dist/channels/allow-from.js +26 -0
  204. package/dist/channels/allowlists/resolve-utils.js +43 -19
  205. package/dist/channels/channel-config.js +14 -7
  206. package/dist/channels/draft-stream-loop.js +7 -0
  207. package/dist/channels/model-overrides.js +82 -0
  208. package/dist/channels/plugins/account-action-gate.js +13 -0
  209. package/dist/channels/plugins/message-actions.js +10 -0
  210. package/dist/channels/plugins/normalize/imessage.js +14 -7
  211. package/dist/channels/plugins/normalize/slack.js +10 -5
  212. package/dist/channels/plugins/normalize/telegram.js +14 -7
  213. package/dist/channels/plugins/outbound/discord.js +80 -8
  214. package/dist/channels/plugins/outbound/signal.js +11 -11
  215. package/dist/channels/plugins/setup-helpers.js +10 -5
  216. package/dist/channels/sender-label.js +14 -7
  217. package/dist/channels/session.js +4 -2
  218. package/dist/channels/status-reactions.js +297 -0
  219. package/dist/channels/telegram/api.js +18 -0
  220. package/dist/cli/argv.js +84 -21
  221. package/dist/cli/banner.js +3 -2
  222. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  223. package/dist/cli/cli-name.js +11 -11
  224. package/dist/cli/cli-utils.js +13 -3
  225. package/dist/cli/command-format.js +1 -1
  226. package/dist/cli/config-cli.js +1 -1
  227. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  228. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  229. package/dist/cli/daemon-cli/restart-health.js +126 -0
  230. package/dist/cli/daemon-cli/status.gather.js +9 -13
  231. package/dist/cli/daemon-cli/status.print.js +2 -10
  232. package/dist/cli/deps.js +27 -22
  233. package/dist/cli/exec-approvals-cli.js +92 -124
  234. package/dist/cli/gateway-cli/run-loop.js +23 -5
  235. package/dist/cli/memory-cli.js +158 -61
  236. package/dist/cli/node-cli/register.js +14 -5
  237. package/dist/cli/nodes-cli/register.push.js +63 -0
  238. package/dist/cli/nodes-media-utils.js +26 -0
  239. package/dist/cli/outbound-send-deps.js +2 -9
  240. package/dist/cli/outbound-send-mapping.js +11 -0
  241. package/dist/cli/pairing-cli.js +40 -14
  242. package/dist/cli/plugins-cli.js +250 -73
  243. package/dist/cli/ports.js +11 -10
  244. package/dist/cli/program/build-program.js +3 -1
  245. package/dist/cli/program/command-registry.js +214 -136
  246. package/dist/cli/program/command-tree.js +16 -0
  247. package/dist/cli/program/help.js +43 -12
  248. package/dist/cli/program/preaction.js +13 -9
  249. package/dist/cli/program/register.configure.js +3 -18
  250. package/dist/cli/program/register.maintenance.js +2 -2
  251. package/dist/cli/program/register.onboard.js +2 -0
  252. package/dist/cli/program/register.status-health-sessions.js +16 -17
  253. package/dist/cli/program/register.subclis.js +93 -52
  254. package/dist/cli/route.js +12 -8
  255. package/dist/cli/system-cli.js +36 -46
  256. package/dist/cli/test-runtime-capture.js +24 -0
  257. package/dist/cli/update-cli/shared.js +22 -9
  258. package/dist/cli/update-cli/update-command.js +89 -14
  259. package/dist/cli/update-cli/wizard.js +6 -12
  260. package/dist/commands/agent/run-context.js +18 -5
  261. package/dist/commands/agent/session-store.js +17 -4
  262. package/dist/commands/agent.js +185 -89
  263. package/dist/commands/agents.bindings.js +14 -7
  264. package/dist/commands/agents.commands.add.js +13 -9
  265. package/dist/commands/agents.commands.identity.js +12 -6
  266. package/dist/commands/agents.commands.list.js +11 -6
  267. package/dist/commands/agents.config.js +8 -10
  268. package/dist/commands/agents.providers.js +12 -6
  269. package/dist/commands/auth-choice-options.js +103 -75
  270. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  271. package/dist/commands/auth-choice.apply.js +4 -0
  272. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  273. package/dist/commands/auth-choice.apply.openai.js +3 -1
  274. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  275. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  276. package/dist/commands/channels/remove.js +13 -6
  277. package/dist/commands/channels/shared.js +4 -14
  278. package/dist/commands/channels.mock-harness.js +23 -0
  279. package/dist/commands/configure.commands.js +14 -0
  280. package/dist/commands/configure.gateway.js +2 -4
  281. package/dist/commands/configure.js +1 -1
  282. package/dist/commands/configure.shared.js +11 -0
  283. package/dist/commands/daemon-install-helpers.js +2 -2
  284. package/dist/commands/daemon-install-runtime-warning.js +11 -0
  285. package/dist/commands/dashboard.js +12 -10
  286. package/dist/commands/docs.js +14 -8
  287. package/dist/commands/doctor-config-flow.js +11 -9
  288. package/dist/commands/doctor-legacy-config.js +281 -0
  289. package/dist/commands/doctor-state-integrity.js +99 -23
  290. package/dist/commands/doctor-update.js +12 -9
  291. package/dist/commands/models/list.list-command.js +7 -5
  292. package/dist/commands/models/set-image.js +2 -21
  293. package/dist/commands/node-daemon-install-helpers.js +10 -8
  294. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  295. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  296. package/dist/commands/onboard-auth.credentials.js +90 -13
  297. package/dist/commands/onboard-auth.js +1 -1
  298. package/dist/commands/onboard-auth.models.js +6 -5
  299. package/dist/commands/onboard-hooks.js +1 -1
  300. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  301. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  302. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  303. package/dist/commands/onboard-remote.js +14 -7
  304. package/dist/commands/onboard.js +11 -13
  305. package/dist/commands/sandbox-display.js +6 -5
  306. package/dist/commands/sessions.test-helpers.js +61 -0
  307. package/dist/commands/status-all/diagnosis.js +14 -10
  308. package/dist/commands/status-all/format.js +1 -0
  309. package/dist/commands/status.gateway-probe.js +1 -16
  310. package/dist/commands/systemd-linger.js +12 -6
  311. package/dist/config/agent-limits.js +2 -0
  312. package/dist/config/commands.js +32 -15
  313. package/dist/config/config-paths.js +9 -11
  314. package/dist/config/config.js +1 -1
  315. package/dist/config/defaults.js +22 -2
  316. package/dist/config/discord-preview-streaming.js +104 -0
  317. package/dist/config/env-substitution.js +62 -34
  318. package/dist/config/env-vars.js +45 -7
  319. package/dist/config/includes.js +4 -0
  320. package/dist/config/io.js +656 -171
  321. package/dist/config/legacy.migrations.part-1.js +189 -78
  322. package/dist/config/legacy.shared.js +3 -1
  323. package/dist/config/merge-patch.js +54 -4
  324. package/dist/config/prototype-keys.js +4 -0
  325. package/dist/config/redact-snapshot.js +404 -76
  326. package/dist/config/schema.help.js +44 -7
  327. package/dist/config/schema.js +58 -570
  328. package/dist/config/schema.labels.js +38 -6
  329. package/dist/config/sessions/delivery-info.js +10 -3
  330. package/dist/config/sessions/main-session.js +10 -5
  331. package/dist/config/sessions/session-file.js +33 -0
  332. package/dist/config/sessions/session-key.js +10 -5
  333. package/dist/config/sessions/store.js +1 -1
  334. package/dist/config/sessions.js +1 -0
  335. package/dist/config/validation.js +140 -85
  336. package/dist/config/zod-schema.agent-runtime.js +11 -0
  337. package/dist/config/zod-schema.hooks.js +40 -11
  338. package/dist/config/zod-schema.installs.js +20 -0
  339. package/dist/config/zod-schema.js +156 -20
  340. package/dist/config/zod-schema.providers-core.js +78 -4
  341. package/dist/config/zod-schema.providers.js +6 -1
  342. package/dist/config/zod-schema.session.js +41 -2
  343. package/dist/cron/run-log.js +3 -0
  344. package/dist/cron/schedule.js +21 -10
  345. package/dist/cron/service/ops.js +35 -21
  346. package/dist/cron/service/timer.js +116 -16
  347. package/dist/cron/stagger.js +3 -1
  348. package/dist/daemon/cmd-argv.js +21 -0
  349. package/dist/daemon/cmd-set.js +58 -0
  350. package/dist/daemon/service-types.js +1 -0
  351. package/dist/discord/api.js +12 -6
  352. package/dist/discord/draft-chunking.js +22 -0
  353. package/dist/discord/draft-stream.js +124 -0
  354. package/dist/discord/monitor/agent-components.js +1 -1
  355. package/dist/discord/monitor/commands.js +5 -0
  356. package/dist/discord/monitor/exec-approvals.js +357 -162
  357. package/dist/discord/monitor/gateway-plugin.js +2 -1
  358. package/dist/discord/monitor/listeners.js +37 -27
  359. package/dist/discord/monitor/message-handler.js +4 -1
  360. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  361. package/dist/discord/monitor/message-handler.process.js +246 -217
  362. package/dist/discord/monitor/message-utils.js +143 -6
  363. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  364. package/dist/discord/monitor/model-picker.js +651 -0
  365. package/dist/discord/monitor/native-command.js +573 -16
  366. package/dist/discord/monitor/provider.allowlist.js +223 -0
  367. package/dist/discord/monitor/provider.js +275 -347
  368. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  369. package/dist/discord/monitor/reply-delivery.js +123 -16
  370. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  371. package/dist/discord/monitor/thread-bindings.js +4 -0
  372. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  373. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  374. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  375. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  376. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  377. package/dist/discord/resolve-users.js +33 -21
  378. package/dist/discord/send.channels.js +15 -0
  379. package/dist/discord/send.js +3 -2
  380. package/dist/discord/send.outbound.js +82 -26
  381. package/dist/discord/send.permissions.js +83 -30
  382. package/dist/discord/send.reactions.js +8 -4
  383. package/dist/discord/token.js +10 -5
  384. package/dist/discord/voice/command.js +263 -0
  385. package/dist/discord/voice/manager.js +531 -0
  386. package/dist/gateway/auth.js +72 -13
  387. package/dist/gateway/call.js +152 -83
  388. package/dist/gateway/canvas-capability.js +75 -0
  389. package/dist/gateway/client.js +28 -4
  390. package/dist/gateway/config-reload.js +3 -4
  391. package/dist/gateway/control-plane-audit.js +28 -0
  392. package/dist/gateway/control-plane-rate-limit.js +53 -0
  393. package/dist/gateway/control-ui.js +219 -96
  394. package/dist/gateway/events.js +1 -0
  395. package/dist/gateway/hooks-mapping.js +88 -38
  396. package/dist/gateway/hooks.js +109 -54
  397. package/dist/gateway/http-auth-helpers.js +3 -2
  398. package/dist/gateway/http-common.js +22 -0
  399. package/dist/gateway/http-endpoint-helpers.js +1 -0
  400. package/dist/gateway/method-scopes.js +169 -0
  401. package/dist/gateway/net.js +74 -9
  402. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  403. package/dist/gateway/node-registry.js +10 -5
  404. package/dist/gateway/openai-http.js +1 -0
  405. package/dist/gateway/openresponses-http.js +121 -110
  406. package/dist/gateway/origin-check.js +1 -18
  407. package/dist/gateway/probe-auth.js +2 -0
  408. package/dist/gateway/protocol/index.js +4 -2
  409. package/dist/gateway/protocol/schema/cron.js +1 -0
  410. package/dist/gateway/protocol/schema/devices.js +1 -0
  411. package/dist/gateway/protocol/schema/protocol-schemas.js +4 -1
  412. package/dist/gateway/protocol/schema/push.js +18 -0
  413. package/dist/gateway/protocol/schema/sessions.js +6 -0
  414. package/dist/gateway/protocol/schema.js +1 -0
  415. package/dist/gateway/role-policy.js +17 -0
  416. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  417. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  418. package/dist/gateway/server-chat.js +83 -25
  419. package/dist/gateway/server-constants.js +10 -9
  420. package/dist/gateway/server-cron.js +1 -0
  421. package/dist/gateway/server-http.js +247 -54
  422. package/dist/gateway/server-maintenance.js +20 -5
  423. package/dist/gateway/server-methods/agent.js +162 -24
  424. package/dist/gateway/server-methods/chat.js +465 -130
  425. package/dist/gateway/server-methods/config.js +193 -152
  426. package/dist/gateway/server-methods/devices.js +17 -3
  427. package/dist/gateway/server-methods/models.js +11 -1
  428. package/dist/gateway/server-methods/nodes.helpers.js +12 -0
  429. package/dist/gateway/server-methods/nodes.js +251 -69
  430. package/dist/gateway/server-methods/push.js +53 -0
  431. package/dist/gateway/server-methods/sessions.js +64 -8
  432. package/dist/gateway/server-methods/usage.js +162 -75
  433. package/dist/gateway/server-node-events.js +29 -0
  434. package/dist/gateway/server-reload-handlers.js +2 -3
  435. package/dist/gateway/server-runtime-config.js +39 -13
  436. package/dist/gateway/server-runtime-state.js +2 -0
  437. package/dist/gateway/server-startup-memory.js +17 -11
  438. package/dist/gateway/server-ws-runtime.js +1 -0
  439. package/dist/gateway/server.impl.js +296 -139
  440. package/dist/gateway/session-preview.test-helpers.js +11 -0
  441. package/dist/gateway/session-utils.fs.js +32 -34
  442. package/dist/gateway/sessions-resolve.js +17 -5
  443. package/dist/gateway/startup-auth.js +126 -0
  444. package/dist/gateway/test-helpers.agent-results.js +15 -0
  445. package/dist/gateway/test-helpers.mocks.js +37 -14
  446. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  447. package/dist/gateway/test-helpers.server.js +161 -77
  448. package/dist/gateway/tools-invoke-http.js +21 -10
  449. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  450. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  451. package/dist/hooks/bundled/session-memory/handler.js +170 -38
  452. package/dist/hooks/frontmatter.js +6 -6
  453. package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
  454. package/dist/hooks/gmail-watcher.js +11 -6
  455. package/dist/hooks/internal-hooks.js +11 -1
  456. package/dist/hooks/llm-slug-generator.js +4 -1
  457. package/dist/hooks/workspace.js +47 -17
  458. package/dist/imessage/accounts.js +9 -20
  459. package/dist/imessage/monitor/inbound-processing.js +2 -1
  460. package/dist/infra/archive-path.js +49 -0
  461. package/dist/infra/archive.js +174 -73
  462. package/dist/infra/control-ui-assets.js +14 -6
  463. package/dist/infra/device-pairing.js +204 -144
  464. package/dist/infra/env.js +10 -5
  465. package/dist/infra/exec-approvals-allowlist.js +141 -70
  466. package/dist/infra/exec-approvals-analysis.js +78 -20
  467. package/dist/infra/exec-approvals.js +5 -17
  468. package/dist/infra/exec-safe-bin-policy.js +277 -0
  469. package/dist/infra/fixed-window-rate-limit.js +33 -0
  470. package/dist/infra/fs-safe.js +71 -39
  471. package/dist/infra/gateway-lock.js +6 -2
  472. package/dist/infra/git-root.js +61 -0
  473. package/dist/infra/heartbeat-active-hours.js +2 -2
  474. package/dist/infra/heartbeat-reason.js +40 -0
  475. package/dist/infra/heartbeat-runner.js +72 -32
  476. package/dist/infra/heartbeat-wake.js +6 -12
  477. package/dist/infra/host-env-security-policy.json +19 -0
  478. package/dist/infra/host-env-security.js +66 -0
  479. package/dist/infra/install-source-utils.js +91 -7
  480. package/dist/infra/net/ssrf.js +131 -38
  481. package/dist/infra/node-pairing.js +50 -105
  482. package/dist/infra/npm-integrity.js +45 -0
  483. package/dist/infra/npm-pack-install.js +40 -0
  484. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  485. package/dist/infra/outbound/channel-adapters.js +20 -7
  486. package/dist/infra/outbound/channel-selection.js +12 -6
  487. package/dist/infra/outbound/envelope.js +1 -1
  488. package/dist/infra/outbound/format.js +12 -6
  489. package/dist/infra/outbound/message-action-runner.js +107 -327
  490. package/dist/infra/outbound/message.js +59 -36
  491. package/dist/infra/outbound/outbound-policy.js +52 -25
  492. package/dist/infra/outbound/outbound-send-service.js +58 -71
  493. package/dist/infra/outbound/payloads.js +14 -7
  494. package/dist/infra/outbound/session-binding-service.js +123 -0
  495. package/dist/infra/pairing-files.js +10 -0
  496. package/dist/infra/path-guards.js +25 -0
  497. package/dist/infra/plain-object.js +9 -0
  498. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  499. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  500. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  501. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  502. package/dist/infra/push-apns.js +365 -0
  503. package/dist/infra/restart-sentinel.js +16 -1
  504. package/dist/infra/restart.js +229 -26
  505. package/dist/infra/retry-policy.js +4 -2
  506. package/dist/infra/retry.js +9 -5
  507. package/dist/infra/scp-host.js +54 -0
  508. package/dist/infra/session-cost-usage.js +107 -59
  509. package/dist/infra/session-maintenance-warning.js +3 -1
  510. package/dist/infra/shell-env.js +98 -34
  511. package/dist/infra/ssh-config.js +12 -6
  512. package/dist/infra/system-run-command.js +49 -4
  513. package/dist/infra/update-channels.js +10 -5
  514. package/dist/infra/update-startup.js +86 -9
  515. package/dist/line/accounts.js +5 -7
  516. package/dist/line/bot-access.js +8 -20
  517. package/dist/line/bot-handlers.js +3 -1
  518. package/dist/link-understanding/detect.js +15 -7
  519. package/dist/media/constants.js +15 -6
  520. package/dist/media/image-ops.js +7 -0
  521. package/dist/media/inbound-path-policy.js +114 -0
  522. package/dist/media/input-files.js +16 -0
  523. package/dist/media/local-roots.js +3 -2
  524. package/dist/media-understanding/apply.js +4 -1
  525. package/dist/media-understanding/concurrency.js +8 -20
  526. package/dist/memory/backend-config.js +45 -6
  527. package/dist/memory/embeddings.js +10 -4
  528. package/dist/memory/fs-utils.js +23 -0
  529. package/dist/memory/manager-search.js +12 -6
  530. package/dist/memory/manager-sync-ops.js +12 -2
  531. package/dist/memory/qmd-manager.js +466 -53
  532. package/dist/memory/query-expansion.js +167 -3
  533. package/dist/memory/status-format.js +10 -5
  534. package/dist/memory/sync-memory-files.js +1 -1
  535. package/dist/memory/test-manager.js +8 -0
  536. package/dist/node-host/invoke-system-run.js +281 -0
  537. package/dist/node-host/invoke.js +55 -337
  538. package/dist/pairing/pairing-store.js +22 -0
  539. package/dist/plugin-sdk/allow-from.js +1 -1
  540. package/dist/plugin-sdk/command-auth.js +3 -1
  541. package/dist/plugin-sdk/index.js +6 -3
  542. package/dist/plugin-sdk/temp-path.js +47 -0
  543. package/dist/plugin-sdk/webhook-targets.js +32 -0
  544. package/dist/plugins/bundled-dir.js +9 -6
  545. package/dist/plugins/discovery.js +217 -23
  546. package/dist/plugins/hook-runner-global.js +16 -0
  547. package/dist/plugins/hooks.js +50 -0
  548. package/dist/plugins/install.js +28 -16
  549. package/dist/plugins/loader.js +192 -26
  550. package/dist/plugins/logger.js +8 -0
  551. package/dist/plugins/manifest-registry.js +3 -0
  552. package/dist/plugins/path-safety.js +34 -0
  553. package/dist/plugins/registry.js +5 -2
  554. package/dist/plugins/runtime/index.js +271 -206
  555. package/dist/plugins/runtime.js +3 -17
  556. package/dist/plugins/update.js +78 -12
  557. package/dist/process/spawn-utils.js +14 -7
  558. package/dist/providers/github-copilot-models.js +4 -1
  559. package/dist/providers/github-copilot-token.js +11 -6
  560. package/dist/providers/qwen-portal-oauth.js +14 -6
  561. package/dist/routing/account-id.js +30 -0
  562. package/dist/routing/resolve-route.js +3 -7
  563. package/dist/routing/session-key.js +2 -16
  564. package/dist/security/audit-channel.js +100 -20
  565. package/dist/security/audit-extra.async.js +505 -179
  566. package/dist/security/audit-extra.js +12 -2
  567. package/dist/security/audit-extra.sync.js +421 -35
  568. package/dist/security/audit-fs.js +31 -13
  569. package/dist/security/audit.js +180 -370
  570. package/dist/security/dm-policy-shared.js +68 -0
  571. package/dist/security/external-content.js +46 -14
  572. package/dist/security/fix.js +49 -85
  573. package/dist/security/scan-paths.js +20 -0
  574. package/dist/security/secret-equal.js +3 -7
  575. package/dist/security/windows-acl.js +30 -15
  576. package/dist/shared/entry-status.js +6 -0
  577. package/dist/shared/frontmatter.js +5 -5
  578. package/dist/shared/node-list-parse.js +13 -0
  579. package/dist/shared/node-match.js +11 -4
  580. package/dist/shared/operator-scope-compat.js +42 -0
  581. package/dist/shared/text-chunking.js +29 -0
  582. package/dist/signal/accounts.js +7 -20
  583. package/dist/signal/monitor/event-handler.js +3 -1
  584. package/dist/slack/accounts.js +6 -19
  585. package/dist/slack/actions.js +11 -3
  586. package/dist/slack/blocks.test-helpers.js +31 -0
  587. package/dist/slack/monitor/auth.js +1 -1
  588. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  589. package/dist/slack/monitor/mrkdwn.js +8 -0
  590. package/dist/slack/monitor/replies.js +15 -7
  591. package/dist/slack/monitor/slash.js +22 -13
  592. package/dist/slack/resolve-channels.js +10 -5
  593. package/dist/slack/send.js +102 -12
  594. package/dist/slack/stream-mode.js +10 -0
  595. package/dist/slack/streaming.js +4 -2
  596. package/dist/telegram/accounts.js +19 -14
  597. package/dist/telegram/bot/helpers.js +3 -5
  598. package/dist/telegram/bot-access.js +35 -36
  599. package/dist/telegram/bot-handlers.js +120 -148
  600. package/dist/telegram/bot-message-context.js +68 -9
  601. package/dist/telegram/bot-message-dispatch.js +477 -210
  602. package/dist/telegram/bot-native-commands.js +16 -0
  603. package/dist/telegram/draft-stream.js +44 -8
  604. package/dist/telegram/inline-buttons.js +5 -15
  605. package/dist/telegram/monitor.js +11 -7
  606. package/dist/telegram/network-config.js +19 -7
  607. package/dist/telegram/reasoning-lane-coordinator.js +128 -0
  608. package/dist/telegram/send.js +3 -2
  609. package/dist/telegram/sent-message-cache.js +5 -6
  610. package/dist/telegram/status-reaction-variants.js +208 -0
  611. package/dist/telegram/sticker-cache.js +11 -9
  612. package/dist/terminal/prompt-select-styled.js +9 -0
  613. package/dist/terminal/theme.js +12 -12
  614. package/dist/test-utils/command-runner.js +6 -0
  615. package/dist/test-utils/internal-hook-event-payload.js +10 -0
  616. package/dist/test-utils/model-auth-mock.js +12 -0
  617. package/dist/test-utils/provider-usage-fetch.js +14 -0
  618. package/dist/test-utils/temp-home.js +33 -0
  619. package/dist/tts/tts.js +80 -567
  620. package/dist/tui/components/chat-log.js +50 -8
  621. package/dist/tui/theme/theme.js +10 -12
  622. package/dist/tui/tui-command-handlers.js +36 -27
  623. package/dist/tui/tui-event-handlers.js +122 -32
  624. package/dist/tui/tui-local-shell.js +16 -6
  625. package/dist/tui/tui.js +236 -48
  626. package/dist/utils/account-id.js +2 -4
  627. package/dist/utils/boolean.js +10 -5
  628. package/dist/utils/directive-tags.js +11 -0
  629. package/dist/utils/mask-api-key.js +10 -0
  630. package/dist/utils/queue-helpers.js +67 -12
  631. package/dist/utils/run-with-concurrency.js +39 -0
  632. package/dist/web/auto-reply/deliver-reply.js +8 -4
  633. package/dist/web/auto-reply/mentions.js +10 -5
  634. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  635. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  636. package/dist/web/inbound/access-control.js +5 -2
  637. package/dist/web/login-qr.js +12 -6
  638. package/dist/web/media.js +126 -15
  639. package/docs/tools/slash-commands.md +5 -1
  640. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  641. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  642. package/extensions/feishu/src/external-keys.ts +19 -0
  643. package/extensions/lobster/src/windows-spawn.ts +193 -0
  644. package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
  645. package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
  646. package/package.json +1 -1
@@ -1,312 +1,325 @@
1
1
  import { isActKind, parseClickButton, parseClickModifiers, } from "./agent.act.shared.js";
2
- import { handleRouteError, readBody, requirePwAi, resolveProfileContext, SELECTOR_UNSUPPORTED_MESSAGE, } from "./agent.shared.js";
2
+ import { readBody, resolveTargetIdFromBody, withPlaywrightRouteContext, SELECTOR_UNSUPPORTED_MESSAGE, } from "./agent.shared.js";
3
+ import { DEFAULT_DOWNLOAD_DIR, DEFAULT_UPLOAD_DIR, resolvePathWithinRoot, resolveExistingPathsWithinRoot, } from "./path-output.js";
3
4
  import { jsonError, toBoolean, toNumber, toStringArray, toStringOrEmpty } from "./utils.js";
5
+ function resolveDownloadPathOrRespond(res, requestedPath) {
6
+ const downloadPathResult = resolvePathWithinRoot({
7
+ rootDir: DEFAULT_DOWNLOAD_DIR,
8
+ requestedPath,
9
+ scopeLabel: "downloads directory",
10
+ });
11
+ if (!downloadPathResult.ok) {
12
+ res.status(400).json({ error: downloadPathResult.error });
13
+ return null;
14
+ }
15
+ return downloadPathResult.path;
16
+ }
17
+ function buildDownloadRequestBase(cdpUrl, targetId, timeoutMs) {
18
+ return {
19
+ cdpUrl,
20
+ targetId,
21
+ timeoutMs: timeoutMs ?? undefined,
22
+ };
23
+ }
24
+ function respondWithDownloadResult(res, targetId, result) {
25
+ res.json({ ok: true, targetId, download: result });
26
+ }
4
27
  export function registerBrowserAgentActRoutes(app, ctx) {
5
28
  app.post("/act", async (req, res) => {
6
- const profileCtx = resolveProfileContext(req, res, ctx);
7
- if (!profileCtx) {
8
- return;
9
- }
10
29
  const body = readBody(req);
11
30
  const kindRaw = toStringOrEmpty(body.kind);
12
31
  if (!isActKind(kindRaw)) {
13
32
  return jsonError(res, 400, "kind is required");
14
33
  }
15
34
  const kind = kindRaw;
16
- const targetId = toStringOrEmpty(body.targetId) || undefined;
35
+ const targetId = resolveTargetIdFromBody(body);
17
36
  if (Object.hasOwn(body, "selector") && kind !== "wait") {
18
37
  return jsonError(res, 400, SELECTOR_UNSUPPORTED_MESSAGE);
19
38
  }
20
- try {
21
- const tab = await profileCtx.ensureTabAvailable(targetId);
22
- const cdpUrl = profileCtx.profile.cdpUrl;
23
- const pw = await requirePwAi(res, `act:${kind}`);
24
- if (!pw) {
25
- return;
26
- }
27
- const evaluateEnabled = ctx.state().resolved.evaluateEnabled;
28
- switch (kind) {
29
- case "click": {
30
- const ref = toStringOrEmpty(body.ref);
31
- if (!ref) {
32
- return jsonError(res, 400, "ref is required");
33
- }
34
- const doubleClick = toBoolean(body.doubleClick) ?? false;
35
- const timeoutMs = toNumber(body.timeoutMs);
36
- const buttonRaw = toStringOrEmpty(body.button) || "";
37
- const button = buttonRaw ? parseClickButton(buttonRaw) : undefined;
38
- if (buttonRaw && !button) {
39
- return jsonError(res, 400, "button must be left|right|middle");
40
- }
41
- const modifiersRaw = toStringArray(body.modifiers) ?? [];
42
- const parsedModifiers = parseClickModifiers(modifiersRaw);
43
- if (parsedModifiers.error) {
44
- return jsonError(res, 400, parsedModifiers.error);
45
- }
46
- const modifiers = parsedModifiers.modifiers;
47
- const clickRequest = {
48
- cdpUrl,
49
- targetId: tab.targetId,
50
- ref,
51
- doubleClick,
52
- };
53
- if (button) {
54
- clickRequest.button = button;
55
- }
56
- if (modifiers) {
57
- clickRequest.modifiers = modifiers;
58
- }
59
- if (timeoutMs) {
60
- clickRequest.timeoutMs = timeoutMs;
61
- }
62
- await pw.clickViaPlaywright(clickRequest);
63
- return res.json({ ok: true, targetId: tab.targetId, url: tab.url });
64
- }
65
- case "type": {
66
- const ref = toStringOrEmpty(body.ref);
67
- if (!ref) {
68
- return jsonError(res, 400, "ref is required");
39
+ await withPlaywrightRouteContext({
40
+ req,
41
+ res,
42
+ ctx,
43
+ targetId,
44
+ feature: `act:${kind}`,
45
+ run: async ({ cdpUrl, tab, pw }) => {
46
+ const evaluateEnabled = ctx.state().resolved.evaluateEnabled;
47
+ switch (kind) {
48
+ case "click": {
49
+ const ref = toStringOrEmpty(body.ref);
50
+ if (!ref) {
51
+ return jsonError(res, 400, "ref is required");
52
+ }
53
+ const doubleClick = toBoolean(body.doubleClick) ?? false;
54
+ const timeoutMs = toNumber(body.timeoutMs);
55
+ const buttonRaw = toStringOrEmpty(body.button) || "";
56
+ const button = buttonRaw ? parseClickButton(buttonRaw) : undefined;
57
+ if (buttonRaw && !button) {
58
+ return jsonError(res, 400, "button must be left|right|middle");
59
+ }
60
+ const modifiersRaw = toStringArray(body.modifiers) ?? [];
61
+ const parsedModifiers = parseClickModifiers(modifiersRaw);
62
+ if (parsedModifiers.error) {
63
+ return jsonError(res, 400, parsedModifiers.error);
64
+ }
65
+ const modifiers = parsedModifiers.modifiers;
66
+ const clickRequest = {
67
+ cdpUrl,
68
+ targetId: tab.targetId,
69
+ ref,
70
+ doubleClick,
71
+ };
72
+ if (button) {
73
+ clickRequest.button = button;
74
+ }
75
+ if (modifiers) {
76
+ clickRequest.modifiers = modifiers;
77
+ }
78
+ if (timeoutMs) {
79
+ clickRequest.timeoutMs = timeoutMs;
80
+ }
81
+ await pw.clickViaPlaywright(clickRequest);
82
+ return res.json({ ok: true, targetId: tab.targetId, url: tab.url });
69
83
  }
70
- if (typeof body.text !== "string") {
71
- return jsonError(res, 400, "text is required");
84
+ case "type": {
85
+ const ref = toStringOrEmpty(body.ref);
86
+ if (!ref) {
87
+ return jsonError(res, 400, "ref is required");
88
+ }
89
+ if (typeof body.text !== "string") {
90
+ return jsonError(res, 400, "text is required");
91
+ }
92
+ const text = body.text;
93
+ const submit = toBoolean(body.submit) ?? false;
94
+ const slowly = toBoolean(body.slowly) ?? false;
95
+ const timeoutMs = toNumber(body.timeoutMs);
96
+ const typeRequest = {
97
+ cdpUrl,
98
+ targetId: tab.targetId,
99
+ ref,
100
+ text,
101
+ submit,
102
+ slowly,
103
+ };
104
+ if (timeoutMs) {
105
+ typeRequest.timeoutMs = timeoutMs;
106
+ }
107
+ await pw.typeViaPlaywright(typeRequest);
108
+ return res.json({ ok: true, targetId: tab.targetId });
72
109
  }
73
- const text = body.text;
74
- const submit = toBoolean(body.submit) ?? false;
75
- const slowly = toBoolean(body.slowly) ?? false;
76
- const timeoutMs = toNumber(body.timeoutMs);
77
- const typeRequest = {
78
- cdpUrl,
79
- targetId: tab.targetId,
80
- ref,
81
- text,
82
- submit,
83
- slowly,
84
- };
85
- if (timeoutMs) {
86
- typeRequest.timeoutMs = timeoutMs;
110
+ case "press": {
111
+ const key = toStringOrEmpty(body.key);
112
+ if (!key) {
113
+ return jsonError(res, 400, "key is required");
114
+ }
115
+ const delayMs = toNumber(body.delayMs);
116
+ await pw.pressKeyViaPlaywright({
117
+ cdpUrl,
118
+ targetId: tab.targetId,
119
+ key,
120
+ delayMs: delayMs ?? undefined,
121
+ });
122
+ return res.json({ ok: true, targetId: tab.targetId });
87
123
  }
88
- await pw.typeViaPlaywright(typeRequest);
89
- return res.json({ ok: true, targetId: tab.targetId });
90
- }
91
- case "press": {
92
- const key = toStringOrEmpty(body.key);
93
- if (!key) {
94
- return jsonError(res, 400, "key is required");
124
+ case "hover": {
125
+ const ref = toStringOrEmpty(body.ref);
126
+ if (!ref) {
127
+ return jsonError(res, 400, "ref is required");
128
+ }
129
+ const timeoutMs = toNumber(body.timeoutMs);
130
+ await pw.hoverViaPlaywright({
131
+ cdpUrl,
132
+ targetId: tab.targetId,
133
+ ref,
134
+ timeoutMs: timeoutMs ?? undefined,
135
+ });
136
+ return res.json({ ok: true, targetId: tab.targetId });
95
137
  }
96
- const delayMs = toNumber(body.delayMs);
97
- await pw.pressKeyViaPlaywright({
98
- cdpUrl,
99
- targetId: tab.targetId,
100
- key,
101
- delayMs: delayMs ?? undefined,
102
- });
103
- return res.json({ ok: true, targetId: tab.targetId });
104
- }
105
- case "hover": {
106
- const ref = toStringOrEmpty(body.ref);
107
- if (!ref) {
108
- return jsonError(res, 400, "ref is required");
138
+ case "scrollIntoView": {
139
+ const ref = toStringOrEmpty(body.ref);
140
+ if (!ref) {
141
+ return jsonError(res, 400, "ref is required");
142
+ }
143
+ const timeoutMs = toNumber(body.timeoutMs);
144
+ const scrollRequest = {
145
+ cdpUrl,
146
+ targetId: tab.targetId,
147
+ ref,
148
+ };
149
+ if (timeoutMs) {
150
+ scrollRequest.timeoutMs = timeoutMs;
151
+ }
152
+ await pw.scrollIntoViewViaPlaywright(scrollRequest);
153
+ return res.json({ ok: true, targetId: tab.targetId });
109
154
  }
110
- const timeoutMs = toNumber(body.timeoutMs);
111
- await pw.hoverViaPlaywright({
112
- cdpUrl,
113
- targetId: tab.targetId,
114
- ref,
115
- timeoutMs: timeoutMs ?? undefined,
116
- });
117
- return res.json({ ok: true, targetId: tab.targetId });
118
- }
119
- case "scrollIntoView": {
120
- const ref = toStringOrEmpty(body.ref);
121
- if (!ref) {
122
- return jsonError(res, 400, "ref is required");
155
+ case "drag": {
156
+ const startRef = toStringOrEmpty(body.startRef);
157
+ const endRef = toStringOrEmpty(body.endRef);
158
+ if (!startRef || !endRef) {
159
+ return jsonError(res, 400, "startRef and endRef are required");
160
+ }
161
+ const timeoutMs = toNumber(body.timeoutMs);
162
+ await pw.dragViaPlaywright({
163
+ cdpUrl,
164
+ targetId: tab.targetId,
165
+ startRef,
166
+ endRef,
167
+ timeoutMs: timeoutMs ?? undefined,
168
+ });
169
+ return res.json({ ok: true, targetId: tab.targetId });
123
170
  }
124
- const timeoutMs = toNumber(body.timeoutMs);
125
- const scrollRequest = {
126
- cdpUrl,
127
- targetId: tab.targetId,
128
- ref,
129
- };
130
- if (timeoutMs) {
131
- scrollRequest.timeoutMs = timeoutMs;
171
+ case "select": {
172
+ const ref = toStringOrEmpty(body.ref);
173
+ const values = toStringArray(body.values);
174
+ if (!ref || !values?.length) {
175
+ return jsonError(res, 400, "ref and values are required");
176
+ }
177
+ const timeoutMs = toNumber(body.timeoutMs);
178
+ await pw.selectOptionViaPlaywright({
179
+ cdpUrl,
180
+ targetId: tab.targetId,
181
+ ref,
182
+ values,
183
+ timeoutMs: timeoutMs ?? undefined,
184
+ });
185
+ return res.json({ ok: true, targetId: tab.targetId });
132
186
  }
133
- await pw.scrollIntoViewViaPlaywright(scrollRequest);
134
- return res.json({ ok: true, targetId: tab.targetId });
135
- }
136
- case "drag": {
137
- const startRef = toStringOrEmpty(body.startRef);
138
- const endRef = toStringOrEmpty(body.endRef);
139
- if (!startRef || !endRef) {
140
- return jsonError(res, 400, "startRef and endRef are required");
187
+ case "fill": {
188
+ const rawFields = Array.isArray(body.fields) ? body.fields : [];
189
+ const fields = rawFields
190
+ .map((field) => {
191
+ if (!field || typeof field !== "object") {
192
+ return null;
193
+ }
194
+ const rec = field;
195
+ const ref = toStringOrEmpty(rec.ref);
196
+ const type = toStringOrEmpty(rec.type);
197
+ if (!ref || !type) {
198
+ return null;
199
+ }
200
+ const value = typeof rec.value === "string" ||
201
+ typeof rec.value === "number" ||
202
+ typeof rec.value === "boolean"
203
+ ? rec.value
204
+ : undefined;
205
+ const parsed = value === undefined ? { ref, type } : { ref, type, value };
206
+ return parsed;
207
+ })
208
+ .filter((field) => field !== null);
209
+ if (!fields.length) {
210
+ return jsonError(res, 400, "fields are required");
211
+ }
212
+ const timeoutMs = toNumber(body.timeoutMs);
213
+ await pw.fillFormViaPlaywright({
214
+ cdpUrl,
215
+ targetId: tab.targetId,
216
+ fields,
217
+ timeoutMs: timeoutMs ?? undefined,
218
+ });
219
+ return res.json({ ok: true, targetId: tab.targetId });
141
220
  }
142
- const timeoutMs = toNumber(body.timeoutMs);
143
- await pw.dragViaPlaywright({
144
- cdpUrl,
145
- targetId: tab.targetId,
146
- startRef,
147
- endRef,
148
- timeoutMs: timeoutMs ?? undefined,
149
- });
150
- return res.json({ ok: true, targetId: tab.targetId });
151
- }
152
- case "select": {
153
- const ref = toStringOrEmpty(body.ref);
154
- const values = toStringArray(body.values);
155
- if (!ref || !values?.length) {
156
- return jsonError(res, 400, "ref and values are required");
221
+ case "resize": {
222
+ const width = toNumber(body.width);
223
+ const height = toNumber(body.height);
224
+ if (!width || !height) {
225
+ return jsonError(res, 400, "width and height are required");
226
+ }
227
+ await pw.resizeViewportViaPlaywright({
228
+ cdpUrl,
229
+ targetId: tab.targetId,
230
+ width,
231
+ height,
232
+ });
233
+ return res.json({ ok: true, targetId: tab.targetId, url: tab.url });
157
234
  }
158
- const timeoutMs = toNumber(body.timeoutMs);
159
- await pw.selectOptionViaPlaywright({
160
- cdpUrl,
161
- targetId: tab.targetId,
162
- ref,
163
- values,
164
- timeoutMs: timeoutMs ?? undefined,
165
- });
166
- return res.json({ ok: true, targetId: tab.targetId });
167
- }
168
- case "fill": {
169
- const rawFields = Array.isArray(body.fields) ? body.fields : [];
170
- const fields = rawFields
171
- .map((field) => {
172
- if (!field || typeof field !== "object") {
173
- return null;
235
+ case "wait": {
236
+ const timeMs = toNumber(body.timeMs);
237
+ const text = toStringOrEmpty(body.text) || undefined;
238
+ const textGone = toStringOrEmpty(body.textGone) || undefined;
239
+ const selector = toStringOrEmpty(body.selector) || undefined;
240
+ const url = toStringOrEmpty(body.url) || undefined;
241
+ const loadStateRaw = toStringOrEmpty(body.loadState);
242
+ const loadState = loadStateRaw === "load" ||
243
+ loadStateRaw === "domcontentloaded" ||
244
+ loadStateRaw === "networkidle"
245
+ ? loadStateRaw
246
+ : undefined;
247
+ const fn = toStringOrEmpty(body.fn) || undefined;
248
+ const timeoutMs = toNumber(body.timeoutMs) ?? undefined;
249
+ if (fn && !evaluateEnabled) {
250
+ return jsonError(res, 403, [
251
+ "wait --fn is disabled by config (browser.evaluateEnabled=false).",
252
+ "Docs: /gateway/configuration#browser-clawd-managed-browser",
253
+ ].join("\n"));
174
254
  }
175
- const rec = field;
176
- const ref = toStringOrEmpty(rec.ref);
177
- const type = toStringOrEmpty(rec.type);
178
- if (!ref || !type) {
179
- return null;
255
+ if (timeMs === undefined &&
256
+ !text &&
257
+ !textGone &&
258
+ !selector &&
259
+ !url &&
260
+ !loadState &&
261
+ !fn) {
262
+ return jsonError(res, 400, "wait requires at least one of: timeMs, text, textGone, selector, url, loadState, fn");
180
263
  }
181
- const value = typeof rec.value === "string" ||
182
- typeof rec.value === "number" ||
183
- typeof rec.value === "boolean"
184
- ? rec.value
185
- : undefined;
186
- const parsed = value === undefined ? { ref, type } : { ref, type, value };
187
- return parsed;
188
- })
189
- .filter((field) => field !== null);
190
- if (!fields.length) {
191
- return jsonError(res, 400, "fields are required");
192
- }
193
- const timeoutMs = toNumber(body.timeoutMs);
194
- await pw.fillFormViaPlaywright({
195
- cdpUrl,
196
- targetId: tab.targetId,
197
- fields,
198
- timeoutMs: timeoutMs ?? undefined,
199
- });
200
- return res.json({ ok: true, targetId: tab.targetId });
201
- }
202
- case "resize": {
203
- const width = toNumber(body.width);
204
- const height = toNumber(body.height);
205
- if (!width || !height) {
206
- return jsonError(res, 400, "width and height are required");
207
- }
208
- await pw.resizeViewportViaPlaywright({
209
- cdpUrl,
210
- targetId: tab.targetId,
211
- width,
212
- height,
213
- });
214
- return res.json({ ok: true, targetId: tab.targetId, url: tab.url });
215
- }
216
- case "wait": {
217
- const timeMs = toNumber(body.timeMs);
218
- const text = toStringOrEmpty(body.text) || undefined;
219
- const textGone = toStringOrEmpty(body.textGone) || undefined;
220
- const selector = toStringOrEmpty(body.selector) || undefined;
221
- const url = toStringOrEmpty(body.url) || undefined;
222
- const loadStateRaw = toStringOrEmpty(body.loadState);
223
- const loadState = loadStateRaw === "load" ||
224
- loadStateRaw === "domcontentloaded" ||
225
- loadStateRaw === "networkidle"
226
- ? loadStateRaw
227
- : undefined;
228
- const fn = toStringOrEmpty(body.fn) || undefined;
229
- const timeoutMs = toNumber(body.timeoutMs) ?? undefined;
230
- if (fn && !evaluateEnabled) {
231
- return jsonError(res, 403, [
232
- "wait --fn is disabled by config (browser.evaluateEnabled=false).",
233
- "Docs: /gateway/configuration#browser-clawd-managed-browser",
234
- ].join("\n"));
235
- }
236
- if (timeMs === undefined &&
237
- !text &&
238
- !textGone &&
239
- !selector &&
240
- !url &&
241
- !loadState &&
242
- !fn) {
243
- return jsonError(res, 400, "wait requires at least one of: timeMs, text, textGone, selector, url, loadState, fn");
264
+ await pw.waitForViaPlaywright({
265
+ cdpUrl,
266
+ targetId: tab.targetId,
267
+ timeMs,
268
+ text,
269
+ textGone,
270
+ selector,
271
+ url,
272
+ loadState,
273
+ fn,
274
+ timeoutMs,
275
+ });
276
+ return res.json({ ok: true, targetId: tab.targetId });
244
277
  }
245
- await pw.waitForViaPlaywright({
246
- cdpUrl,
247
- targetId: tab.targetId,
248
- timeMs,
249
- text,
250
- textGone,
251
- selector,
252
- url,
253
- loadState,
254
- fn,
255
- timeoutMs,
256
- });
257
- return res.json({ ok: true, targetId: tab.targetId });
258
- }
259
- case "evaluate": {
260
- if (!evaluateEnabled) {
261
- return jsonError(res, 403, [
262
- "act:evaluate is disabled by config (browser.evaluateEnabled=false).",
263
- "Docs: /gateway/configuration#browser-clawd-managed-browser",
264
- ].join("\n"));
278
+ case "evaluate": {
279
+ if (!evaluateEnabled) {
280
+ return jsonError(res, 403, [
281
+ "act:evaluate is disabled by config (browser.evaluateEnabled=false).",
282
+ "Docs: /gateway/configuration#browser-clawd-managed-browser",
283
+ ].join("\n"));
284
+ }
285
+ const fn = toStringOrEmpty(body.fn);
286
+ if (!fn) {
287
+ return jsonError(res, 400, "fn is required");
288
+ }
289
+ const ref = toStringOrEmpty(body.ref) || undefined;
290
+ const evalTimeoutMs = toNumber(body.timeoutMs);
291
+ const evalRequest = {
292
+ cdpUrl,
293
+ targetId: tab.targetId,
294
+ fn,
295
+ ref,
296
+ signal: req.signal,
297
+ };
298
+ if (evalTimeoutMs !== undefined) {
299
+ evalRequest.timeoutMs = evalTimeoutMs;
300
+ }
301
+ const result = await pw.evaluateViaPlaywright(evalRequest);
302
+ return res.json({
303
+ ok: true,
304
+ targetId: tab.targetId,
305
+ url: tab.url,
306
+ result,
307
+ });
265
308
  }
266
- const fn = toStringOrEmpty(body.fn);
267
- if (!fn) {
268
- return jsonError(res, 400, "fn is required");
309
+ case "close": {
310
+ await pw.closePageViaPlaywright({ cdpUrl, targetId: tab.targetId });
311
+ return res.json({ ok: true, targetId: tab.targetId });
269
312
  }
270
- const ref = toStringOrEmpty(body.ref) || undefined;
271
- const evalTimeoutMs = toNumber(body.timeoutMs);
272
- const evalRequest = {
273
- cdpUrl,
274
- targetId: tab.targetId,
275
- fn,
276
- ref,
277
- signal: req.signal,
278
- };
279
- if (evalTimeoutMs !== undefined) {
280
- evalRequest.timeoutMs = evalTimeoutMs;
313
+ default: {
314
+ return jsonError(res, 400, "unsupported kind");
281
315
  }
282
- const result = await pw.evaluateViaPlaywright(evalRequest);
283
- return res.json({
284
- ok: true,
285
- targetId: tab.targetId,
286
- url: tab.url,
287
- result,
288
- });
289
- }
290
- case "close": {
291
- await pw.closePageViaPlaywright({ cdpUrl, targetId: tab.targetId });
292
- return res.json({ ok: true, targetId: tab.targetId });
293
316
  }
294
- default: {
295
- return jsonError(res, 400, "unsupported kind");
296
- }
297
- }
298
- }
299
- catch (err) {
300
- handleRouteError(ctx, res, err);
301
- }
317
+ },
318
+ });
302
319
  });
303
320
  app.post("/hooks/file-chooser", async (req, res) => {
304
- const profileCtx = resolveProfileContext(req, res, ctx);
305
- if (!profileCtx) {
306
- return;
307
- }
308
321
  const body = readBody(req);
309
- const targetId = toStringOrEmpty(body.targetId) || undefined;
322
+ const targetId = resolveTargetIdFromBody(body);
310
323
  const ref = toStringOrEmpty(body.ref) || undefined;
311
324
  const inputRef = toStringOrEmpty(body.inputRef) || undefined;
312
325
  const element = toStringOrEmpty(body.element) || undefined;
@@ -315,111 +328,113 @@ export function registerBrowserAgentActRoutes(app, ctx) {
315
328
  if (!paths.length) {
316
329
  return jsonError(res, 400, "paths are required");
317
330
  }
318
- try {
319
- const tab = await profileCtx.ensureTabAvailable(targetId);
320
- const pw = await requirePwAi(res, "file chooser hook");
321
- if (!pw) {
322
- return;
323
- }
324
- if (inputRef || element) {
325
- if (ref) {
326
- return jsonError(res, 400, "ref cannot be combined with inputRef/element");
327
- }
328
- await pw.setInputFilesViaPlaywright({
329
- cdpUrl: profileCtx.profile.cdpUrl,
330
- targetId: tab.targetId,
331
- inputRef,
332
- element,
333
- paths,
334
- });
335
- }
336
- else {
337
- await pw.armFileUploadViaPlaywright({
338
- cdpUrl: profileCtx.profile.cdpUrl,
339
- targetId: tab.targetId,
340
- paths,
341
- timeoutMs: timeoutMs ?? undefined,
331
+ await withPlaywrightRouteContext({
332
+ req,
333
+ res,
334
+ ctx,
335
+ targetId,
336
+ feature: "file chooser hook",
337
+ run: async ({ cdpUrl, tab, pw }) => {
338
+ const uploadPathsResult = await resolveExistingPathsWithinRoot({
339
+ rootDir: DEFAULT_UPLOAD_DIR,
340
+ requestedPaths: paths,
341
+ scopeLabel: `uploads directory (${DEFAULT_UPLOAD_DIR})`,
342
342
  });
343
- if (ref) {
344
- await pw.clickViaPlaywright({
345
- cdpUrl: profileCtx.profile.cdpUrl,
343
+ if (!uploadPathsResult.ok) {
344
+ res.status(400).json({ error: uploadPathsResult.error });
345
+ return;
346
+ }
347
+ const resolvedPaths = uploadPathsResult.paths;
348
+ if (inputRef || element) {
349
+ if (ref) {
350
+ return jsonError(res, 400, "ref cannot be combined with inputRef/element");
351
+ }
352
+ await pw.setInputFilesViaPlaywright({
353
+ cdpUrl,
346
354
  targetId: tab.targetId,
347
- ref,
355
+ inputRef,
356
+ element,
357
+ paths: resolvedPaths,
348
358
  });
349
359
  }
350
- }
351
- res.json({ ok: true });
352
- }
353
- catch (err) {
354
- handleRouteError(ctx, res, err);
355
- }
360
+ else {
361
+ await pw.armFileUploadViaPlaywright({
362
+ cdpUrl,
363
+ targetId: tab.targetId,
364
+ paths: resolvedPaths,
365
+ timeoutMs: timeoutMs ?? undefined,
366
+ });
367
+ if (ref) {
368
+ await pw.clickViaPlaywright({
369
+ cdpUrl,
370
+ targetId: tab.targetId,
371
+ ref,
372
+ });
373
+ }
374
+ }
375
+ res.json({ ok: true });
376
+ },
377
+ });
356
378
  });
357
379
  app.post("/hooks/dialog", async (req, res) => {
358
- const profileCtx = resolveProfileContext(req, res, ctx);
359
- if (!profileCtx) {
360
- return;
361
- }
362
380
  const body = readBody(req);
363
- const targetId = toStringOrEmpty(body.targetId) || undefined;
381
+ const targetId = resolveTargetIdFromBody(body);
364
382
  const accept = toBoolean(body.accept);
365
383
  const promptText = toStringOrEmpty(body.promptText) || undefined;
366
384
  const timeoutMs = toNumber(body.timeoutMs);
367
385
  if (accept === undefined) {
368
386
  return jsonError(res, 400, "accept is required");
369
387
  }
370
- try {
371
- const tab = await profileCtx.ensureTabAvailable(targetId);
372
- const pw = await requirePwAi(res, "dialog hook");
373
- if (!pw) {
374
- return;
375
- }
376
- await pw.armDialogViaPlaywright({
377
- cdpUrl: profileCtx.profile.cdpUrl,
378
- targetId: tab.targetId,
379
- accept,
380
- promptText,
381
- timeoutMs: timeoutMs ?? undefined,
382
- });
383
- res.json({ ok: true });
384
- }
385
- catch (err) {
386
- handleRouteError(ctx, res, err);
387
- }
388
+ await withPlaywrightRouteContext({
389
+ req,
390
+ res,
391
+ ctx,
392
+ targetId,
393
+ feature: "dialog hook",
394
+ run: async ({ cdpUrl, tab, pw }) => {
395
+ await pw.armDialogViaPlaywright({
396
+ cdpUrl,
397
+ targetId: tab.targetId,
398
+ accept,
399
+ promptText,
400
+ timeoutMs: timeoutMs ?? undefined,
401
+ });
402
+ res.json({ ok: true });
403
+ },
404
+ });
388
405
  });
389
406
  app.post("/wait/download", async (req, res) => {
390
- const profileCtx = resolveProfileContext(req, res, ctx);
391
- if (!profileCtx) {
392
- return;
393
- }
394
407
  const body = readBody(req);
395
- const targetId = toStringOrEmpty(body.targetId) || undefined;
396
- const out = toStringOrEmpty(body.path) || undefined;
408
+ const targetId = resolveTargetIdFromBody(body);
409
+ const out = toStringOrEmpty(body.path) || "";
397
410
  const timeoutMs = toNumber(body.timeoutMs);
398
- try {
399
- const tab = await profileCtx.ensureTabAvailable(targetId);
400
- const pw = await requirePwAi(res, "wait for download");
401
- if (!pw) {
402
- return;
403
- }
404
- const result = await pw.waitForDownloadViaPlaywright({
405
- cdpUrl: profileCtx.profile.cdpUrl,
406
- targetId: tab.targetId,
407
- path: out,
408
- timeoutMs: timeoutMs ?? undefined,
409
- });
410
- res.json({ ok: true, targetId: tab.targetId, download: result });
411
- }
412
- catch (err) {
413
- handleRouteError(ctx, res, err);
414
- }
411
+ await withPlaywrightRouteContext({
412
+ req,
413
+ res,
414
+ ctx,
415
+ targetId,
416
+ feature: "wait for download",
417
+ run: async ({ cdpUrl, tab, pw }) => {
418
+ let downloadPath;
419
+ if (out.trim()) {
420
+ const resolvedDownloadPath = resolveDownloadPathOrRespond(res, out);
421
+ if (!resolvedDownloadPath) {
422
+ return;
423
+ }
424
+ downloadPath = resolvedDownloadPath;
425
+ }
426
+ const requestBase = buildDownloadRequestBase(cdpUrl, tab.targetId, timeoutMs);
427
+ const result = await pw.waitForDownloadViaPlaywright({
428
+ ...requestBase,
429
+ path: downloadPath,
430
+ });
431
+ respondWithDownloadResult(res, tab.targetId, result);
432
+ },
433
+ });
415
434
  });
416
435
  app.post("/download", async (req, res) => {
417
- const profileCtx = resolveProfileContext(req, res, ctx);
418
- if (!profileCtx) {
419
- return;
420
- }
421
436
  const body = readBody(req);
422
- const targetId = toStringOrEmpty(body.targetId) || undefined;
437
+ const targetId = resolveTargetIdFromBody(body);
423
438
  const ref = toStringOrEmpty(body.ref);
424
439
  const out = toStringOrEmpty(body.path);
425
440
  const timeoutMs = toNumber(body.timeoutMs);
@@ -429,83 +444,75 @@ export function registerBrowserAgentActRoutes(app, ctx) {
429
444
  if (!out) {
430
445
  return jsonError(res, 400, "path is required");
431
446
  }
432
- try {
433
- const tab = await profileCtx.ensureTabAvailable(targetId);
434
- const pw = await requirePwAi(res, "download");
435
- if (!pw) {
436
- return;
437
- }
438
- const result = await pw.downloadViaPlaywright({
439
- cdpUrl: profileCtx.profile.cdpUrl,
440
- targetId: tab.targetId,
441
- ref,
442
- path: out,
443
- timeoutMs: timeoutMs ?? undefined,
444
- });
445
- res.json({ ok: true, targetId: tab.targetId, download: result });
446
- }
447
- catch (err) {
448
- handleRouteError(ctx, res, err);
449
- }
447
+ await withPlaywrightRouteContext({
448
+ req,
449
+ res,
450
+ ctx,
451
+ targetId,
452
+ feature: "download",
453
+ run: async ({ cdpUrl, tab, pw }) => {
454
+ const downloadPath = resolveDownloadPathOrRespond(res, out);
455
+ if (!downloadPath) {
456
+ return;
457
+ }
458
+ const requestBase = buildDownloadRequestBase(cdpUrl, tab.targetId, timeoutMs);
459
+ const result = await pw.downloadViaPlaywright({
460
+ ...requestBase,
461
+ ref,
462
+ path: downloadPath,
463
+ });
464
+ respondWithDownloadResult(res, tab.targetId, result);
465
+ },
466
+ });
450
467
  });
451
468
  app.post("/response/body", async (req, res) => {
452
- const profileCtx = resolveProfileContext(req, res, ctx);
453
- if (!profileCtx) {
454
- return;
455
- }
456
469
  const body = readBody(req);
457
- const targetId = toStringOrEmpty(body.targetId) || undefined;
470
+ const targetId = resolveTargetIdFromBody(body);
458
471
  const url = toStringOrEmpty(body.url);
459
472
  const timeoutMs = toNumber(body.timeoutMs);
460
473
  const maxChars = toNumber(body.maxChars);
461
474
  if (!url) {
462
475
  return jsonError(res, 400, "url is required");
463
476
  }
464
- try {
465
- const tab = await profileCtx.ensureTabAvailable(targetId);
466
- const pw = await requirePwAi(res, "response body");
467
- if (!pw) {
468
- return;
469
- }
470
- const result = await pw.responseBodyViaPlaywright({
471
- cdpUrl: profileCtx.profile.cdpUrl,
472
- targetId: tab.targetId,
473
- url,
474
- timeoutMs: timeoutMs ?? undefined,
475
- maxChars: maxChars ?? undefined,
476
- });
477
- res.json({ ok: true, targetId: tab.targetId, response: result });
478
- }
479
- catch (err) {
480
- handleRouteError(ctx, res, err);
481
- }
477
+ await withPlaywrightRouteContext({
478
+ req,
479
+ res,
480
+ ctx,
481
+ targetId,
482
+ feature: "response body",
483
+ run: async ({ cdpUrl, tab, pw }) => {
484
+ const result = await pw.responseBodyViaPlaywright({
485
+ cdpUrl,
486
+ targetId: tab.targetId,
487
+ url,
488
+ timeoutMs: timeoutMs ?? undefined,
489
+ maxChars: maxChars ?? undefined,
490
+ });
491
+ res.json({ ok: true, targetId: tab.targetId, response: result });
492
+ },
493
+ });
482
494
  });
483
495
  app.post("/highlight", async (req, res) => {
484
- const profileCtx = resolveProfileContext(req, res, ctx);
485
- if (!profileCtx) {
486
- return;
487
- }
488
496
  const body = readBody(req);
489
- const targetId = toStringOrEmpty(body.targetId) || undefined;
497
+ const targetId = resolveTargetIdFromBody(body);
490
498
  const ref = toStringOrEmpty(body.ref);
491
499
  if (!ref) {
492
500
  return jsonError(res, 400, "ref is required");
493
501
  }
494
- try {
495
- const tab = await profileCtx.ensureTabAvailable(targetId);
496
- const pw = await requirePwAi(res, "highlight");
497
- if (!pw) {
498
- return;
499
- }
500
- await pw.highlightViaPlaywright({
501
- cdpUrl: profileCtx.profile.cdpUrl,
502
- targetId: tab.targetId,
503
- ref,
504
- });
505
- res.json({ ok: true, targetId: tab.targetId });
506
- }
507
- catch (err) {
508
- handleRouteError(ctx, res, err);
509
- }
502
+ await withPlaywrightRouteContext({
503
+ req,
504
+ res,
505
+ ctx,
506
+ targetId,
507
+ feature: "highlight",
508
+ run: async ({ cdpUrl, tab, pw }) => {
509
+ await pw.highlightViaPlaywright({
510
+ cdpUrl,
511
+ targetId: tab.targetId,
512
+ ref,
513
+ });
514
+ res.json({ ok: true, targetId: tab.targetId });
515
+ },
516
+ });
510
517
  });
511
518
  }