@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,3 +1,15 @@
1
+ // Keep tool-policy browser-safe: do not import tools/common at runtime.
2
+ function wrapOwnerOnlyToolExecution(tool, senderIsOwner) {
3
+ if (tool.ownerOnly !== true || senderIsOwner || !tool.execute) {
4
+ return tool;
5
+ }
6
+ return {
7
+ ...tool,
8
+ execute: async () => {
9
+ throw new Error("Tool restricted to owner senders.");
10
+ },
11
+ };
12
+ }
1
13
  const TOOL_NAME_ALIASES = {
2
14
  bash: "exec",
3
15
  "apply-patch": "apply_patch",
@@ -16,6 +28,7 @@ export const TOOL_GROUPS = {
16
28
  "sessions_history",
17
29
  "sessions_send",
18
30
  "sessions_spawn",
31
+ "subagents",
19
32
  "session_status",
20
33
  ],
21
34
  // UI helpers
@@ -26,7 +39,7 @@ export const TOOL_GROUPS = {
26
39
  "group:messaging": ["message"],
27
40
  // Nodes + device tools
28
41
  "group:nodes": ["nodes"],
29
- // All Poolbot native tools (excludes provider plugins).
42
+ // All Pool Bot native tools (excludes provider plugins).
30
43
  "group:poolbot": [
31
44
  "browser",
32
45
  "canvas",
@@ -39,6 +52,7 @@ export const TOOL_GROUPS = {
39
52
  "sessions_history",
40
53
  "sessions_send",
41
54
  "sessions_spawn",
55
+ "subagents",
42
56
  "session_status",
43
57
  "memory_search",
44
58
  "memory_get",
@@ -47,7 +61,7 @@ export const TOOL_GROUPS = {
47
61
  "image",
48
62
  ],
49
63
  };
50
- const OWNER_ONLY_TOOL_NAMES = new Set(["whatsapp_login"]);
64
+ const OWNER_ONLY_TOOL_NAME_FALLBACKS = new Set(["whatsapp_login", "cron", "gateway"]);
51
65
  const TOOL_PROFILES = {
52
66
  minimal: {
53
67
  allow: ["session_status"],
@@ -71,31 +85,27 @@ export function normalizeToolName(name) {
71
85
  return TOOL_NAME_ALIASES[normalized] ?? normalized;
72
86
  }
73
87
  export function isOwnerOnlyToolName(name) {
74
- return OWNER_ONLY_TOOL_NAMES.has(normalizeToolName(name));
88
+ return OWNER_ONLY_TOOL_NAME_FALLBACKS.has(normalizeToolName(name));
89
+ }
90
+ function isOwnerOnlyTool(tool) {
91
+ return tool.ownerOnly === true || isOwnerOnlyToolName(tool.name);
75
92
  }
76
93
  export function applyOwnerOnlyToolPolicy(tools, senderIsOwner) {
77
94
  const withGuard = tools.map((tool) => {
78
- if (!isOwnerOnlyToolName(tool.name)) {
95
+ if (!isOwnerOnlyTool(tool)) {
79
96
  return tool;
80
97
  }
81
- if (senderIsOwner || !tool.execute) {
82
- return tool;
83
- }
84
- return {
85
- ...tool,
86
- execute: async () => {
87
- throw new Error("Tool restricted to owner senders.");
88
- },
89
- };
98
+ return wrapOwnerOnlyToolExecution(tool, senderIsOwner);
90
99
  });
91
100
  if (senderIsOwner) {
92
101
  return withGuard;
93
102
  }
94
- return withGuard.filter((tool) => !isOwnerOnlyToolName(tool.name));
103
+ return withGuard.filter((tool) => !isOwnerOnlyTool(tool));
95
104
  }
96
105
  export function normalizeToolList(list) {
97
- if (!list)
106
+ if (!list) {
98
107
  return [];
108
+ }
99
109
  return list.map(normalizeToolName).filter(Boolean);
100
110
  }
101
111
  export function expandToolGroups(list) {
@@ -114,14 +124,17 @@ export function expandToolGroups(list) {
114
124
  export function collectExplicitAllowlist(policies) {
115
125
  const entries = [];
116
126
  for (const policy of policies) {
117
- if (!policy?.allow)
127
+ if (!policy?.allow) {
118
128
  continue;
129
+ }
119
130
  for (const value of policy.allow) {
120
- if (typeof value !== "string")
131
+ if (typeof value !== "string") {
121
132
  continue;
133
+ }
122
134
  const trimmed = value.trim();
123
- if (trimmed)
135
+ if (trimmed) {
124
136
  entries.push(trimmed);
137
+ }
125
138
  }
126
139
  }
127
140
  return entries;
@@ -131,8 +144,9 @@ export function buildPluginToolGroups(params) {
131
144
  const byPlugin = new Map();
132
145
  for (const tool of params.tools) {
133
146
  const meta = params.toolMeta(tool);
134
- if (!meta)
147
+ if (!meta) {
135
148
  continue;
149
+ }
136
150
  const name = normalizeToolName(tool.name);
137
151
  all.push(name);
138
152
  const pluginId = meta.pluginId.toLowerCase();
@@ -143,8 +157,9 @@ export function buildPluginToolGroups(params) {
143
157
  return { all, byPlugin };
144
158
  }
145
159
  export function expandPluginGroups(list, groups) {
146
- if (!list || list.length === 0)
160
+ if (!list || list.length === 0) {
147
161
  return list;
162
+ }
148
163
  const expanded = [];
149
164
  for (const entry of list) {
150
165
  const normalized = normalizeToolName(entry);
@@ -167,8 +182,9 @@ export function expandPluginGroups(list, groups) {
167
182
  return Array.from(new Set(expanded));
168
183
  }
169
184
  export function expandPolicyWithPluginGroups(policy, groups) {
170
- if (!policy)
185
+ if (!policy) {
171
186
  return undefined;
187
+ }
172
188
  return {
173
189
  allow: expandPluginGroups(policy.allow, groups),
174
190
  deny: expandPluginGroups(policy.deny, groups),
@@ -187,13 +203,19 @@ export function stripPluginOnlyAllowlist(policy, groups, coreTools) {
187
203
  const unknownAllowlist = [];
188
204
  let hasCoreEntry = false;
189
205
  for (const entry of normalized) {
206
+ if (entry === "*") {
207
+ hasCoreEntry = true;
208
+ continue;
209
+ }
190
210
  const isPluginEntry = entry === "group:plugins" || pluginIds.has(entry) || pluginTools.has(entry);
191
211
  const expanded = expandToolGroups([entry]);
192
212
  const isCoreEntry = expanded.some((tool) => coreTools.has(tool));
193
- if (isCoreEntry)
213
+ if (isCoreEntry) {
194
214
  hasCoreEntry = true;
195
- if (!isCoreEntry && !isPluginEntry)
215
+ }
216
+ if (!isCoreEntry && !isPluginEntry) {
196
217
  unknownAllowlist.push(entry);
218
+ }
197
219
  }
198
220
  const strippedAllowlist = !hasCoreEntry;
199
221
  // When an allowlist contains only plugin tools, we strip it to avoid accidentally
@@ -209,13 +231,16 @@ export function stripPluginOnlyAllowlist(policy, groups, coreTools) {
209
231
  };
210
232
  }
211
233
  export function resolveToolProfilePolicy(profile) {
212
- if (!profile)
234
+ if (!profile) {
213
235
  return undefined;
236
+ }
214
237
  const resolved = TOOL_PROFILES[profile];
215
- if (!resolved)
238
+ if (!resolved) {
216
239
  return undefined;
217
- if (!resolved.allow && !resolved.deny)
240
+ }
241
+ if (!resolved.allow && !resolved.deny) {
218
242
  return undefined;
243
+ }
219
244
  return {
220
245
  allow: resolved.allow ? [...resolved.allow] : undefined,
221
246
  deny: resolved.deny ? [...resolved.deny] : undefined,
@@ -1,14 +1,35 @@
1
- import { browserCloseTab, browserFocusTab, browserOpenTab, browserProfiles, browserSnapshot, browserStart, browserStatus, browserStop, browserTabs, } from "../../browser/client.js";
2
- import { browserAct, browserArmDialog, browserArmFileChooser, browserConsoleMessages, browserNavigate, browserPdfSave, browserScreenshotAction, } from "../../browser/client-actions.js";
3
1
  import crypto from "node:crypto";
2
+ import { browserAct, browserArmDialog, browserArmFileChooser, browserConsoleMessages, browserNavigate, browserPdfSave, browserScreenshotAction, } from "../../browser/client-actions.js";
3
+ import { browserCloseTab, browserFocusTab, browserOpenTab, browserProfiles, browserSnapshot, browserStart, browserStatus, browserStop, browserTabs, } from "../../browser/client.js";
4
4
  import { resolveBrowserConfig } from "../../browser/config.js";
5
5
  import { DEFAULT_AI_SNAPSHOT_MAX_CHARS } from "../../browser/constants.js";
6
+ import { DEFAULT_UPLOAD_DIR, resolveExistingPathsWithinRoot } from "../../browser/paths.js";
7
+ import { applyBrowserProxyPaths, persistBrowserProxyFiles } from "../../browser/proxy-files.js";
6
8
  import { loadConfig } from "../../config/config.js";
7
- import { saveMediaBuffer } from "../../media/store.js";
8
- import { listNodes, resolveNodeIdFromList } from "./nodes-utils.js";
9
+ import { wrapExternalContent } from "../../security/external-content.js";
9
10
  import { BrowserToolSchema } from "./browser-tool.schema.js";
10
11
  import { imageResultFromFile, jsonResult, readStringParam } from "./common.js";
11
12
  import { callGatewayTool } from "./gateway.js";
13
+ import { listNodes, resolveNodeIdFromList } from "./nodes-utils.js";
14
+ function wrapBrowserExternalJson(params) {
15
+ const extractedText = JSON.stringify(params.payload, null, 2);
16
+ const wrappedText = wrapExternalContent(extractedText, {
17
+ source: "browser",
18
+ includeWarning: params.includeWarning ?? true,
19
+ });
20
+ return {
21
+ wrappedText,
22
+ safeDetails: {
23
+ ok: true,
24
+ externalContent: {
25
+ untrusted: true,
26
+ source: "browser",
27
+ kind: params.kind,
28
+ wrapped: true,
29
+ },
30
+ },
31
+ };
32
+ }
12
33
  const DEFAULT_BROWSER_PROXY_TIMEOUT_MS = 20_000;
13
34
  function isBrowserNode(node) {
14
35
  const caps = Array.isArray(node.caps) ? node.caps : [];
@@ -28,8 +49,9 @@ async function resolveBrowserNodeTarget(params) {
28
49
  if (params.sandboxBridgeUrl?.trim() && params.target !== "node" && !params.requestedNode) {
29
50
  return null;
30
51
  }
31
- if (params.target && params.target !== "node")
52
+ if (params.target && params.target !== "node") {
32
53
  return null;
54
+ }
33
55
  if (mode === "manual" && params.target !== "node" && !params.requestedNode) {
34
56
  return null;
35
57
  }
@@ -54,8 +76,9 @@ async function resolveBrowserNodeTarget(params) {
54
76
  }
55
77
  throw new Error(`Multiple browser-capable nodes connected (${browserNodes.length}). Set gateway.nodes.browser.node or pass node=<id>.`);
56
78
  }
57
- if (mode === "manual")
79
+ if (mode === "manual") {
58
80
  return null;
81
+ }
59
82
  if (browserNodes.length === 1) {
60
83
  const node = browserNodes[0];
61
84
  return { nodeId: node.nodeId, label: node.displayName ?? node.remoteIp ?? node.nodeId };
@@ -66,7 +89,7 @@ async function callBrowserProxy(params) {
66
89
  const gatewayTimeoutMs = typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs)
67
90
  ? Math.max(1, Math.floor(params.timeoutMs))
68
91
  : DEFAULT_BROWSER_PROXY_TIMEOUT_MS;
69
- const payload = (await callGatewayTool("node.invoke", { timeoutMs: gatewayTimeoutMs }, {
92
+ const payload = await callGatewayTool("node.invoke", { timeoutMs: gatewayTimeoutMs }, {
70
93
  nodeId: params.nodeId,
71
94
  command: "browser.proxy",
72
95
  params: {
@@ -78,44 +101,21 @@ async function callBrowserProxy(params) {
78
101
  profile: params.profile,
79
102
  },
80
103
  idempotencyKey: crypto.randomUUID(),
81
- }));
104
+ });
82
105
  const parsed = payload?.payload ??
83
106
  (typeof payload?.payloadJSON === "string" && payload.payloadJSON
84
107
  ? JSON.parse(payload.payloadJSON)
85
108
  : null);
86
- if (!parsed || typeof parsed !== "object") {
109
+ if (!parsed || typeof parsed !== "object" || !("result" in parsed)) {
87
110
  throw new Error("browser proxy failed");
88
111
  }
89
112
  return parsed;
90
113
  }
91
114
  async function persistProxyFiles(files) {
92
- if (!files || files.length === 0)
93
- return new Map();
94
- const mapping = new Map();
95
- for (const file of files) {
96
- const buffer = Buffer.from(file.base64, "base64");
97
- const saved = await saveMediaBuffer(buffer, file.mimeType, "browser", buffer.byteLength);
98
- mapping.set(file.path, saved.path);
99
- }
100
- return mapping;
115
+ return await persistBrowserProxyFiles(files);
101
116
  }
102
117
  function applyProxyPaths(result, mapping) {
103
- if (!result || typeof result !== "object")
104
- return;
105
- const obj = result;
106
- if (typeof obj.path === "string" && mapping.has(obj.path)) {
107
- obj.path = mapping.get(obj.path);
108
- }
109
- if (typeof obj.imagePath === "string" && mapping.has(obj.imagePath)) {
110
- obj.imagePath = mapping.get(obj.imagePath);
111
- }
112
- const download = obj.download;
113
- if (download && typeof download === "object") {
114
- const d = download;
115
- if (typeof d.path === "string" && mapping.has(d.path)) {
116
- d.path = mapping.get(d.path);
117
- }
118
- }
118
+ applyBrowserProxyPaths(result, mapping);
119
119
  }
120
120
  function resolveBrowserBaseUrl(params) {
121
121
  const cfg = loadConfig();
@@ -143,11 +143,11 @@ export function createBrowserTool(opts) {
143
143
  label: "Browser",
144
144
  name: "browser",
145
145
  description: [
146
- "Control the browser via Poolbot's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions).",
146
+ "Control the browser via Pool Bot's browser control server (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions).",
147
147
  'Profiles: use profile="chrome" for Chrome extension relay takeover (your existing Chrome tabs). Use profile="clawd" for the isolated clawd-managed browser.',
148
- 'If the user mentions the Chrome extension / Browser Relay / toolbar button / attach tab”, ALWAYS use profile="chrome" (do not ask which profile).',
148
+ 'If the user mentions the Chrome extension / Browser Relay / toolbar button / "attach tab", ALWAYS use profile="chrome" (do not ask which profile).',
149
149
  'When a node-hosted browser proxy is available, the tool may auto-route to it. Pin a node with node=<id|name> or target="node".',
150
- "Chrome extension relay needs an attached tab: user must click the Poolbot Browser Relay toolbar icon on the tab (badge ON). If no tab is connected, ask them to attach it.",
150
+ "Chrome extension relay needs an attached tab: user must click the Pool Bot Browser Relay toolbar icon on the tab (badge ON). If no tab is connected, ask them to attach it.",
151
151
  "When using refs from snapshot (e.g. e12), keep the same tab: prefer passing targetId from the snapshot response into subsequent actions (act/click/type/etc).",
152
152
  'For stable, self-resolving refs across calls, use snapshot with refs="aria" (Playwright aria-ref ids). Default refs="role" are role+name-based.',
153
153
  "Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
@@ -254,9 +254,28 @@ export function createBrowserTool(opts) {
254
254
  profile,
255
255
  });
256
256
  const tabs = result.tabs ?? [];
257
- return jsonResult({ tabs });
257
+ const wrapped = wrapBrowserExternalJson({
258
+ kind: "tabs",
259
+ payload: { tabs },
260
+ includeWarning: false,
261
+ });
262
+ return {
263
+ content: [{ type: "text", text: wrapped.wrappedText }],
264
+ details: { ...wrapped.safeDetails, tabCount: tabs.length },
265
+ };
266
+ }
267
+ {
268
+ const tabs = await browserTabs(baseUrl, { profile });
269
+ const wrapped = wrapBrowserExternalJson({
270
+ kind: "tabs",
271
+ payload: { tabs },
272
+ includeWarning: false,
273
+ });
274
+ return {
275
+ content: [{ type: "text", text: wrapped.wrappedText }],
276
+ details: { ...wrapped.safeDetails, tabCount: tabs.length },
277
+ };
258
278
  }
259
- return jsonResult({ tabs: await browserTabs(baseUrl, { profile }) });
260
279
  case "open": {
261
280
  const targetUrl = readStringParam(params, "targetUrl", {
262
281
  required: true,
@@ -305,10 +324,12 @@ export function createBrowserTool(opts) {
305
324
  });
306
325
  return jsonResult(result);
307
326
  }
308
- if (targetId)
327
+ if (targetId) {
309
328
  await browserCloseTab(baseUrl, targetId, { profile });
310
- else
329
+ }
330
+ else {
311
331
  await browserAct(baseUrl, { kind: "close" }, { profile });
332
+ }
312
333
  return jsonResult({ ok: true });
313
334
  }
314
335
  case "snapshot": {
@@ -383,20 +404,68 @@ export function createBrowserTool(opts) {
383
404
  profile,
384
405
  });
385
406
  if (snapshot.format === "ai") {
407
+ const extractedText = snapshot.snapshot ?? "";
408
+ const wrappedSnapshot = wrapExternalContent(extractedText, {
409
+ source: "browser",
410
+ includeWarning: true,
411
+ });
412
+ const safeDetails = {
413
+ ok: true,
414
+ format: snapshot.format,
415
+ targetId: snapshot.targetId,
416
+ url: snapshot.url,
417
+ truncated: snapshot.truncated,
418
+ stats: snapshot.stats,
419
+ refs: snapshot.refs ? Object.keys(snapshot.refs).length : undefined,
420
+ labels: snapshot.labels,
421
+ labelsCount: snapshot.labelsCount,
422
+ labelsSkipped: snapshot.labelsSkipped,
423
+ imagePath: snapshot.imagePath,
424
+ imageType: snapshot.imageType,
425
+ externalContent: {
426
+ untrusted: true,
427
+ source: "browser",
428
+ kind: "snapshot",
429
+ format: "ai",
430
+ wrapped: true,
431
+ },
432
+ };
386
433
  if (labels && snapshot.imagePath) {
387
434
  return await imageResultFromFile({
388
435
  label: "browser:snapshot",
389
436
  path: snapshot.imagePath,
390
- extraText: snapshot.snapshot,
391
- details: snapshot,
437
+ extraText: wrappedSnapshot,
438
+ details: safeDetails,
392
439
  });
393
440
  }
394
441
  return {
395
- content: [{ type: "text", text: snapshot.snapshot }],
396
- details: snapshot,
442
+ content: [{ type: "text", text: wrappedSnapshot }],
443
+ details: safeDetails,
444
+ };
445
+ }
446
+ {
447
+ const wrapped = wrapBrowserExternalJson({
448
+ kind: "snapshot",
449
+ payload: snapshot,
450
+ });
451
+ return {
452
+ content: [{ type: "text", text: wrapped.wrappedText }],
453
+ details: {
454
+ ...wrapped.safeDetails,
455
+ format: "aria",
456
+ targetId: snapshot.targetId,
457
+ url: snapshot.url,
458
+ nodeCount: snapshot.nodes.length,
459
+ externalContent: {
460
+ untrusted: true,
461
+ source: "browser",
462
+ kind: "snapshot",
463
+ format: "aria",
464
+ wrapped: true,
465
+ },
466
+ },
397
467
  };
398
468
  }
399
- return jsonResult(snapshot);
400
469
  }
401
470
  case "screenshot": {
402
471
  const targetId = readStringParam(params, "targetId");
@@ -458,7 +527,7 @@ export function createBrowserTool(opts) {
458
527
  const level = typeof params.level === "string" ? params.level.trim() : undefined;
459
528
  const targetId = typeof params.targetId === "string" ? params.targetId.trim() : undefined;
460
529
  if (proxyRequest) {
461
- const result = await proxyRequest({
530
+ const result = (await proxyRequest({
462
531
  method: "GET",
463
532
  path: "/console",
464
533
  profile,
@@ -466,10 +535,37 @@ export function createBrowserTool(opts) {
466
535
  level,
467
536
  targetId,
468
537
  },
538
+ }));
539
+ const wrapped = wrapBrowserExternalJson({
540
+ kind: "console",
541
+ payload: result,
542
+ includeWarning: false,
543
+ });
544
+ return {
545
+ content: [{ type: "text", text: wrapped.wrappedText }],
546
+ details: {
547
+ ...wrapped.safeDetails,
548
+ targetId: typeof result.targetId === "string" ? result.targetId : undefined,
549
+ messageCount: Array.isArray(result.messages) ? result.messages.length : undefined,
550
+ },
551
+ };
552
+ }
553
+ {
554
+ const result = await browserConsoleMessages(baseUrl, { level, targetId, profile });
555
+ const wrapped = wrapBrowserExternalJson({
556
+ kind: "console",
557
+ payload: result,
558
+ includeWarning: false,
469
559
  });
470
- return jsonResult(result);
560
+ return {
561
+ content: [{ type: "text", text: wrapped.wrappedText }],
562
+ details: {
563
+ ...wrapped.safeDetails,
564
+ targetId: result.targetId,
565
+ messageCount: result.messages.length,
566
+ },
567
+ };
471
568
  }
472
- return jsonResult(await browserConsoleMessages(baseUrl, { level, targetId, profile }));
473
569
  }
474
570
  case "pdf": {
475
571
  const targetId = typeof params.targetId === "string" ? params.targetId.trim() : undefined;
@@ -488,8 +584,18 @@ export function createBrowserTool(opts) {
488
584
  }
489
585
  case "upload": {
490
586
  const paths = Array.isArray(params.paths) ? params.paths.map((p) => String(p)) : [];
491
- if (paths.length === 0)
587
+ if (paths.length === 0) {
492
588
  throw new Error("paths required");
589
+ }
590
+ const uploadPathsResult = await resolveExistingPathsWithinRoot({
591
+ rootDir: DEFAULT_UPLOAD_DIR,
592
+ requestedPaths: paths,
593
+ scopeLabel: `uploads directory (${DEFAULT_UPLOAD_DIR})`,
594
+ });
595
+ if (!uploadPathsResult.ok) {
596
+ throw new Error(uploadPathsResult.error);
597
+ }
598
+ const normalizedPaths = uploadPathsResult.paths;
493
599
  const ref = readStringParam(params, "ref");
494
600
  const inputRef = readStringParam(params, "inputRef");
495
601
  const element = readStringParam(params, "element");
@@ -503,7 +609,7 @@ export function createBrowserTool(opts) {
503
609
  path: "/hooks/file-chooser",
504
610
  profile,
505
611
  body: {
506
- paths,
612
+ paths: normalizedPaths,
507
613
  ref,
508
614
  inputRef,
509
615
  element,
@@ -514,7 +620,7 @@ export function createBrowserTool(opts) {
514
620
  return jsonResult(result);
515
621
  }
516
622
  return jsonResult(await browserArmFileChooser(baseUrl, {
517
- paths,
623
+ paths: normalizedPaths,
518
624
  ref,
519
625
  inputRef,
520
626
  element,
@@ -581,9 +687,9 @@ export function createBrowserTool(opts) {
581
687
  })).tabs ?? [])
582
688
  : await browserTabs(baseUrl, { profile }).catch(() => []);
583
689
  if (!tabs.length) {
584
- throw new Error("No Chrome tabs are attached via the Poolbot Browser Relay extension. Click the toolbar icon on the tab you want to control (badge ON), then retry.");
690
+ throw new Error("No Chrome tabs are attached via the Pool Bot Browser Relay extension. Click the toolbar icon on the tab you want to control (badge ON), then retry.", { cause: err });
585
691
  }
586
- throw new Error(`Chrome tab not found (stale targetId?). Run action=tabs profile="chrome" and use one of the returned targetIds.`);
692
+ throw new Error(`Chrome tab not found (stale targetId?). Run action=tabs profile="chrome" and use one of the returned targetIds.`, { cause: err });
587
693
  }
588
694
  throw err;
589
695
  }
@@ -1,8 +1,12 @@
1
1
  import crypto from "node:crypto";
2
2
  import fs from "node:fs/promises";
3
+ import path from "node:path";
3
4
  import { Type } from "@sinclair/typebox";
4
5
  import { writeBase64ToFile } from "../../cli/nodes-camera.js";
5
6
  import { canvasSnapshotTempPath, parseCanvasSnapshotPayload } from "../../cli/nodes-canvas.js";
7
+ import { logVerbose, shouldLogVerbose } from "../../globals.js";
8
+ import { isInboundPathAllowed } from "../../media/inbound-path-policy.js";
9
+ import { getDefaultMediaLocalRoots } from "../../media/local-roots.js";
6
10
  import { imageMimeFromFormat } from "../../media/mime.js";
7
11
  import { resolveImageSanitizationLimits } from "../image-sanitization.js";
8
12
  import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
@@ -19,6 +23,28 @@ const CANVAS_ACTIONS = [
19
23
  "a2ui_reset",
20
24
  ];
21
25
  const CANVAS_SNAPSHOT_FORMATS = ["png", "jpg", "jpeg"];
26
+ async function readJsonlFromPath(jsonlPath) {
27
+ const trimmed = jsonlPath.trim();
28
+ if (!trimmed) {
29
+ return "";
30
+ }
31
+ const resolved = path.resolve(trimmed);
32
+ const roots = getDefaultMediaLocalRoots();
33
+ if (!isInboundPathAllowed({ filePath: resolved, roots })) {
34
+ if (shouldLogVerbose()) {
35
+ logVerbose(`Blocked canvas jsonlPath outside allowed roots: ${resolved}`);
36
+ }
37
+ throw new Error("jsonlPath outside allowed roots");
38
+ }
39
+ const canonical = await fs.realpath(resolved).catch(() => resolved);
40
+ if (!isInboundPathAllowed({ filePath: canonical, roots })) {
41
+ if (shouldLogVerbose()) {
42
+ logVerbose(`Blocked canvas jsonlPath outside allowed roots: ${canonical}`);
43
+ }
44
+ throw new Error("jsonlPath outside allowed roots");
45
+ }
46
+ return await fs.readFile(canonical, "utf8");
47
+ }
22
48
  // Flattened schema: runtime validates per-action requirements.
23
49
  const CanvasToolSchema = Type.Object({
24
50
  action: stringEnum(CANVAS_ACTIONS),
@@ -145,7 +171,7 @@ export function createCanvasTool(options) {
145
171
  const jsonl = typeof params.jsonl === "string" && params.jsonl.trim()
146
172
  ? params.jsonl
147
173
  : typeof params.jsonlPath === "string" && params.jsonlPath.trim()
148
- ? await fs.readFile(params.jsonlPath.trim(), "utf8")
174
+ ? await readJsonlFromPath(params.jsonlPath)
149
175
  : "";
150
176
  if (!jsonl.trim()) {
151
177
  throw new Error("jsonl or jsonlPath required");
@@ -1,6 +1,7 @@
1
1
  import fs from "node:fs/promises";
2
2
  import { detectMime } from "../../media/mime.js";
3
3
  import { sanitizeToolResultImages } from "../tool-images.js";
4
+ export const OWNER_ONLY_TOOL_ERROR = "Tool restricted to owner senders.";
4
5
  export class ToolInputError extends Error {
5
6
  status = 400;
6
7
  constructor(message) {
@@ -8,6 +9,13 @@ export class ToolInputError extends Error {
8
9
  this.name = "ToolInputError";
9
10
  }
10
11
  }
12
+ export class ToolAuthorizationError extends ToolInputError {
13
+ status = 403;
14
+ constructor(message) {
15
+ super(message);
16
+ this.name = "ToolAuthorizationError";
17
+ }
18
+ }
11
19
  export function createActionGate(actions) {
12
20
  return (key, defaultValue = true) => {
13
21
  const value = actions?.[key];
@@ -131,6 +139,17 @@ export function jsonResult(payload) {
131
139
  details: payload,
132
140
  };
133
141
  }
142
+ export function wrapOwnerOnlyToolExecution(tool, senderIsOwner) {
143
+ if (tool.ownerOnly !== true || senderIsOwner || !tool.execute) {
144
+ return tool;
145
+ }
146
+ return {
147
+ ...tool,
148
+ execute: async () => {
149
+ throw new Error(OWNER_ONLY_TOOL_ERROR);
150
+ },
151
+ };
152
+ }
134
153
  export async function imageResult(params) {
135
154
  const content = [
136
155
  {
@@ -162,3 +181,29 @@ export async function imageResultFromFile(params) {
162
181
  imageSanitization: params.imageSanitization,
163
182
  });
164
183
  }
184
+ /**
185
+ * Validate and parse an `availableTags` parameter from untrusted input.
186
+ * Returns `undefined` when the value is missing or not an array.
187
+ * Entries that lack a string `name` are silently dropped.
188
+ */
189
+ export function parseAvailableTags(raw) {
190
+ if (raw === undefined || raw === null) {
191
+ return undefined;
192
+ }
193
+ if (!Array.isArray(raw)) {
194
+ return undefined;
195
+ }
196
+ const result = raw
197
+ .filter((t) => typeof t === "object" && t !== null && typeof t.name === "string")
198
+ .map((t) => ({
199
+ ...(t.id !== undefined && typeof t.id === "string" ? { id: t.id } : {}),
200
+ name: t.name,
201
+ ...(typeof t.moderated === "boolean" ? { moderated: t.moderated } : {}),
202
+ ...(t.emoji_id === null || typeof t.emoji_id === "string" ? { emoji_id: t.emoji_id } : {}),
203
+ ...(t.emoji_name === null || typeof t.emoji_name === "string"
204
+ ? { emoji_name: t.emoji_name }
205
+ : {}),
206
+ }));
207
+ // Return undefined instead of empty array to avoid accidentally clearing all tags
208
+ return result.length ? result : undefined;
209
+ }
@@ -0,0 +1,12 @@
1
+ import { vi } from "vitest";
2
+ export const callGatewayMock = vi.fn();
3
+ vi.mock("../../gateway/call.js", () => ({
4
+ callGateway: (opts) => callGatewayMock(opts),
5
+ }));
6
+ vi.mock("../agent-scope.js", () => ({
7
+ resolveSessionAgentId: () => "agent-123",
8
+ }));
9
+ export function resetCronToolGatewayMock() {
10
+ callGatewayMock.mockReset();
11
+ callGatewayMock.mockResolvedValue({ ok: true });
12
+ }