@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,49 +1,62 @@
1
- import { listChannelPlugins } from "../channels/plugins/index.js";
2
- import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js";
1
+ import { resolveSandboxConfigForAgent } from "../agents/sandbox.js";
3
2
  import { resolveBrowserConfig, resolveProfile } from "../browser/config.js";
3
+ import { resolveBrowserControlAuth } from "../browser/control-auth.js";
4
+ import { listChannelPlugins } from "../channels/plugins/index.js";
5
+ import { formatCliCommand } from "../cli/command-format.js";
4
6
  import { resolveConfigPath, resolveStateDir } from "../config/paths.js";
5
7
  import { resolveGatewayAuth } from "../gateway/auth.js";
6
- import { formatCliCommand } from "../cli/command-format.js";
7
8
  import { buildGatewayConnectionDetails } from "../gateway/call.js";
9
+ import { resolveGatewayProbeAuth } from "../gateway/probe-auth.js";
8
10
  import { probeGateway } from "../gateway/probe.js";
9
- import { DEFAULT_GATEWAY_HTTP_TOOL_DENY } from "./dangerous-tools.js";
10
- import { collectAttackSurfaceSummaryFindings, collectExposureMatrixFindings, collectHooksHardeningFindings, collectIncludeFilePermFindings, collectModelHygieneFindings, collectSmallModelRiskFindings, collectPluginsTrustFindings, collectSecretsInConfigFindings, collectStateDeepFilesystemFindings, collectSyncedFolderFindings, readConfigSnapshotForAudit, } from "./audit-extra.js";
11
- import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
12
- import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "../config/commands.js";
11
+ import { collectChannelSecurityFindings } from "./audit-channel.js";
12
+ import { collectAttackSurfaceSummaryFindings, collectExposureMatrixFindings, collectGatewayHttpNoAuthFindings, collectGatewayHttpSessionKeyOverrideFindings, collectHooksHardeningFindings, collectIncludeFilePermFindings, collectInstalledSkillsCodeSafetyFindings, collectSandboxBrowserHashLabelFindings, collectMinimalProfileOverrideFindings, collectModelHygieneFindings, collectNodeDenyCommandPatternFindings, collectSmallModelRiskFindings, collectSandboxDangerousConfigFindings, collectSandboxDockerNoopFindings, collectPluginsTrustFindings, collectSecretsInConfigFindings, collectPluginsCodeSafetyFindings, collectStateDeepFilesystemFindings, collectSyncedFolderFindings, readConfigSnapshotForAudit, } from "./audit-extra.js";
13
13
  import { formatPermissionDetail, formatPermissionRemediation, inspectPathPermissions, } from "./audit-fs.js";
14
+ import { DEFAULT_GATEWAY_HTTP_TOOL_DENY } from "./dangerous-tools.js";
14
15
  function countBySeverity(findings) {
15
16
  let critical = 0;
16
17
  let warn = 0;
17
18
  let info = 0;
18
19
  for (const f of findings) {
19
- if (f.severity === "critical")
20
+ if (f.severity === "critical") {
20
21
  critical += 1;
21
- else if (f.severity === "warn")
22
+ }
23
+ else if (f.severity === "warn") {
22
24
  warn += 1;
23
- else
25
+ }
26
+ else {
24
27
  info += 1;
28
+ }
25
29
  }
26
30
  return { critical, warn, info };
27
31
  }
28
32
  function normalizeAllowFromList(list) {
29
- if (!Array.isArray(list))
33
+ if (!Array.isArray(list)) {
30
34
  return [];
35
+ }
31
36
  return list.map((v) => String(v).trim()).filter(Boolean);
32
37
  }
33
- function classifyChannelWarningSeverity(message) {
34
- const s = message.toLowerCase();
35
- if (s.includes("dms: open") ||
36
- s.includes('grouppolicy="open"') ||
37
- s.includes('dmpolicy="open"')) {
38
- return "critical";
38
+ function collectEnabledInsecureOrDangerousFlags(cfg) {
39
+ const enabledFlags = [];
40
+ if (cfg.gateway?.controlUi?.allowInsecureAuth === true) {
41
+ enabledFlags.push("gateway.controlUi.allowInsecureAuth=true");
39
42
  }
40
- if (s.includes("allows any") || s.includes("anyone can dm") || s.includes("public")) {
41
- return "critical";
43
+ if (cfg.gateway?.controlUi?.dangerouslyDisableDeviceAuth === true) {
44
+ enabledFlags.push("gateway.controlUi.dangerouslyDisableDeviceAuth=true");
42
45
  }
43
- if (s.includes("locked") || s.includes("disabled")) {
44
- return "info";
46
+ if (cfg.hooks?.gmail?.allowUnsafeExternalContent === true) {
47
+ enabledFlags.push("hooks.gmail.allowUnsafeExternalContent=true");
45
48
  }
46
- return "warn";
49
+ if (Array.isArray(cfg.hooks?.mappings)) {
50
+ for (const [index, mapping] of cfg.hooks.mappings.entries()) {
51
+ if (mapping?.allowUnsafeExternalContent === true) {
52
+ enabledFlags.push(`hooks.mappings[${index}].allowUnsafeExternalContent=true`);
53
+ }
54
+ }
55
+ }
56
+ if (cfg.tools?.exec?.applyPatch?.workspaceOnly === false) {
57
+ enabledFlags.push("tools.exec.applyPatch.workspaceOnly=false");
58
+ }
59
+ return enabledFlags;
47
60
  }
48
61
  async function collectFilesystemFindings(params) {
49
62
  const findings = [];
@@ -66,7 +79,7 @@ async function collectFilesystemFindings(params) {
66
79
  checkId: "fs.state_dir.perms_world_writable",
67
80
  severity: "critical",
68
81
  title: "State dir is world-writable",
69
- detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your Poolbot state.`,
82
+ detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; other users can write into your Pool Bot state.`,
70
83
  remediation: formatPermissionRemediation({
71
84
  targetPath: params.stateDir,
72
85
  perms: stateDirPerms,
@@ -81,7 +94,7 @@ async function collectFilesystemFindings(params) {
81
94
  checkId: "fs.state_dir.perms_group_writable",
82
95
  severity: "warn",
83
96
  title: "State dir is group-writable",
84
- detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your Poolbot state.`,
97
+ detail: `${formatPermissionDetail(params.stateDir, stateDirPerms)}; group users can write into your Pool Bot state.`,
85
98
  remediation: formatPermissionRemediation({
86
99
  targetPath: params.stateDir,
87
100
  perms: stateDirPerms,
@@ -113,6 +126,7 @@ async function collectFilesystemFindings(params) {
113
126
  exec: params.execIcacls,
114
127
  });
115
128
  if (configPerms.ok) {
129
+ const skipReadablePermWarnings = configPerms.isSymlink;
116
130
  if (configPerms.isSymlink) {
117
131
  findings.push({
118
132
  checkId: "fs.config.symlink",
@@ -136,7 +150,7 @@ async function collectFilesystemFindings(params) {
136
150
  }),
137
151
  });
138
152
  }
139
- else if (configPerms.worldReadable) {
153
+ else if (!skipReadablePermWarnings && configPerms.worldReadable) {
140
154
  findings.push({
141
155
  checkId: "fs.config.perms_world_readable",
142
156
  severity: "critical",
@@ -151,7 +165,7 @@ async function collectFilesystemFindings(params) {
151
165
  }),
152
166
  });
153
167
  }
154
- else if (configPerms.groupReadable) {
168
+ else if (!skipReadablePermWarnings && configPerms.groupReadable) {
155
169
  findings.push({
156
170
  checkId: "fs.config.perms_group_readable",
157
171
  severity: "warn",
@@ -181,12 +195,13 @@ function collectGatewayConfigFindings(cfg, env) {
181
195
  const hasToken = typeof auth.token === "string" && auth.token.trim().length > 0;
182
196
  const hasPassword = typeof auth.password === "string" && auth.password.trim().length > 0;
183
197
  const hasSharedSecret = (auth.mode === "token" && hasToken) || (auth.mode === "password" && hasPassword);
184
- const hasTailscaleAuth = auth.allowTailscale === true && tailscaleMode === "serve";
198
+ const hasTailscaleAuth = auth.allowTailscale && tailscaleMode === "serve";
185
199
  const hasGatewayAuth = hasSharedSecret || hasTailscaleAuth;
186
- // HTTP /tools/invoke: warn if operators re-enable dangerous tools over HTTP
187
- const gatewayCfgAny = cfg.gateway;
188
- const toolsCfg = gatewayCfgAny?.tools;
189
- const gatewayToolsAllowRaw = Array.isArray(toolsCfg?.allow) ? toolsCfg.allow : [];
200
+ // HTTP /tools/invoke is intended for narrow automation, not session orchestration/admin operations.
201
+ // If operators opt-in to re-enabling these tools over HTTP, warn loudly so the choice is explicit.
202
+ const gatewayToolsAllowRaw = Array.isArray(cfg.gateway?.tools?.allow)
203
+ ? cfg.gateway?.tools?.allow
204
+ : [];
190
205
  const gatewayToolsAllow = new Set(gatewayToolsAllowRaw
191
206
  .map((v) => (typeof v === "string" ? v.trim().toLowerCase() : ""))
192
207
  .filter(Boolean));
@@ -203,7 +218,7 @@ function collectGatewayConfigFindings(cfg, env) {
203
218
  "If you keep them enabled, keep gateway.bind loopback-only (or tailnet-only), restrict network exposure, and treat the gateway token/password as full-admin.",
204
219
  });
205
220
  }
206
- if (bind !== "loopback" && !hasSharedSecret) {
221
+ if (bind !== "loopback" && !hasSharedSecret && auth.mode !== "trusted-proxy") {
207
222
  findings.push({
208
223
  checkId: "gateway.bind_no_auth",
209
224
  severity: "critical",
@@ -253,9 +268,9 @@ function collectGatewayConfigFindings(cfg, env) {
253
268
  if (cfg.gateway?.controlUi?.allowInsecureAuth === true) {
254
269
  findings.push({
255
270
  checkId: "gateway.control_ui.insecure_auth",
256
- severity: "critical",
257
- title: "Control UI allows insecure HTTP auth",
258
- detail: "gateway.controlUi.allowInsecureAuth=true allows token-only auth over HTTP and skips device identity.",
271
+ severity: "warn",
272
+ title: "Control UI insecure auth toggle enabled",
273
+ detail: "gateway.controlUi.allowInsecureAuth=true does not bypass secure context or device identity checks; only dangerouslyDisableDeviceAuth disables Control UI device identity checks.",
259
274
  remediation: "Disable it or switch to HTTPS (Tailscale Serve) or localhost.",
260
275
  });
261
276
  }
@@ -268,6 +283,16 @@ function collectGatewayConfigFindings(cfg, env) {
268
283
  remediation: "Disable it unless you are in a short-lived break-glass scenario.",
269
284
  });
270
285
  }
286
+ const enabledDangerousFlags = collectEnabledInsecureOrDangerousFlags(cfg);
287
+ if (enabledDangerousFlags.length > 0) {
288
+ findings.push({
289
+ checkId: "config.insecure_or_dangerous_flags",
290
+ severity: "warn",
291
+ title: "Insecure or dangerous config flags enabled",
292
+ detail: `Detected ${enabledDangerousFlags.length} enabled flag(s): ${enabledDangerousFlags.join(", ")}.`,
293
+ remediation: "Disable these flags when not actively debugging, or keep deployment scoped to trusted/local-only networks.",
294
+ });
295
+ }
271
296
  const token = typeof auth.token === "string" && auth.token.trim().length > 0 ? auth.token.trim() : null;
272
297
  if (auth.mode === "token" && token && token.length < 24) {
273
298
  findings.push({
@@ -277,8 +302,54 @@ function collectGatewayConfigFindings(cfg, env) {
277
302
  detail: `gateway auth token is ${token.length} chars; prefer a long random token.`,
278
303
  });
279
304
  }
280
- const authCfgAny = cfg.gateway?.auth;
281
- if (bind !== "loopback" && !authCfgAny?.rateLimit) {
305
+ if (auth.mode === "trusted-proxy") {
306
+ const trustedProxies = cfg.gateway?.trustedProxies ?? [];
307
+ const trustedProxyConfig = cfg.gateway?.auth?.trustedProxy;
308
+ findings.push({
309
+ checkId: "gateway.trusted_proxy_auth",
310
+ severity: "critical",
311
+ title: "Trusted-proxy auth mode enabled",
312
+ detail: 'gateway.auth.mode="trusted-proxy" delegates authentication to a reverse proxy. ' +
313
+ "Ensure your proxy (Pomerium, Caddy, nginx) handles auth correctly and that gateway.trustedProxies " +
314
+ "only contains IPs of your actual proxy servers.",
315
+ remediation: "Verify: (1) Your proxy terminates TLS and authenticates users. " +
316
+ "(2) gateway.trustedProxies is restricted to proxy IPs only. " +
317
+ "(3) Direct access to the Gateway port is blocked by firewall. " +
318
+ "See /gateway/trusted-proxy-auth for setup guidance.",
319
+ });
320
+ if (trustedProxies.length === 0) {
321
+ findings.push({
322
+ checkId: "gateway.trusted_proxy_no_proxies",
323
+ severity: "critical",
324
+ title: "Trusted-proxy auth enabled but no trusted proxies configured",
325
+ detail: 'gateway.auth.mode="trusted-proxy" but gateway.trustedProxies is empty. ' +
326
+ "All requests will be rejected.",
327
+ remediation: "Set gateway.trustedProxies to the IP(s) of your reverse proxy.",
328
+ });
329
+ }
330
+ if (!trustedProxyConfig?.userHeader) {
331
+ findings.push({
332
+ checkId: "gateway.trusted_proxy_no_user_header",
333
+ severity: "critical",
334
+ title: "Trusted-proxy auth missing userHeader config",
335
+ detail: 'gateway.auth.mode="trusted-proxy" but gateway.auth.trustedProxy.userHeader is not configured.',
336
+ remediation: "Set gateway.auth.trustedProxy.userHeader to the header name your proxy uses " +
337
+ '(e.g., "x-forwarded-user", "x-pomerium-claim-email").',
338
+ });
339
+ }
340
+ const allowUsers = trustedProxyConfig?.allowUsers ?? [];
341
+ if (allowUsers.length === 0) {
342
+ findings.push({
343
+ checkId: "gateway.trusted_proxy_no_allowlist",
344
+ severity: "warn",
345
+ title: "Trusted-proxy auth allows all authenticated users",
346
+ detail: "gateway.auth.trustedProxy.allowUsers is empty, so any user authenticated by your proxy can access the Gateway.",
347
+ remediation: "Consider setting gateway.auth.trustedProxy.allowUsers to restrict access to specific users " +
348
+ '(e.g., ["nick@example.com"]).',
349
+ });
350
+ }
351
+ }
352
+ if (bind !== "loopback" && auth.mode !== "trusted-proxy" && !cfg.gateway?.auth?.rateLimit) {
282
353
  findings.push({
283
354
  checkId: "gateway.auth_no_rate_limit",
284
355
  severity: "warn",
@@ -290,7 +361,7 @@ function collectGatewayConfigFindings(cfg, env) {
290
361
  }
291
362
  return findings;
292
363
  }
293
- function collectBrowserControlFindings(cfg) {
364
+ function collectBrowserControlFindings(cfg, env) {
294
365
  const findings = [];
295
366
  let resolved;
296
367
  try {
@@ -306,12 +377,25 @@ function collectBrowserControlFindings(cfg) {
306
377
  });
307
378
  return findings;
308
379
  }
309
- if (!resolved.enabled)
380
+ if (!resolved.enabled) {
310
381
  return findings;
382
+ }
383
+ const browserAuth = resolveBrowserControlAuth(cfg, env);
384
+ if (!browserAuth.token && !browserAuth.password) {
385
+ findings.push({
386
+ checkId: "browser.control_no_auth",
387
+ severity: "critical",
388
+ title: "Browser control has no auth",
389
+ detail: "Browser control HTTP routes are enabled but no gateway.auth token/password is configured. " +
390
+ "Any local process (or SSRF to loopback) can call browser control endpoints.",
391
+ remediation: "Set gateway.auth.token (recommended) or gateway.auth.password so browser control HTTP routes require authentication. Restarting the gateway will auto-generate gateway.auth.token when browser control is enabled.",
392
+ });
393
+ }
311
394
  for (const name of Object.keys(resolved.profiles)) {
312
395
  const profile = resolveProfile(resolved, name);
313
- if (!profile || profile.cdpIsLoopback)
396
+ if (!profile || profile.cdpIsLoopback) {
314
397
  continue;
398
+ }
315
399
  let url;
316
400
  try {
317
401
  url = new URL(profile.cdpUrl);
@@ -333,8 +417,9 @@ function collectBrowserControlFindings(cfg) {
333
417
  }
334
418
  function collectLoggingFindings(cfg) {
335
419
  const redact = cfg.logging?.redactSensitive;
336
- if (redact !== "off")
420
+ if (redact !== "off") {
337
421
  return [];
422
+ }
338
423
  return [
339
424
  {
340
425
  checkId: "logging.redact_off",
@@ -350,10 +435,12 @@ function collectElevatedFindings(cfg) {
350
435
  const enabled = cfg.tools?.elevated?.enabled;
351
436
  const allowFrom = cfg.tools?.elevated?.allowFrom ?? {};
352
437
  const anyAllowFromKeys = Object.keys(allowFrom).length > 0;
353
- if (enabled === false)
438
+ if (enabled === false) {
354
439
  return findings;
355
- if (!anyAllowFromKeys)
440
+ }
441
+ if (!anyAllowFromKeys) {
356
442
  return findings;
443
+ }
357
444
  for (const [provider, list] of Object.entries(allowFrom)) {
358
445
  const normalized = normalizeAllowFromList(list);
359
446
  if (normalized.includes("*")) {
@@ -375,310 +462,39 @@ function collectElevatedFindings(cfg) {
375
462
  }
376
463
  return findings;
377
464
  }
378
- async function collectChannelSecurityFindings(params) {
465
+ function collectExecRuntimeFindings(cfg) {
379
466
  const findings = [];
380
- const coerceNativeSetting = (value) => {
381
- if (value === true)
382
- return true;
383
- if (value === false)
384
- return false;
385
- if (value === "auto")
386
- return "auto";
387
- return undefined;
388
- };
389
- const warnDmPolicy = async (input) => {
390
- const policyPath = input.policyPath ?? `${input.allowFromPath}policy`;
391
- const configAllowFrom = normalizeAllowFromList(input.allowFrom);
392
- const hasWildcard = configAllowFrom.includes("*");
393
- const dmScope = params.cfg.session?.dmScope ?? "main";
394
- const storeAllowFrom = await readChannelAllowFromStore(input.provider).catch(() => []);
395
- const normalizeEntry = input.normalizeEntry ?? ((value) => value);
396
- const normalizedCfg = configAllowFrom
397
- .filter((value) => value !== "*")
398
- .map((value) => normalizeEntry(value))
399
- .map((value) => value.trim())
400
- .filter(Boolean);
401
- const normalizedStore = storeAllowFrom
402
- .map((value) => normalizeEntry(value))
403
- .map((value) => value.trim())
404
- .filter(Boolean);
405
- const allowCount = Array.from(new Set([...normalizedCfg, ...normalizedStore])).length;
406
- const isMultiUserDm = hasWildcard || allowCount > 1;
407
- if (input.dmPolicy === "open") {
408
- const allowFromKey = `${input.allowFromPath}allowFrom`;
409
- findings.push({
410
- checkId: `channels.${input.provider}.dm.open`,
411
- severity: "critical",
412
- title: `${input.label} DMs are open`,
413
- detail: `${policyPath}="open" allows anyone to DM the bot.`,
414
- remediation: `Use pairing/allowlist; if you really need open DMs, ensure ${allowFromKey} includes "*".`,
415
- });
416
- if (!hasWildcard) {
417
- findings.push({
418
- checkId: `channels.${input.provider}.dm.open_invalid`,
419
- severity: "warn",
420
- title: `${input.label} DM config looks inconsistent`,
421
- detail: `"open" requires ${allowFromKey} to include "*".`,
422
- });
423
- }
424
- }
425
- if (input.dmPolicy === "disabled") {
426
- findings.push({
427
- checkId: `channels.${input.provider}.dm.disabled`,
428
- severity: "info",
429
- title: `${input.label} DMs are disabled`,
430
- detail: `${policyPath}="disabled" ignores inbound DMs.`,
431
- });
432
- return;
433
- }
434
- if (dmScope === "main" && isMultiUserDm) {
435
- findings.push({
436
- checkId: `channels.${input.provider}.dm.scope_main_multiuser`,
437
- severity: "warn",
438
- title: `${input.label} DMs share the main session`,
439
- detail: "Multiple DM senders currently share the main session, which can leak context across users.",
440
- remediation: 'Set session.dmScope="per-channel-peer" to isolate DM sessions per sender.',
441
- });
442
- }
443
- };
444
- for (const plugin of params.plugins) {
445
- if (!plugin.security)
446
- continue;
447
- const accountIds = plugin.config.listAccountIds(params.cfg);
448
- const defaultAccountId = resolveChannelDefaultAccountId({
449
- plugin,
450
- cfg: params.cfg,
451
- accountIds,
467
+ const globalExecHost = cfg.tools?.exec?.host;
468
+ const defaultSandboxMode = resolveSandboxConfigForAgent(cfg).mode;
469
+ const defaultHostIsExplicitSandbox = globalExecHost === "sandbox";
470
+ if (defaultHostIsExplicitSandbox && defaultSandboxMode === "off") {
471
+ findings.push({
472
+ checkId: "tools.exec.host_sandbox_no_sandbox_defaults",
473
+ severity: "warn",
474
+ title: "Exec host is sandbox but sandbox mode is off",
475
+ detail: "tools.exec.host is explicitly set to sandbox while agents.defaults.sandbox.mode=off. " +
476
+ "In this mode, exec runs directly on the gateway host.",
477
+ remediation: 'Enable sandbox mode (`agents.defaults.sandbox.mode="non-main"` or `"all"`) or set tools.exec.host to "gateway" with approvals.',
452
478
  });
453
- const account = plugin.config.resolveAccount(params.cfg, defaultAccountId);
454
- const enabled = plugin.config.isEnabled ? plugin.config.isEnabled(account, params.cfg) : true;
455
- if (!enabled)
456
- continue;
457
- const configured = plugin.config.isConfigured
458
- ? await plugin.config.isConfigured(account, params.cfg)
459
- : true;
460
- if (!configured)
461
- continue;
462
- if (plugin.id === "discord") {
463
- const discordCfg = account?.config ??
464
- {};
465
- const nativeEnabled = resolveNativeCommandsEnabled({
466
- providerId: "discord",
467
- providerSetting: coerceNativeSetting(discordCfg.commands?.native),
468
- globalSetting: params.cfg.commands?.native,
469
- });
470
- const nativeSkillsEnabled = resolveNativeSkillsEnabled({
471
- providerId: "discord",
472
- providerSetting: coerceNativeSetting(discordCfg.commands?.nativeSkills),
473
- globalSetting: params.cfg.commands?.nativeSkills,
474
- });
475
- const slashEnabled = nativeEnabled || nativeSkillsEnabled;
476
- if (slashEnabled) {
477
- const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy;
478
- const groupPolicy = discordCfg.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
479
- const guildEntries = discordCfg.guilds ?? {};
480
- const guildsConfigured = Object.keys(guildEntries).length > 0;
481
- const hasAnyUserAllowlist = Object.values(guildEntries).some((guild) => {
482
- if (!guild || typeof guild !== "object")
483
- return false;
484
- const g = guild;
485
- if (Array.isArray(g.users) && g.users.length > 0)
486
- return true;
487
- const channels = g.channels;
488
- if (!channels || typeof channels !== "object")
489
- return false;
490
- return Object.values(channels).some((channel) => {
491
- if (!channel || typeof channel !== "object")
492
- return false;
493
- const c = channel;
494
- return Array.isArray(c.users) && c.users.length > 0;
495
- });
496
- });
497
- const dmAllowFromRaw = discordCfg.dm?.allowFrom;
498
- const dmAllowFrom = Array.isArray(dmAllowFromRaw) ? dmAllowFromRaw : [];
499
- const storeAllowFrom = await readChannelAllowFromStore("discord").catch(() => []);
500
- const ownerAllowFromConfigured = normalizeAllowFromList([...dmAllowFrom, ...storeAllowFrom]).length > 0;
501
- const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
502
- if (!useAccessGroups &&
503
- groupPolicy !== "disabled" &&
504
- guildsConfigured &&
505
- !hasAnyUserAllowlist) {
506
- findings.push({
507
- checkId: "channels.discord.commands.native.unrestricted",
508
- severity: "critical",
509
- title: "Discord slash commands are unrestricted",
510
- detail: "commands.useAccessGroups=false disables sender allowlists for Discord slash commands unless a per-guild/channel users allowlist is configured; with no users allowlist, any user in allowed guild channels can invoke /… commands.",
511
- remediation: "Set commands.useAccessGroups=true (recommended), or configure channels.discord.guilds.<id>.users (or channels.discord.guilds.<id>.channels.<channel>.users).",
512
- });
513
- }
514
- else if (useAccessGroups &&
515
- groupPolicy !== "disabled" &&
516
- guildsConfigured &&
517
- !ownerAllowFromConfigured &&
518
- !hasAnyUserAllowlist) {
519
- findings.push({
520
- checkId: "channels.discord.commands.native.no_allowlists",
521
- severity: "warn",
522
- title: "Discord slash commands have no allowlists",
523
- detail: "Discord slash commands are enabled, but neither an owner allowFrom list nor any per-guild/channel users allowlist is configured; /… commands will be rejected for everyone.",
524
- remediation: "Add your user id to channels.discord.dm.allowFrom (or approve yourself via pairing), or configure channels.discord.guilds.<id>.users.",
525
- });
526
- }
527
- }
528
- }
529
- if (plugin.id === "slack") {
530
- const slackCfg = account
531
- ?.config ?? {};
532
- const nativeEnabled = resolveNativeCommandsEnabled({
533
- providerId: "slack",
534
- providerSetting: coerceNativeSetting(slackCfg.commands?.native),
535
- globalSetting: params.cfg.commands?.native,
536
- });
537
- const nativeSkillsEnabled = resolveNativeSkillsEnabled({
538
- providerId: "slack",
539
- providerSetting: coerceNativeSetting(slackCfg.commands?.nativeSkills),
540
- globalSetting: params.cfg.commands?.nativeSkills,
541
- });
542
- const slashCommandEnabled = nativeEnabled ||
543
- nativeSkillsEnabled ||
544
- slackCfg.slashCommand?.enabled === true;
545
- if (slashCommandEnabled) {
546
- const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
547
- if (!useAccessGroups) {
548
- findings.push({
549
- checkId: "channels.slack.commands.slash.useAccessGroups_off",
550
- severity: "critical",
551
- title: "Slack slash commands bypass access groups",
552
- detail: "Slack slash/native commands are enabled while commands.useAccessGroups=false; this can allow unrestricted /… command execution from channels/users you didn't explicitly authorize.",
553
- remediation: "Set commands.useAccessGroups=true (recommended).",
554
- });
555
- }
556
- else {
557
- const dmAllowFromRaw = account?.dm
558
- ?.allowFrom;
559
- const dmAllowFrom = Array.isArray(dmAllowFromRaw) ? dmAllowFromRaw : [];
560
- const storeAllowFrom = await readChannelAllowFromStore("slack").catch(() => []);
561
- const ownerAllowFromConfigured = normalizeAllowFromList([...dmAllowFrom, ...storeAllowFrom]).length > 0;
562
- const channels = slackCfg.channels ?? {};
563
- const hasAnyChannelUsersAllowlist = Object.values(channels).some((value) => {
564
- if (!value || typeof value !== "object")
565
- return false;
566
- const channel = value;
567
- return Array.isArray(channel.users) && channel.users.length > 0;
568
- });
569
- if (!ownerAllowFromConfigured && !hasAnyChannelUsersAllowlist) {
570
- findings.push({
571
- checkId: "channels.slack.commands.slash.no_allowlists",
572
- severity: "warn",
573
- title: "Slack slash commands have no allowlists",
574
- detail: "Slack slash/native commands are enabled, but neither an owner allowFrom list nor any channels.<id>.users allowlist is configured; /… commands will be rejected for everyone.",
575
- remediation: "Approve yourself via pairing (recommended), or set channels.slack.dm.allowFrom and/or channels.slack.channels.<id>.users.",
576
- });
577
- }
578
- }
579
- }
580
- }
581
- const dmPolicy = plugin.security.resolveDmPolicy?.({
582
- cfg: params.cfg,
583
- accountId: defaultAccountId,
584
- account,
479
+ }
480
+ const agents = Array.isArray(cfg.agents?.list) ? cfg.agents.list : [];
481
+ const riskyAgents = agents
482
+ .filter((entry) => entry &&
483
+ typeof entry === "object" &&
484
+ typeof entry.id === "string" &&
485
+ entry.tools?.exec?.host === "sandbox" &&
486
+ resolveSandboxConfigForAgent(cfg, entry.id).mode === "off")
487
+ .map((entry) => entry.id)
488
+ .slice(0, 5);
489
+ if (riskyAgents.length > 0) {
490
+ findings.push({
491
+ checkId: "tools.exec.host_sandbox_no_sandbox_agents",
492
+ severity: "warn",
493
+ title: "Agent exec host uses sandbox while sandbox mode is off",
494
+ detail: `agents.list.*.tools.exec.host is set to sandbox for: ${riskyAgents.join(", ")}. ` +
495
+ "With sandbox mode off, exec runs directly on the gateway host.",
496
+ remediation: 'Enable sandbox mode for these agents (`agents.list[].sandbox.mode`) or set their tools.exec.host to "gateway".',
585
497
  });
586
- if (dmPolicy) {
587
- await warnDmPolicy({
588
- label: plugin.meta.label ?? plugin.id,
589
- provider: plugin.id,
590
- dmPolicy: dmPolicy.policy,
591
- allowFrom: dmPolicy.allowFrom,
592
- policyPath: dmPolicy.policyPath,
593
- allowFromPath: dmPolicy.allowFromPath,
594
- normalizeEntry: dmPolicy.normalizeEntry,
595
- });
596
- }
597
- if (plugin.security.collectWarnings) {
598
- const warnings = await plugin.security.collectWarnings({
599
- cfg: params.cfg,
600
- accountId: defaultAccountId,
601
- account,
602
- });
603
- for (const message of warnings ?? []) {
604
- const trimmed = String(message).trim();
605
- if (!trimmed)
606
- continue;
607
- findings.push({
608
- checkId: `channels.${plugin.id}.warning.${findings.length + 1}`,
609
- severity: classifyChannelWarningSeverity(trimmed),
610
- title: `${plugin.meta.label ?? plugin.id} security warning`,
611
- detail: trimmed.replace(/^-\s*/, ""),
612
- });
613
- }
614
- }
615
- if (plugin.id === "telegram") {
616
- const allowTextCommands = params.cfg.commands?.text !== false;
617
- if (!allowTextCommands)
618
- continue;
619
- const telegramCfg = account?.config ??
620
- {};
621
- const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy;
622
- const groupPolicy = telegramCfg.groupPolicy ?? defaultGroupPolicy ?? "allowlist";
623
- const groups = telegramCfg.groups;
624
- const groupsConfigured = Boolean(groups) && Object.keys(groups ?? {}).length > 0;
625
- const groupAccessPossible = groupPolicy === "open" || (groupPolicy === "allowlist" && groupsConfigured);
626
- if (!groupAccessPossible)
627
- continue;
628
- const storeAllowFrom = await readChannelAllowFromStore("telegram").catch(() => []);
629
- const storeHasWildcard = storeAllowFrom.some((v) => String(v).trim() === "*");
630
- const groupAllowFrom = Array.isArray(telegramCfg.groupAllowFrom)
631
- ? telegramCfg.groupAllowFrom
632
- : [];
633
- const groupAllowFromHasWildcard = groupAllowFrom.some((v) => String(v).trim() === "*");
634
- const anyGroupOverride = Boolean(groups &&
635
- Object.values(groups).some((value) => {
636
- if (!value || typeof value !== "object")
637
- return false;
638
- const group = value;
639
- const allowFrom = Array.isArray(group.allowFrom) ? group.allowFrom : [];
640
- if (allowFrom.length > 0)
641
- return true;
642
- const topics = group.topics;
643
- if (!topics || typeof topics !== "object")
644
- return false;
645
- return Object.values(topics).some((topicValue) => {
646
- if (!topicValue || typeof topicValue !== "object")
647
- return false;
648
- const topic = topicValue;
649
- const topicAllow = Array.isArray(topic.allowFrom) ? topic.allowFrom : [];
650
- return topicAllow.length > 0;
651
- });
652
- }));
653
- const hasAnySenderAllowlist = storeAllowFrom.length > 0 || groupAllowFrom.length > 0 || anyGroupOverride;
654
- if (storeHasWildcard || groupAllowFromHasWildcard) {
655
- findings.push({
656
- checkId: "channels.telegram.groups.allowFrom.wildcard",
657
- severity: "critical",
658
- title: "Telegram group allowlist contains wildcard",
659
- detail: 'Telegram group sender allowlist contains "*", which allows any group member to run /… commands and control directives.',
660
- remediation: 'Remove "*" from channels.telegram.groupAllowFrom and pairing store; prefer explicit user ids/usernames.',
661
- });
662
- continue;
663
- }
664
- if (!hasAnySenderAllowlist) {
665
- const providerSetting = telegramCfg.commands
666
- ?.nativeSkills;
667
- const skillsEnabled = resolveNativeSkillsEnabled({
668
- providerId: "telegram",
669
- providerSetting,
670
- globalSetting: params.cfg.commands?.nativeSkills,
671
- });
672
- findings.push({
673
- checkId: "channels.telegram.groups.allowFrom.missing",
674
- severity: "critical",
675
- title: "Telegram group commands have no sender allowlist",
676
- detail: `Telegram group access is enabled but no sender allowlist is configured; this allows any group member to invoke /… commands` +
677
- (skillsEnabled ? " (including skill commands)." : "."),
678
- remediation: "Approve yourself via pairing (recommended), or set channels.telegram.groupAllowFrom (or per-group groups.<id>.allowFrom).",
679
- });
680
- }
681
- }
682
498
  }
683
499
  return findings;
684
500
  }
@@ -688,29 +504,9 @@ async function maybeProbeGateway(params) {
688
504
  const isRemoteMode = params.cfg.gateway?.mode === "remote";
689
505
  const remoteUrlRaw = typeof params.cfg.gateway?.remote?.url === "string" ? params.cfg.gateway.remote.url.trim() : "";
690
506
  const remoteUrlMissing = isRemoteMode && !remoteUrlRaw;
691
- const resolveAuth = (mode) => {
692
- const authToken = params.cfg.gateway?.auth?.token;
693
- const authPassword = params.cfg.gateway?.auth?.password;
694
- const remote = params.cfg.gateway?.remote;
695
- const token = mode === "remote"
696
- ? typeof remote?.token === "string" && remote.token.trim()
697
- ? remote.token.trim()
698
- : undefined
699
- : process.env.POOLBOT_GATEWAY_TOKEN?.trim() ||
700
- process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() ||
701
- (typeof authToken === "string" && authToken.trim() ? authToken.trim() : undefined);
702
- const password = process.env.POOLBOT_GATEWAY_PASSWORD?.trim() ||
703
- process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() ||
704
- (mode === "remote"
705
- ? typeof remote?.password === "string" && remote.password.trim()
706
- ? remote.password.trim()
707
- : undefined
708
- : typeof authPassword === "string" && authPassword.trim()
709
- ? authPassword.trim()
710
- : undefined);
711
- return { token, password };
712
- };
713
- const auth = !isRemoteMode || remoteUrlMissing ? resolveAuth("local") : resolveAuth("remote");
507
+ const auth = !isRemoteMode || remoteUrlMissing
508
+ ? resolveGatewayProbeAuth({ cfg: params.cfg, mode: "local" })
509
+ : resolveGatewayProbeAuth({ cfg: params.cfg, mode: "remote" });
714
510
  const res = await params.probe({ url, auth, timeoutMs: params.timeoutMs }).catch((err) => ({
715
511
  ok: false,
716
512
  url,
@@ -743,10 +539,17 @@ export async function runSecurityAudit(opts) {
743
539
  findings.push(...collectAttackSurfaceSummaryFindings(cfg));
744
540
  findings.push(...collectSyncedFolderFindings({ stateDir, configPath }));
745
541
  findings.push(...collectGatewayConfigFindings(cfg, env));
746
- findings.push(...collectBrowserControlFindings(cfg));
542
+ findings.push(...collectBrowserControlFindings(cfg, env));
747
543
  findings.push(...collectLoggingFindings(cfg));
748
544
  findings.push(...collectElevatedFindings(cfg));
749
- findings.push(...collectHooksHardeningFindings(cfg));
545
+ findings.push(...collectExecRuntimeFindings(cfg));
546
+ findings.push(...collectHooksHardeningFindings(cfg, env));
547
+ findings.push(...collectGatewayHttpNoAuthFindings(cfg, env));
548
+ findings.push(...collectGatewayHttpSessionKeyOverrideFindings(cfg));
549
+ findings.push(...collectSandboxDockerNoopFindings(cfg));
550
+ findings.push(...collectSandboxDangerousConfigFindings(cfg));
551
+ findings.push(...collectNodeDenyCommandPatternFindings(cfg));
552
+ findings.push(...collectMinimalProfileOverrideFindings(cfg));
750
553
  findings.push(...collectSecretsInConfigFindings(cfg));
751
554
  findings.push(...collectModelHygieneFindings(cfg));
752
555
  findings.push(...collectSmallModelRiskFindings({ cfg, env }));
@@ -766,7 +569,14 @@ export async function runSecurityAudit(opts) {
766
569
  findings.push(...(await collectIncludeFilePermFindings({ configSnapshot, env, platform, execIcacls })));
767
570
  }
768
571
  findings.push(...(await collectStateDeepFilesystemFindings({ cfg, env, stateDir, platform, execIcacls })));
572
+ findings.push(...(await collectSandboxBrowserHashLabelFindings({
573
+ execDockerRawFn: opts.execDockerRawFn,
574
+ })));
769
575
  findings.push(...(await collectPluginsTrustFindings({ cfg, stateDir })));
576
+ if (opts.deep === true) {
577
+ findings.push(...(await collectPluginsCodeSafetyFindings({ stateDir })));
578
+ findings.push(...(await collectInstalledSkillsCodeSafetyFindings({ cfg, stateDir })));
579
+ }
770
580
  }
771
581
  if (opts.includeChannelSecurity !== false) {
772
582
  const plugins = opts.plugins ?? listChannelPlugins();
@@ -779,7 +589,7 @@ export async function runSecurityAudit(opts) {
779
589
  probe: opts.probeGatewayFn ?? probeGateway,
780
590
  })
781
591
  : undefined;
782
- if (deep?.gateway?.attempted && deep.gateway.ok === false) {
592
+ if (deep?.gateway?.attempted && !deep.gateway.ok) {
783
593
  findings.push({
784
594
  checkId: "gateway.probe_failed",
785
595
  severity: "warn",