@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
@@ -3,9 +3,11 @@ import { getFinishedSession, getSession, markExited } from "../../agents/bash-pr
3
3
  import { createExecTool } from "../../agents/bash-tools.js";
4
4
  import { resolveSandboxRuntimeStatus } from "../../agents/sandbox.js";
5
5
  import { killProcessTree } from "../../agents/shell-utils.js";
6
- import { formatCliCommand } from "../../cli/command-format.js";
6
+ import { isCommandFlagEnabled } from "../../config/commands.js";
7
7
  import { logVerbose } from "../../globals.js";
8
8
  import { clampInt } from "../../utils.js";
9
+ import { buildDisabledCommandReply } from "./command-gates.js";
10
+ import { formatElevatedUnavailableMessage } from "./elevated-unavailable.js";
9
11
  import { stripMentions, stripStructuralPrefixes } from "./mentions.js";
10
12
  const CHAT_BASH_SCOPE_KEY = "chat:bash";
11
13
  const DEFAULT_FOREGROUND_MS = 2000;
@@ -13,20 +15,23 @@ const MAX_FOREGROUND_MS = 30_000;
13
15
  let activeJob = null;
14
16
  function resolveForegroundMs(cfg) {
15
17
  const raw = cfg.commands?.bashForegroundMs;
16
- if (typeof raw !== "number" || Number.isNaN(raw))
18
+ if (typeof raw !== "number" || Number.isNaN(raw)) {
17
19
  return DEFAULT_FOREGROUND_MS;
20
+ }
18
21
  return clampInt(raw, 0, MAX_FOREGROUND_MS);
19
22
  }
20
23
  function formatSessionSnippet(sessionId) {
21
24
  const trimmed = sessionId.trim();
22
- if (trimmed.length <= 12)
25
+ if (trimmed.length <= 12) {
23
26
  return trimmed;
27
+ }
24
28
  return `${trimmed.slice(0, 8)}…`;
25
29
  }
26
30
  function formatOutputBlock(text) {
27
31
  const trimmed = text.trim();
28
- if (!trimmed)
32
+ if (!trimmed) {
29
33
  return "(no output)";
34
+ }
30
35
  return `\`\`\`txt\n${trimmed}\n\`\`\``;
31
36
  }
32
37
  function parseBashRequest(raw) {
@@ -34,8 +39,9 @@ function parseBashRequest(raw) {
34
39
  let restSource = "";
35
40
  if (trimmed.toLowerCase().startsWith("/bash")) {
36
41
  const match = trimmed.match(/^\/bash(?:\s*:\s*|\s+|$)([\s\S]*)$/i);
37
- if (!match)
42
+ if (!match) {
38
43
  return null;
44
+ }
39
45
  restSource = match[1] ?? "";
40
46
  }
41
47
  else if (trimmed.startsWith("!")) {
@@ -48,8 +54,9 @@ function parseBashRequest(raw) {
48
54
  return null;
49
55
  }
50
56
  const rest = restSource.trimStart();
51
- if (!rest)
57
+ if (!rest) {
52
58
  return { action: "help" };
59
+ }
53
60
  const tokenMatch = rest.match(/^(\S+)(?:\s+([\s\S]+))?$/);
54
61
  const token = tokenMatch?.[1]?.trim() ?? "";
55
62
  const remainder = tokenMatch?.[2]?.trim() ?? "";
@@ -74,21 +81,26 @@ function resolveRawCommandBody(params) {
74
81
  }
75
82
  function getScopedSession(sessionId) {
76
83
  const running = getSession(sessionId);
77
- if (running && running.scopeKey === CHAT_BASH_SCOPE_KEY)
84
+ if (running && running.scopeKey === CHAT_BASH_SCOPE_KEY) {
78
85
  return { running };
86
+ }
79
87
  const finished = getFinishedSession(sessionId);
80
- if (finished && finished.scopeKey === CHAT_BASH_SCOPE_KEY)
88
+ if (finished && finished.scopeKey === CHAT_BASH_SCOPE_KEY) {
81
89
  return { finished };
90
+ }
82
91
  return {};
83
92
  }
84
93
  function ensureActiveJobState() {
85
- if (!activeJob)
94
+ if (!activeJob) {
86
95
  return null;
87
- if (activeJob.state === "starting")
96
+ }
97
+ if (activeJob.state === "starting") {
88
98
  return activeJob;
99
+ }
89
100
  const { running, finished } = getScopedSession(activeJob.sessionId);
90
- if (running)
101
+ if (running) {
91
102
  return activeJob;
103
+ }
92
104
  if (finished) {
93
105
  activeJob = null;
94
106
  return null;
@@ -97,16 +109,20 @@ function ensureActiveJobState() {
97
109
  return null;
98
110
  }
99
111
  function attachActiveWatcher(sessionId) {
100
- if (!activeJob || activeJob.state !== "running")
112
+ if (!activeJob || activeJob.state !== "running") {
101
113
  return;
102
- if (activeJob.sessionId !== sessionId)
114
+ }
115
+ if (activeJob.sessionId !== sessionId) {
103
116
  return;
104
- if (activeJob.watcherAttached)
117
+ }
118
+ if (activeJob.watcherAttached) {
105
119
  return;
120
+ }
106
121
  const { running } = getScopedSession(sessionId);
107
122
  const child = running?.child;
108
- if (!child)
123
+ if (!child) {
109
124
  return;
125
+ }
110
126
  activeJob.watcherAttached = true;
111
127
  child.once("close", () => {
112
128
  if (activeJob?.state === "running" && activeJob.sessionId === sessionId) {
@@ -125,30 +141,13 @@ function buildUsageReply() {
125
141
  ].join("\n"),
126
142
  };
127
143
  }
128
- function formatElevatedUnavailableMessage(params) {
129
- const lines = [];
130
- lines.push(`elevated is not available right now (runtime=${params.runtimeSandboxed ? "sandboxed" : "direct"}).`);
131
- if (params.failures.length > 0) {
132
- lines.push(`Failing gates: ${params.failures.map((f) => `${f.gate} (${f.key})`).join(", ")}`);
133
- }
134
- else {
135
- lines.push("Failing gates: enabled (tools.elevated.enabled / agents.list[].tools.elevated.enabled), allowFrom (tools.elevated.allowFrom.<provider>).");
136
- }
137
- lines.push("Fix-it keys:");
138
- lines.push("- tools.elevated.enabled");
139
- lines.push("- tools.elevated.allowFrom.<provider>");
140
- lines.push("- agents.list[].tools.elevated.enabled");
141
- lines.push("- agents.list[].tools.elevated.allowFrom.<provider>");
142
- if (params.sessionKey) {
143
- lines.push(`See: ${formatCliCommand(`poolbot sandbox explain --session ${params.sessionKey}`)}`);
144
- }
145
- return lines.join("\n");
146
- }
147
144
  export async function handleBashChatCommand(params) {
148
- if (params.cfg.commands?.bash !== true) {
149
- return {
150
- text: "⚠️ bash is disabled. Set commands.bash=true to enable. Docs: https://docs.molt.bot/tools/slash-commands#config",
151
- };
145
+ if (!isCommandFlagEnabled(params.cfg, "bash")) {
146
+ return buildDisabledCommandReply({
147
+ label: "bash",
148
+ configKey: "bash",
149
+ docsUrl: "https://docs.molt.bot/tools/slash-commands#config",
150
+ });
152
151
  }
153
152
  const agentId = params.agentId ??
154
153
  resolveSessionAgentId({
@@ -262,8 +261,9 @@ export async function handleBashChatCommand(params) {
262
261
  };
263
262
  }
264
263
  const commandText = request.command.trim();
265
- if (!commandText)
264
+ if (!commandText) {
266
265
  return buildUsageReply();
266
+ }
267
267
  activeJob = {
268
268
  state: "starting",
269
269
  startedAt: Date.now(),
@@ -274,12 +274,14 @@ export async function handleBashChatCommand(params) {
274
274
  const shouldBackgroundImmediately = foregroundMs <= 0;
275
275
  const timeoutSec = params.cfg.tools?.exec?.timeoutSec;
276
276
  const notifyOnExit = params.cfg.tools?.exec?.notifyOnExit;
277
+ const notifyOnExitEmptySuccess = params.cfg.tools?.exec?.notifyOnExitEmptySuccess;
277
278
  const execTool = createExecTool({
278
279
  scopeKey: CHAT_BASH_SCOPE_KEY,
279
280
  allowBackground: true,
280
281
  timeoutSec,
281
282
  sessionKey: params.sessionKey,
282
283
  notifyOnExit,
284
+ notifyOnExitEmptySuccess,
283
285
  elevated: {
284
286
  enabled: params.elevated.enabled,
285
287
  allowed: params.elevated.allowed,
@@ -0,0 +1,25 @@
1
+ import { isCommandFlagEnabled } from "../../config/commands.js";
2
+ import { logVerbose } from "../../globals.js";
3
+ export function rejectUnauthorizedCommand(params, commandLabel) {
4
+ if (params.command.isAuthorizedSender) {
5
+ return null;
6
+ }
7
+ logVerbose(`Ignoring ${commandLabel} from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
8
+ return { shouldContinue: false };
9
+ }
10
+ export function buildDisabledCommandReply(params) {
11
+ const disabledVerb = params.disabledVerb ?? "is";
12
+ const docsSuffix = params.docsUrl ? ` Docs: ${params.docsUrl}` : "";
13
+ return {
14
+ text: `⚠️ ${params.label} ${disabledVerb} disabled. Set commands.${params.configKey}=true to enable.${docsSuffix}`,
15
+ };
16
+ }
17
+ export function requireCommandFlagEnabled(cfg, params) {
18
+ if (isCommandFlagEnabled(cfg, params.configKey)) {
19
+ return null;
20
+ }
21
+ return {
22
+ shouldContinue: false,
23
+ reply: buildDisabledCommandReply(params),
24
+ };
25
+ }
@@ -1,28 +1,30 @@
1
- import { readConfigFileSnapshot, validateConfigObjectWithPlugins, writeConfigFile, } from "../../config/config.js";
2
- import { resolveChannelConfigWrites } from "../../channels/plugins/config-writes.js";
3
1
  import { getChannelDock } from "../../channels/dock.js";
4
- import { normalizeChannelId } from "../../channels/registry.js";
2
+ import { resolveChannelConfigWrites } from "../../channels/plugins/config-writes.js";
5
3
  import { listPairingChannels } from "../../channels/plugins/pairing.js";
6
- import { logVerbose } from "../../globals.js";
7
- import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
4
+ import { normalizeChannelId } from "../../channels/registry.js";
5
+ import { readConfigFileSnapshot, validateConfigObjectWithPlugins, writeConfigFile, } from "../../config/config.js";
8
6
  import { resolveDiscordAccount } from "../../discord/accounts.js";
7
+ import { resolveDiscordUserAllowlist } from "../../discord/resolve-users.js";
9
8
  import { resolveIMessageAccount } from "../../imessage/accounts.js";
9
+ import { addChannelAllowFromStoreEntry, readChannelAllowFromStore, removeChannelAllowFromStoreEntry, } from "../../pairing/pairing-store.js";
10
+ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
10
11
  import { resolveSignalAccount } from "../../signal/accounts.js";
11
12
  import { resolveSlackAccount } from "../../slack/accounts.js";
13
+ import { resolveSlackUserAllowlist } from "../../slack/resolve-users.js";
12
14
  import { resolveTelegramAccount } from "../../telegram/accounts.js";
13
15
  import { resolveWhatsAppAccount } from "../../web/accounts.js";
14
- import { resolveSlackUserAllowlist } from "../../slack/resolve-users.js";
15
- import { resolveDiscordUserAllowlist } from "../../discord/resolve-users.js";
16
- import { addChannelAllowFromStoreEntry, readChannelAllowFromStore, removeChannelAllowFromStoreEntry, } from "../../pairing/pairing-store.js";
16
+ import { rejectUnauthorizedCommand, requireCommandFlagEnabled } from "./command-gates.js";
17
17
  const ACTIONS = new Set(["list", "add", "remove"]);
18
18
  const SCOPES = new Set(["dm", "group", "all"]);
19
19
  function parseAllowlistCommand(raw) {
20
20
  const trimmed = raw.trim();
21
- if (!trimmed.toLowerCase().startsWith("/allowlist"))
21
+ if (!trimmed.toLowerCase().startsWith("/allowlist")) {
22
22
  return null;
23
+ }
23
24
  const rest = trimmed.slice("/allowlist".length).trim();
24
- if (!rest)
25
+ if (!rest) {
25
26
  return { action: "list", scope: "dm" };
27
+ }
26
28
  const tokens = rest.split(/\s+/);
27
29
  let action = "list";
28
30
  let scope = "dm";
@@ -70,13 +72,15 @@ function parseAllowlistCommand(raw) {
70
72
  const key = kv[0]?.trim().toLowerCase();
71
73
  const value = kv[1]?.trim();
72
74
  if (key === "channel") {
73
- if (value)
75
+ if (value) {
74
76
  channel = value;
77
+ }
75
78
  continue;
76
79
  }
77
80
  if (key === "account") {
78
- if (value)
81
+ if (value) {
79
82
  account = value;
83
+ }
80
84
  continue;
81
85
  }
82
86
  if (key === "scope" && value && SCOPES.has(value.toLowerCase())) {
@@ -107,8 +111,9 @@ function normalizeAllowFrom(params) {
107
111
  return params.values.map((entry) => String(entry).trim()).filter(Boolean);
108
112
  }
109
113
  function formatEntryList(entries, resolved) {
110
- if (entries.length === 0)
114
+ if (entries.length === 0) {
111
115
  return "(none)";
116
+ }
112
117
  return entries
113
118
  .map((entry) => {
114
119
  const name = resolved?.get(entry);
@@ -136,8 +141,9 @@ function resolveAccountTarget(parsed, channelId, accountId) {
136
141
  function getNestedValue(root, path) {
137
142
  let current = root;
138
143
  for (const key of path) {
139
- if (!current || typeof current !== "object")
144
+ if (!current || typeof current !== "object") {
140
145
  return undefined;
146
+ }
141
147
  current = current[key];
142
148
  }
143
149
  return current;
@@ -154,8 +160,9 @@ function ensureNestedObject(root, path) {
154
160
  return current;
155
161
  }
156
162
  function setNestedValue(root, path, value) {
157
- if (path.length === 0)
163
+ if (path.length === 0) {
158
164
  return;
165
+ }
159
166
  if (path.length === 1) {
160
167
  root[path[0]] = value;
161
168
  return;
@@ -164,80 +171,86 @@ function setNestedValue(root, path, value) {
164
171
  parent[path[path.length - 1]] = value;
165
172
  }
166
173
  function deleteNestedValue(root, path) {
167
- if (path.length === 0)
174
+ if (path.length === 0) {
168
175
  return;
176
+ }
169
177
  if (path.length === 1) {
170
178
  delete root[path[0]];
171
179
  return;
172
180
  }
173
181
  const parent = getNestedValue(root, path.slice(0, -1));
174
- if (!parent || typeof parent !== "object")
182
+ if (!parent || typeof parent !== "object") {
175
183
  return;
184
+ }
176
185
  delete parent[path[path.length - 1]];
177
186
  }
178
187
  function resolveChannelAllowFromPaths(channelId, scope) {
179
- if (scope === "all")
188
+ const supportsGroupAllowlist = channelId === "telegram" ||
189
+ channelId === "whatsapp" ||
190
+ channelId === "signal" ||
191
+ channelId === "imessage";
192
+ if (scope === "all") {
180
193
  return null;
194
+ }
181
195
  if (scope === "dm") {
182
- if (channelId === "slack" || channelId === "discord")
183
- return ["dm", "allowFrom"];
184
- if (channelId === "telegram" ||
185
- channelId === "whatsapp" ||
186
- channelId === "signal" ||
187
- channelId === "imessage") {
196
+ if (channelId === "slack" || channelId === "discord") {
197
+ // Canonical DM allowlist location for Slack/Discord. Legacy: dm.allowFrom.
198
+ return ["allowFrom"];
199
+ }
200
+ if (supportsGroupAllowlist) {
188
201
  return ["allowFrom"];
189
202
  }
190
203
  return null;
191
204
  }
192
205
  if (scope === "group") {
193
- if (channelId === "telegram" ||
194
- channelId === "whatsapp" ||
195
- channelId === "signal" ||
196
- channelId === "imessage") {
206
+ if (supportsGroupAllowlist) {
197
207
  return ["groupAllowFrom"];
198
208
  }
199
209
  return null;
200
210
  }
201
211
  return null;
202
212
  }
213
+ function mapResolvedAllowlistNames(entries) {
214
+ const map = new Map();
215
+ for (const entry of entries) {
216
+ if (entry.resolved && entry.name) {
217
+ map.set(entry.input, entry.name);
218
+ }
219
+ }
220
+ return map;
221
+ }
203
222
  async function resolveSlackNames(params) {
204
223
  const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId });
205
224
  const token = account.config.userToken?.trim() || account.botToken?.trim();
206
- if (!token)
225
+ if (!token) {
207
226
  return new Map();
208
- const resolved = await resolveSlackUserAllowlist({ token, entries: params.entries });
209
- const map = new Map();
210
- for (const entry of resolved) {
211
- if (entry.resolved && entry.name)
212
- map.set(entry.input, entry.name);
213
227
  }
214
- return map;
228
+ const resolved = await resolveSlackUserAllowlist({ token, entries: params.entries });
229
+ return mapResolvedAllowlistNames(resolved);
215
230
  }
216
231
  async function resolveDiscordNames(params) {
217
232
  const account = resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId });
218
233
  const token = account.token?.trim();
219
- if (!token)
234
+ if (!token) {
220
235
  return new Map();
221
- const resolved = await resolveDiscordUserAllowlist({ token, entries: params.entries });
222
- const map = new Map();
223
- for (const entry of resolved) {
224
- if (entry.resolved && entry.name)
225
- map.set(entry.input, entry.name);
226
236
  }
227
- return map;
237
+ const resolved = await resolveDiscordUserAllowlist({ token, entries: params.entries });
238
+ return mapResolvedAllowlistNames(resolved);
228
239
  }
229
240
  export const handleAllowlistCommand = async (params, allowTextCommands) => {
230
- if (!allowTextCommands)
241
+ if (!allowTextCommands) {
231
242
  return null;
243
+ }
232
244
  const parsed = parseAllowlistCommand(params.command.commandBodyNormalized);
233
- if (!parsed)
245
+ if (!parsed) {
234
246
  return null;
247
+ }
235
248
  if (parsed.action === "error") {
236
- return { shouldContinue: false, reply: { text: `⚠️ ${parsed.message}` } };
249
+ return { shouldContinue: false, reply: { text: `\u26a0\ufe0f ${parsed.message}` } };
237
250
  }
238
- if (!params.command.isAuthorizedSender) {
239
- logVerbose(`Ignoring /allowlist from unauthorized sender: ${params.command.senderId || "<unknown>"}`);
240
- return { shouldContinue: false };
251
+ const unauthorized = rejectUnauthorizedCommand(params, "/allowlist");
252
+ if (unauthorized) {
253
+ return unauthorized;
241
254
  }
242
255
  const channelId = normalizeChannelId(parsed.channel) ??
243
256
  params.command.channelId ??
@@ -245,7 +258,7 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
245
258
  if (!channelId) {
246
259
  return {
247
260
  shouldContinue: false,
248
- reply: { text: "⚠️ Unknown channel. Add channel=<id> to the command." },
261
+ reply: { text: "\u26a0\ufe0f Unknown channel. Add channel=<id> to the command." },
249
262
  };
250
263
  }
251
264
  const accountId = normalizeAccountId(parsed.account ?? params.ctx.AccountId);
@@ -305,7 +318,7 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
305
318
  }
306
319
  else if (channelId === "slack") {
307
320
  const account = resolveSlackAccount({ cfg: params.cfg, accountId });
308
- dmAllowFrom = (account.dm?.allowFrom ?? []).map(String);
321
+ dmAllowFrom = (account.config.allowFrom ?? account.config.dm?.allowFrom ?? []).map(String);
309
322
  groupPolicy = account.groupPolicy;
310
323
  const channels = account.channels ?? {};
311
324
  groupOverrides = Object.entries(channels)
@@ -317,7 +330,7 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
317
330
  }
318
331
  else if (channelId === "discord") {
319
332
  const account = resolveDiscordAccount({ cfg: params.cfg, accountId });
320
- dmAllowFrom = (account.config.dm?.allowFrom ?? []).map(String);
333
+ dmAllowFrom = (account.config.allowFrom ?? account.config.dm?.allowFrom ?? []).map(String);
321
334
  groupPolicy = account.config.groupPolicy;
322
335
  const guilds = account.config.guilds ?? {};
323
336
  for (const [guildKey, guildCfg] of Object.entries(guilds)) {
@@ -374,12 +387,14 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
374
387
  entries: groupOverrideDisplay,
375
388
  })
376
389
  : undefined;
377
- const lines = ["🧾 Allowlist"];
390
+ const lines = ["\ud83e\uddf6 Allowlist"];
378
391
  lines.push(`Channel: ${channelId}${accountId ? ` (account ${accountId})` : ""}`);
379
- if (dmPolicy)
392
+ if (dmPolicy) {
380
393
  lines.push(`DM policy: ${dmPolicy}`);
381
- if (groupPolicy)
394
+ }
395
+ if (groupPolicy) {
382
396
  lines.push(`Group policy: ${groupPolicy}`);
397
+ }
383
398
  const showDm = scope === "dm" || scope === "all";
384
399
  const showGroup = scope === "group" || scope === "all";
385
400
  if (showDm) {
@@ -413,11 +428,13 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
413
428
  }
414
429
  return { shouldContinue: false, reply: { text: lines.join("\n") } };
415
430
  }
416
- if (params.cfg.commands?.config !== true) {
417
- return {
418
- shouldContinue: false,
419
- reply: { text: "⚠️ /allowlist edits are disabled. Set commands.config=true to enable." },
420
- };
431
+ const disabled = requireCommandFlagEnabled(params.cfg, {
432
+ label: "/allowlist edits",
433
+ configKey: "config",
434
+ disabledVerb: "are",
435
+ });
436
+ if (disabled) {
437
+ return disabled;
421
438
  }
422
439
  const shouldUpdateConfig = parsed.target !== "store";
423
440
  const shouldTouchStore = parsed.target !== "config" && listPairingChannels().includes(channelId);
@@ -431,7 +448,9 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
431
448
  const hint = `channels.${channelId}.configWrites=true`;
432
449
  return {
433
450
  shouldContinue: false,
434
- reply: { text: `⚠️ Config writes are disabled for ${channelId}. Set ${hint} to enable.` },
451
+ reply: {
452
+ text: `\u26a0\ufe0f Config writes are disabled for ${channelId}. Set ${hint} to enable.`,
453
+ },
435
454
  };
436
455
  }
437
456
  const allowlistPath = resolveChannelAllowFromPaths(channelId, scope);
@@ -439,7 +458,7 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
439
458
  return {
440
459
  shouldContinue: false,
441
460
  reply: {
442
- text: `⚠️ ${channelId} does not support ${scope} allowlist edits via /allowlist.`,
461
+ text: `\u26a0\ufe0f ${channelId} does not support ${scope} allowlist edits via /allowlist.`,
443
462
  },
444
463
  };
445
464
  }
@@ -447,15 +466,29 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
447
466
  if (!snapshot.valid || !snapshot.parsed || typeof snapshot.parsed !== "object") {
448
467
  return {
449
468
  shouldContinue: false,
450
- reply: { text: "⚠️ Config file is invalid; fix it before using /allowlist." },
469
+ reply: { text: "\u26a0\ufe0f Config file is invalid; fix it before using /allowlist." },
451
470
  };
452
471
  }
453
472
  const parsedConfig = structuredClone(snapshot.parsed);
454
473
  const { target, pathPrefix, accountId: normalizedAccountId, } = resolveAccountTarget(parsedConfig, channelId, accountId);
455
- const existingRaw = getNestedValue(target, allowlistPath);
456
- const existing = Array.isArray(existingRaw)
457
- ? existingRaw.map((entry) => String(entry).trim()).filter(Boolean)
458
- : [];
474
+ const existing = [];
475
+ const existingPaths = scope === "dm" && (channelId === "slack" || channelId === "discord")
476
+ ? // Read both while legacy alias may still exist; write canonical below.
477
+ [allowlistPath, ["dm", "allowFrom"]]
478
+ : [allowlistPath];
479
+ for (const path of existingPaths) {
480
+ const existingRaw = getNestedValue(target, path);
481
+ if (!Array.isArray(existingRaw)) {
482
+ continue;
483
+ }
484
+ for (const entry of existingRaw) {
485
+ const value = String(entry).trim();
486
+ if (!value || existing.includes(value)) {
487
+ continue;
488
+ }
489
+ existing.push(value);
490
+ }
491
+ }
459
492
  const normalizedEntry = normalizeAllowFrom({
460
493
  cfg: params.cfg,
461
494
  channelId,
@@ -465,7 +498,7 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
465
498
  if (normalizedEntry.length === 0) {
466
499
  return {
467
500
  shouldContinue: false,
468
- reply: { text: "⚠️ Invalid allowlist entry." },
501
+ reply: { text: "\u26a0\ufe0f Invalid allowlist entry." },
469
502
  };
470
503
  }
471
504
  const existingNormalized = normalizeAllowFrom({
@@ -508,6 +541,10 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
508
541
  else {
509
542
  setNestedValue(target, allowlistPath, next);
510
543
  }
544
+ if (scope === "dm" && (channelId === "slack" || channelId === "discord")) {
545
+ // Remove legacy DM allowlist alias to prevent drift.
546
+ deleteNestedValue(target, ["dm", "allowFrom"]);
547
+ }
511
548
  }
512
549
  if (configChanged) {
513
550
  const validated = validateConfigObjectWithPlugins(parsedConfig);
@@ -515,13 +552,15 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
515
552
  const issue = validated.issues[0];
516
553
  return {
517
554
  shouldContinue: false,
518
- reply: { text: `⚠️ Config invalid after update (${issue.path}: ${issue.message}).` },
555
+ reply: {
556
+ text: `\u26a0\ufe0f Config invalid after update (${issue.path}: ${issue.message}).`,
557
+ },
519
558
  };
520
559
  }
521
560
  await writeConfigFile(validated.config);
522
561
  }
523
562
  if (!configChanged && !shouldTouchStore) {
524
- const message = parsed.action === "add" ? " Already allowlisted." : "⚠️ Entry not found.";
563
+ const message = parsed.action === "add" ? "\u2705 Already allowlisted." : "\u26a0\ufe0f Entry not found.";
525
564
  return { shouldContinue: false, reply: { text: message } };
526
565
  }
527
566
  if (shouldTouchStore) {
@@ -545,14 +584,14 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
545
584
  return {
546
585
  shouldContinue: false,
547
586
  reply: {
548
- text: `✅ ${scopeLabel} allowlist ${actionLabel}: ${targetLabel}.`,
587
+ text: `\u2705 ${scopeLabel} allowlist ${actionLabel}: ${targetLabel}.`,
549
588
  },
550
589
  };
551
590
  }
552
591
  if (!shouldTouchStore) {
553
592
  return {
554
593
  shouldContinue: false,
555
- reply: { text: "⚠️ This channel does not support allowlist storage." },
594
+ reply: { text: "\u26a0\ufe0f This channel does not support allowlist storage." },
556
595
  };
557
596
  }
558
597
  if (parsed.action === "add") {
@@ -565,6 +604,6 @@ export const handleAllowlistCommand = async (params, allowTextCommands) => {
565
604
  const scopeLabel = scope === "dm" ? "DM" : "group";
566
605
  return {
567
606
  shouldContinue: false,
568
- reply: { text: `✅ ${scopeLabel} allowlist ${actionLabel} in pairing store.` },
607
+ reply: { text: `\u2705 ${scopeLabel} allowlist ${actionLabel} in pairing store.` },
569
608
  };
570
609
  };
@@ -1,17 +1,18 @@
1
- import { logVerbose } from "../../globals.js";
2
1
  import { handleBashChatCommand } from "./bash-command.js";
2
+ import { rejectUnauthorizedCommand } from "./command-gates.js";
3
3
  export const handleBashCommand = async (params, allowTextCommands) => {
4
- if (!allowTextCommands)
4
+ if (!allowTextCommands) {
5
5
  return null;
6
+ }
6
7
  const { command } = params;
7
8
  const bashSlashRequested = command.commandBodyNormalized === "/bash" || command.commandBodyNormalized.startsWith("/bash ");
8
9
  const bashBangRequested = command.commandBodyNormalized.startsWith("!");
9
10
  if (!bashSlashRequested && !(bashBangRequested && command.isAuthorizedSender)) {
10
11
  return null;
11
12
  }
12
- if (!command.isAuthorizedSender) {
13
- logVerbose(`Ignoring /bash from unauthorized sender: ${command.senderId || "<unknown>"}`);
14
- return { shouldContinue: false };
13
+ const unauthorized = rejectUnauthorizedCommand(params, "/bash");
14
+ if (unauthorized) {
15
+ return unauthorized;
15
16
  }
16
17
  const reply = await handleBashChatCommand({
17
18
  ctx: params.ctx,