@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,19 +1,24 @@
1
1
  import { createServer as createHttpServer, } from "node:http";
2
2
  import { createServer as createHttpsServer } from "node:https";
3
+ import { resolveAgentAvatar } from "../agents/identity-avatar.js";
3
4
  import { A2UI_PATH, CANVAS_HOST_PATH, CANVAS_WS_PATH, handleA2uiHttpRequest, } from "../canvas-host/a2ui.js";
4
5
  import { loadConfig } from "../config/config.js";
5
- import { resolveAgentAvatar } from "../agents/identity-avatar.js";
6
+ import { safeEqualSecret } from "../security/secret-equal.js";
6
7
  import { handleSlackHttpRequest } from "../slack/http/index.js";
7
- import { authorizeGatewayConnect, isLocalDirectRequest } from "./auth.js";
8
+ import { authorizeHttpGatewayConnect, isLocalDirectRequest, } from "./auth.js";
9
+ import { CANVAS_CAPABILITY_TTL_MS, normalizeCanvasScopedUrl } from "./canvas-capability.js";
8
10
  import { handleControlUiAvatarRequest, handleControlUiHttpRequest, } from "./control-ui.js";
9
- import { extractHookToken, getHookAgentPolicyError, getHookChannelError, isHookAgentAllowed, normalizeAgentPayload, normalizeHookHeaders, normalizeWakePayload, readJsonBody, resolveHookTargetAgentId, resolveHookChannel, resolveHookDeliver, } from "./hooks.js";
10
11
  import { applyHookMappings } from "./hooks-mapping.js";
11
- import { sendUnauthorized } from "./http-common.js";
12
- import { getBearerToken, getHeader } from "./http-utils.js";
13
- import { resolveGatewayClientIp } from "./net.js";
12
+ import { extractHookToken, getHookAgentPolicyError, getHookChannelError, isHookAgentAllowed, normalizeAgentPayload, normalizeHookHeaders, normalizeWakePayload, readJsonBody, resolveHookSessionKey, resolveHookTargetAgentId, resolveHookChannel, resolveHookDeliver, } from "./hooks.js";
13
+ import { sendGatewayAuthFailure, setDefaultSecurityHeaders } from "./http-common.js";
14
+ import { getBearerToken } from "./http-utils.js";
14
15
  import { handleOpenAiHttpRequest } from "./openai-http.js";
15
16
  import { handleOpenResponsesHttpRequest } from "./openresponses-http.js";
17
+ import { GATEWAY_CLIENT_MODES, normalizeGatewayClientMode } from "./protocol/client-info.js";
16
18
  import { handleToolsInvokeHttpRequest } from "./tools-invoke-http.js";
19
+ const HOOK_AUTH_FAILURE_LIMIT = 20;
20
+ const HOOK_AUTH_FAILURE_WINDOW_MS = 60_000;
21
+ const HOOK_AUTH_FAILURE_TRACK_MAX = 2048;
17
22
  function sendJson(res, status, body) {
18
23
  res.statusCode = status;
19
24
  res.setHeader("Content-Type", "application/json; charset=utf-8");
@@ -26,67 +31,167 @@ function isCanvasPath(pathname) {
26
31
  pathname.startsWith(`${CANVAS_HOST_PATH}/`) ||
27
32
  pathname === CANVAS_WS_PATH);
28
33
  }
29
- function hasAuthorizedWsClientForIp(clients, clientIp) {
34
+ function isNodeWsClient(client) {
35
+ if (client.connect.role === "node") {
36
+ return true;
37
+ }
38
+ return normalizeGatewayClientMode(client.connect.client.mode) === GATEWAY_CLIENT_MODES.NODE;
39
+ }
40
+ function hasAuthorizedNodeWsClientForCanvasCapability(clients, capability) {
41
+ const nowMs = Date.now();
30
42
  for (const client of clients) {
31
- if (client.clientIp && client.clientIp === clientIp) {
43
+ if (!isNodeWsClient(client)) {
44
+ continue;
45
+ }
46
+ if (!client.canvasCapability || !client.canvasCapabilityExpiresAtMs) {
47
+ continue;
48
+ }
49
+ if (client.canvasCapabilityExpiresAtMs <= nowMs) {
50
+ continue;
51
+ }
52
+ if (safeEqualSecret(client.canvasCapability, capability)) {
53
+ // Sliding expiration while the connected node keeps using canvas.
54
+ client.canvasCapabilityExpiresAtMs = nowMs + CANVAS_CAPABILITY_TTL_MS;
32
55
  return true;
33
56
  }
34
57
  }
35
58
  return false;
36
59
  }
37
60
  async function authorizeCanvasRequest(params) {
38
- const { req, auth, trustedProxies, clients } = params;
39
- if (isLocalDirectRequest(req, trustedProxies)) {
40
- return true;
61
+ const { req, auth, trustedProxies, allowRealIpFallback, clients, canvasCapability, malformedScopedPath, rateLimiter, } = params;
62
+ if (malformedScopedPath) {
63
+ return { ok: false, reason: "unauthorized" };
41
64
  }
65
+ if (isLocalDirectRequest(req, trustedProxies, allowRealIpFallback)) {
66
+ return { ok: true };
67
+ }
68
+ let lastAuthFailure = null;
42
69
  const token = getBearerToken(req);
43
70
  if (token) {
44
- const authResult = await authorizeGatewayConnect({
71
+ const authResult = await authorizeHttpGatewayConnect({
45
72
  auth: { ...auth, allowTailscale: false },
46
73
  connectAuth: { token, password: token },
47
74
  req,
48
75
  trustedProxies,
76
+ allowRealIpFallback,
77
+ rateLimiter,
49
78
  });
50
79
  if (authResult.ok) {
51
- return true;
80
+ return authResult;
52
81
  }
82
+ lastAuthFailure = authResult;
53
83
  }
54
- const clientIp = resolveGatewayClientIp({
55
- remoteAddr: req.socket?.remoteAddress ?? "",
56
- forwardedFor: getHeader(req, "x-forwarded-for"),
57
- realIp: getHeader(req, "x-real-ip"),
58
- trustedProxies,
59
- });
60
- if (!clientIp) {
61
- return false;
84
+ if (canvasCapability && hasAuthorizedNodeWsClientForCanvasCapability(clients, canvasCapability)) {
85
+ return { ok: true };
86
+ }
87
+ return lastAuthFailure ?? { ok: false, reason: "unauthorized" };
88
+ }
89
+ function writeUpgradeAuthFailure(socket, auth) {
90
+ if (auth.rateLimited) {
91
+ const retryAfterSeconds = auth.retryAfterMs && auth.retryAfterMs > 0 ? Math.ceil(auth.retryAfterMs / 1000) : undefined;
92
+ socket.write([
93
+ "HTTP/1.1 429 Too Many Requests",
94
+ retryAfterSeconds ? `Retry-After: ${retryAfterSeconds}` : undefined,
95
+ "Content-Type: application/json; charset=utf-8",
96
+ "Connection: close",
97
+ "",
98
+ JSON.stringify({
99
+ error: {
100
+ message: "Too many failed authentication attempts. Please try again later.",
101
+ type: "rate_limited",
102
+ },
103
+ }),
104
+ ]
105
+ .filter(Boolean)
106
+ .join("\r\n"));
107
+ return;
62
108
  }
63
- return hasAuthorizedWsClientForIp(clients, clientIp);
109
+ socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
64
110
  }
65
111
  export function createHooksRequestHandler(opts) {
66
112
  const { getHooksConfig, bindHost, port, logHooks, dispatchAgentHook, dispatchWakeHook } = opts;
113
+ const hookAuthFailures = new Map();
114
+ const resolveHookClientKey = (req) => {
115
+ return req.socket?.remoteAddress?.trim() || "unknown";
116
+ };
117
+ const recordHookAuthFailure = (clientKey, nowMs) => {
118
+ if (!hookAuthFailures.has(clientKey) && hookAuthFailures.size >= HOOK_AUTH_FAILURE_TRACK_MAX) {
119
+ // Prune expired entries instead of clearing all state.
120
+ for (const [key, entry] of hookAuthFailures) {
121
+ if (nowMs - entry.windowStartedAtMs >= HOOK_AUTH_FAILURE_WINDOW_MS) {
122
+ hookAuthFailures.delete(key);
123
+ }
124
+ }
125
+ // If still at capacity after pruning, drop the oldest half.
126
+ if (hookAuthFailures.size >= HOOK_AUTH_FAILURE_TRACK_MAX) {
127
+ let toRemove = Math.floor(hookAuthFailures.size / 2);
128
+ for (const key of hookAuthFailures.keys()) {
129
+ if (toRemove <= 0) {
130
+ break;
131
+ }
132
+ hookAuthFailures.delete(key);
133
+ toRemove--;
134
+ }
135
+ }
136
+ }
137
+ const current = hookAuthFailures.get(clientKey);
138
+ const expired = !current || nowMs - current.windowStartedAtMs >= HOOK_AUTH_FAILURE_WINDOW_MS;
139
+ const next = expired
140
+ ? { count: 1, windowStartedAtMs: nowMs }
141
+ : { count: current.count + 1, windowStartedAtMs: current.windowStartedAtMs };
142
+ // Delete-before-set refreshes Map insertion order so recently-active
143
+ // clients are not evicted before dormant ones during oldest-half eviction.
144
+ if (hookAuthFailures.has(clientKey)) {
145
+ hookAuthFailures.delete(clientKey);
146
+ }
147
+ hookAuthFailures.set(clientKey, next);
148
+ if (next.count <= HOOK_AUTH_FAILURE_LIMIT) {
149
+ return { throttled: false };
150
+ }
151
+ const retryAfterMs = Math.max(1, next.windowStartedAtMs + HOOK_AUTH_FAILURE_WINDOW_MS - nowMs);
152
+ return {
153
+ throttled: true,
154
+ retryAfterSeconds: Math.ceil(retryAfterMs / 1000),
155
+ };
156
+ };
157
+ const clearHookAuthFailure = (clientKey) => {
158
+ hookAuthFailures.delete(clientKey);
159
+ };
67
160
  return async (req, res) => {
68
161
  const hooksConfig = getHooksConfig();
69
- if (!hooksConfig)
162
+ if (!hooksConfig) {
70
163
  return false;
164
+ }
71
165
  const url = new URL(req.url ?? "/", `http://${bindHost}:${port}`);
72
166
  const basePath = hooksConfig.basePath;
73
167
  if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) {
74
168
  return false;
75
169
  }
76
- // pool-bot keeps the deprecation-warning approach for query-param tokens
77
- // (upstream hard-rejects; we warn and allow for now)
78
- const { token, fromQuery } = extractHookToken(req, url);
79
- if (!token || token !== hooksConfig.token) {
170
+ if (url.searchParams.has("token")) {
171
+ res.statusCode = 400;
172
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
173
+ res.end("Hook token must be provided via Authorization: Bearer <token> or X-Pool Bot-Token header (query parameters are not allowed).");
174
+ return true;
175
+ }
176
+ const { token } = extractHookToken(req);
177
+ const clientKey = resolveHookClientKey(req);
178
+ if (!safeEqualSecret(token, hooksConfig.token)) {
179
+ const throttle = recordHookAuthFailure(clientKey, Date.now());
180
+ if (throttle.throttled) {
181
+ const retryAfter = throttle.retryAfterSeconds ?? 1;
182
+ res.statusCode = 429;
183
+ res.setHeader("Retry-After", String(retryAfter));
184
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
185
+ res.end("Too Many Requests");
186
+ logHooks.warn(`hook auth throttled for ${clientKey}; retry-after=${retryAfter}s`);
187
+ return true;
188
+ }
80
189
  res.statusCode = 401;
81
190
  res.setHeader("Content-Type", "text/plain; charset=utf-8");
82
191
  res.end("Unauthorized");
83
192
  return true;
84
193
  }
85
- if (fromQuery) {
86
- logHooks.warn("Hook token provided via query parameter is deprecated for security reasons. " +
87
- "Tokens in URLs appear in logs, browser history, and referrer headers. " +
88
- "Use Authorization: Bearer <token> or X-Poolbot-Token header instead.");
89
- }
194
+ clearHookAuthFailure(clientKey);
90
195
  if (req.method !== "POST") {
91
196
  res.statusCode = 405;
92
197
  res.setHeader("Allow", "POST");
@@ -103,7 +208,11 @@ export function createHooksRequestHandler(opts) {
103
208
  }
104
209
  const body = await readJsonBody(req, hooksConfig.maxBodyBytes);
105
210
  if (!body.ok) {
106
- const status = body.error === "payload too large" ? 413 : 400;
211
+ const status = body.error === "payload too large"
212
+ ? 413
213
+ : body.error === "request body timeout"
214
+ ? 408
215
+ : 400;
107
216
  sendJson(res, status, { ok: false, error: body.error });
108
217
  return true;
109
218
  }
@@ -129,8 +238,18 @@ export function createHooksRequestHandler(opts) {
129
238
  sendJson(res, 400, { ok: false, error: getHookAgentPolicyError() });
130
239
  return true;
131
240
  }
241
+ const sessionKey = resolveHookSessionKey({
242
+ hooksConfig,
243
+ source: "request",
244
+ sessionKey: normalized.value.sessionKey,
245
+ });
246
+ if (!sessionKey.ok) {
247
+ sendJson(res, 400, { ok: false, error: sessionKey.error });
248
+ return true;
249
+ }
132
250
  const runId = dispatchAgentHook({
133
251
  ...normalized.value,
252
+ sessionKey: sessionKey.value,
134
253
  agentId: resolveHookTargetAgentId(hooksConfig, normalized.value.agentId),
135
254
  });
136
255
  sendJson(res, 202, { ok: true, runId });
@@ -171,12 +290,21 @@ export function createHooksRequestHandler(opts) {
171
290
  sendJson(res, 400, { ok: false, error: getHookAgentPolicyError() });
172
291
  return true;
173
292
  }
293
+ const sessionKey = resolveHookSessionKey({
294
+ hooksConfig,
295
+ source: "mapping",
296
+ sessionKey: mapped.action.sessionKey,
297
+ });
298
+ if (!sessionKey.ok) {
299
+ sendJson(res, 400, { ok: false, error: sessionKey.error });
300
+ return true;
301
+ }
174
302
  const runId = dispatchAgentHook({
175
303
  message: mapped.action.message,
176
304
  name: mapped.action.name ?? "Hook",
177
305
  agentId: resolveHookTargetAgentId(hooksConfig, mapped.action.agentId),
178
306
  wakeMode: mapped.action.wakeMode,
179
- sessionKey: mapped.action.sessionKey ?? "",
307
+ sessionKey: sessionKey.value,
180
308
  deliver: resolveHookDeliver(mapped.action.deliver),
181
309
  channel,
182
310
  to: mapped.action.to,
@@ -202,7 +330,7 @@ export function createHooksRequestHandler(opts) {
202
330
  };
203
331
  }
204
332
  export function createGatewayHttpServer(opts) {
205
- const { canvasHost, clients, controlUiEnabled, controlUiBasePath, controlUiRoot, openAiChatCompletionsEnabled, openResponsesEnabled, openResponsesConfig, handleHooksRequest, handlePluginRequest, resolvedAuth, } = opts;
333
+ const { canvasHost, clients, controlUiEnabled, controlUiBasePath, controlUiRoot, openAiChatCompletionsEnabled, openResponsesEnabled, openResponsesConfig, handleHooksRequest, handlePluginRequest, resolvedAuth, rateLimiter, } = opts;
206
334
  const httpServer = opts.tlsOptions
207
335
  ? createHttpsServer(opts.tlsOptions, (req, res) => {
208
336
  void handleRequest(req, res);
@@ -211,69 +339,120 @@ export function createGatewayHttpServer(opts) {
211
339
  void handleRequest(req, res);
212
340
  });
213
341
  async function handleRequest(req, res) {
342
+ setDefaultSecurityHeaders(res);
214
343
  // Don't interfere with WebSocket upgrades; ws handles the 'upgrade' event.
215
- if (String(req.headers.upgrade ?? "").toLowerCase() === "websocket")
344
+ if (String(req.headers.upgrade ?? "").toLowerCase() === "websocket") {
216
345
  return;
346
+ }
217
347
  try {
218
348
  const configSnapshot = loadConfig();
219
349
  const trustedProxies = configSnapshot.gateway?.trustedProxies ?? [];
220
- if (await handleHooksRequest(req, res))
350
+ const allowRealIpFallback = configSnapshot.gateway?.allowRealIpFallback === true;
351
+ const scopedCanvas = normalizeCanvasScopedUrl(req.url ?? "/");
352
+ if (scopedCanvas.malformedScopedPath) {
353
+ sendGatewayAuthFailure(res, { ok: false, reason: "unauthorized" });
354
+ return;
355
+ }
356
+ if (scopedCanvas.rewrittenUrl) {
357
+ req.url = scopedCanvas.rewrittenUrl;
358
+ }
359
+ const requestPath = new URL(req.url ?? "/", "http://localhost").pathname;
360
+ if (await handleHooksRequest(req, res)) {
221
361
  return;
362
+ }
222
363
  if (await handleToolsInvokeHttpRequest(req, res, {
223
364
  auth: resolvedAuth,
224
365
  trustedProxies,
225
- }))
226
- return;
227
- if (await handleSlackHttpRequest(req, res))
366
+ allowRealIpFallback,
367
+ rateLimiter,
368
+ })) {
228
369
  return;
229
- if (handlePluginRequest && (await handlePluginRequest(req, res)))
370
+ }
371
+ if (await handleSlackHttpRequest(req, res)) {
230
372
  return;
373
+ }
374
+ if (handlePluginRequest) {
375
+ // Channel HTTP endpoints are gateway-auth protected by default.
376
+ // Non-channel plugin routes remain plugin-owned and must enforce
377
+ // their own auth when exposing sensitive functionality.
378
+ if (requestPath.startsWith("/api/channels/")) {
379
+ const token = getBearerToken(req);
380
+ const authResult = await authorizeHttpGatewayConnect({
381
+ auth: resolvedAuth,
382
+ connectAuth: token ? { token, password: token } : null,
383
+ req,
384
+ trustedProxies,
385
+ allowRealIpFallback,
386
+ rateLimiter,
387
+ });
388
+ if (!authResult.ok) {
389
+ sendGatewayAuthFailure(res, authResult);
390
+ return;
391
+ }
392
+ }
393
+ if (await handlePluginRequest(req, res)) {
394
+ return;
395
+ }
396
+ }
231
397
  if (openResponsesEnabled) {
232
398
  if (await handleOpenResponsesHttpRequest(req, res, {
233
399
  auth: resolvedAuth,
234
400
  config: openResponsesConfig,
235
401
  trustedProxies,
236
- }))
402
+ allowRealIpFallback,
403
+ rateLimiter,
404
+ })) {
237
405
  return;
406
+ }
238
407
  }
239
408
  if (openAiChatCompletionsEnabled) {
240
409
  if (await handleOpenAiHttpRequest(req, res, {
241
410
  auth: resolvedAuth,
242
411
  trustedProxies,
243
- }))
412
+ allowRealIpFallback,
413
+ rateLimiter,
414
+ })) {
244
415
  return;
416
+ }
245
417
  }
246
418
  if (canvasHost) {
247
- const url = new URL(req.url ?? "/", "http://localhost");
248
- if (isCanvasPath(url.pathname)) {
419
+ if (isCanvasPath(requestPath)) {
249
420
  const ok = await authorizeCanvasRequest({
250
421
  req,
251
422
  auth: resolvedAuth,
252
423
  trustedProxies,
424
+ allowRealIpFallback,
253
425
  clients,
426
+ canvasCapability: scopedCanvas.capability,
427
+ malformedScopedPath: scopedCanvas.malformedScopedPath,
428
+ rateLimiter,
254
429
  });
255
- if (!ok) {
256
- sendUnauthorized(res);
430
+ if (!ok.ok) {
431
+ sendGatewayAuthFailure(res, ok);
257
432
  return;
258
433
  }
259
434
  }
260
- if (await handleA2uiHttpRequest(req, res))
435
+ if (await handleA2uiHttpRequest(req, res)) {
261
436
  return;
262
- if (await canvasHost.handleHttpRequest(req, res))
437
+ }
438
+ if (await canvasHost.handleHttpRequest(req, res)) {
263
439
  return;
440
+ }
264
441
  }
265
442
  if (controlUiEnabled) {
266
443
  if (handleControlUiAvatarRequest(req, res, {
267
444
  basePath: controlUiBasePath,
268
445
  resolveAvatar: (agentId) => resolveAgentAvatar(configSnapshot, agentId),
269
- }))
446
+ })) {
270
447
  return;
448
+ }
271
449
  if (handleControlUiHttpRequest(req, res, {
272
450
  basePath: controlUiBasePath,
273
451
  config: configSnapshot,
274
452
  root: controlUiRoot,
275
- }))
453
+ })) {
276
454
  return;
455
+ }
277
456
  }
278
457
  res.statusCode = 404;
279
458
  res.setHeader("Content-Type", "text/plain; charset=utf-8");
@@ -288,22 +467,36 @@ export function createGatewayHttpServer(opts) {
288
467
  return httpServer;
289
468
  }
290
469
  export function attachGatewayUpgradeHandler(opts) {
291
- const { httpServer, wss, canvasHost, clients, resolvedAuth } = opts;
470
+ const { httpServer, wss, canvasHost, clients, resolvedAuth, rateLimiter } = opts;
292
471
  httpServer.on("upgrade", (req, socket, head) => {
293
472
  void (async () => {
473
+ const scopedCanvas = normalizeCanvasScopedUrl(req.url ?? "/");
474
+ if (scopedCanvas.malformedScopedPath) {
475
+ writeUpgradeAuthFailure(socket, { ok: false, reason: "unauthorized" });
476
+ socket.destroy();
477
+ return;
478
+ }
479
+ if (scopedCanvas.rewrittenUrl) {
480
+ req.url = scopedCanvas.rewrittenUrl;
481
+ }
294
482
  if (canvasHost) {
295
483
  const url = new URL(req.url ?? "/", "http://localhost");
296
484
  if (url.pathname === CANVAS_WS_PATH) {
297
485
  const configSnapshot = loadConfig();
298
486
  const trustedProxies = configSnapshot.gateway?.trustedProxies ?? [];
487
+ const allowRealIpFallback = configSnapshot.gateway?.allowRealIpFallback === true;
299
488
  const ok = await authorizeCanvasRequest({
300
489
  req,
301
490
  auth: resolvedAuth,
302
491
  trustedProxies,
492
+ allowRealIpFallback,
303
493
  clients,
494
+ canvasCapability: scopedCanvas.capability,
495
+ malformedScopedPath: scopedCanvas.malformedScopedPath,
496
+ rateLimiter,
304
497
  });
305
- if (!ok) {
306
- socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
498
+ if (!ok.ok) {
499
+ writeUpgradeAuthFailure(socket, ok);
307
500
  socket.destroy();
308
501
  return;
309
502
  }
@@ -1,7 +1,7 @@
1
1
  import { abortChatRunById } from "./chat-abort.js";
2
- import { setBroadcastHealthUpdate } from "./server/health-state.js";
3
2
  import { DEDUPE_MAX, DEDUPE_TTL_MS, HEALTH_REFRESH_INTERVAL_MS, TICK_INTERVAL_MS, } from "./server-constants.js";
4
3
  import { formatError } from "./server-utils.js";
4
+ import { setBroadcastHealthUpdate } from "./server/health-state.js";
5
5
  export function startGatewayMaintenanceTimers(params) {
6
6
  setBroadcastHealthUpdate((snap) => {
7
7
  params.broadcast("health", snap, {
@@ -30,20 +30,34 @@ export function startGatewayMaintenanceTimers(params) {
30
30
  .catch((err) => params.logHealth.error(`initial refresh failed: ${formatError(err)}`));
31
31
  // dedupe cache cleanup
32
32
  const dedupeCleanup = setInterval(() => {
33
+ const AGENT_RUN_SEQ_MAX = 10_000;
33
34
  const now = Date.now();
34
35
  for (const [k, v] of params.dedupe) {
35
- if (now - v.ts > DEDUPE_TTL_MS)
36
+ if (now - v.ts > DEDUPE_TTL_MS) {
36
37
  params.dedupe.delete(k);
38
+ }
37
39
  }
38
40
  if (params.dedupe.size > DEDUPE_MAX) {
39
- const entries = [...params.dedupe.entries()].sort((a, b) => a[1].ts - b[1].ts);
41
+ const entries = [...params.dedupe.entries()].toSorted((a, b) => a[1].ts - b[1].ts);
40
42
  for (let i = 0; i < params.dedupe.size - DEDUPE_MAX; i++) {
41
43
  params.dedupe.delete(entries[i][0]);
42
44
  }
43
45
  }
46
+ if (params.agentRunSeq.size > AGENT_RUN_SEQ_MAX) {
47
+ const excess = params.agentRunSeq.size - AGENT_RUN_SEQ_MAX;
48
+ let removed = 0;
49
+ for (const runId of params.agentRunSeq.keys()) {
50
+ params.agentRunSeq.delete(runId);
51
+ removed += 1;
52
+ if (removed >= excess) {
53
+ break;
54
+ }
55
+ }
56
+ }
44
57
  for (const [runId, entry] of params.chatAbortControllers) {
45
- if (now <= entry.expiresAtMs)
58
+ if (now <= entry.expiresAtMs) {
46
59
  continue;
60
+ }
47
61
  abortChatRunById({
48
62
  chatAbortControllers: params.chatAbortControllers,
49
63
  chatRunBuffers: params.chatRunBuffers,
@@ -57,8 +71,9 @@ export function startGatewayMaintenanceTimers(params) {
57
71
  }
58
72
  const ABORTED_RUN_TTL_MS = 60 * 60_000;
59
73
  for (const [runId, abortedAt] of params.chatRunState.abortedRuns) {
60
- if (now - abortedAt <= ABORTED_RUN_TTL_MS)
74
+ if (now - abortedAt <= ABORTED_RUN_TTL_MS) {
61
75
  continue;
76
+ }
62
77
  params.chatRunState.abortedRuns.delete(runId);
63
78
  params.chatRunBuffers.delete(runId);
64
79
  params.chatDeltaSentAt.delete(runId);