@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,36 +1,182 @@
1
- import { approveNodePairing, listNodePairing, rejectNodePairing, renamePairedNode, requestNodePairing, verifyNodeToken, } from "../../infra/node-pairing.js";
2
- import { listDevicePairing } from "../../infra/device-pairing.js";
3
- import { ErrorCodes, errorShape, validateNodeDescribeParams, validateNodeEventParams, validateNodeInvokeParams, validateNodeInvokeResultParams, validateNodeListParams, validateNodePairApproveParams, validateNodePairListParams, validateNodePairRejectParams, validateNodePairRequestParams, validateNodePairVerifyParams, validateNodeRenameParams, } from "../protocol/index.js";
4
- import { respondInvalidParams, respondUnavailableOnThrow, safeParseJson, uniqueSortedStrings, } from "./nodes.helpers.js";
5
1
  import { loadConfig } from "../../config/config.js";
2
+ import { listDevicePairing } from "../../infra/device-pairing.js";
3
+ import { approveNodePairing, listNodePairing, rejectNodePairing, renamePairedNode, requestNodePairing, verifyNodeToken, } from "../../infra/node-pairing.js";
4
+ import { loadApnsRegistration, resolveApnsAuthConfigFromEnv, sendApnsAlert, sendApnsBackgroundWake, } from "../../infra/push-apns.js";
6
5
  import { isNodeCommandAllowed, resolveNodeCommandAllowlist } from "../node-command-policy.js";
6
+ import { sanitizeNodeInvokeParamsForForwarding } from "../node-invoke-sanitize.js";
7
+ import { ErrorCodes, errorShape, validateNodeDescribeParams, validateNodeEventParams, validateNodeInvokeParams, validateNodeListParams, validateNodePairApproveParams, validateNodePairListParams, validateNodePairRejectParams, validateNodePairRequestParams, validateNodePairVerifyParams, validateNodeRenameParams, } from "../protocol/index.js";
8
+ import { handleNodeInvokeResult } from "./nodes.handlers.invoke-result.js";
9
+ import { respondInvalidParams, respondUnavailableOnNodeInvokeError, respondUnavailableOnThrow, safeParseJson, uniqueSortedStrings, } from "./nodes.helpers.js";
10
+ const NODE_WAKE_RECONNECT_WAIT_MS = 3_000;
11
+ const NODE_WAKE_RECONNECT_RETRY_WAIT_MS = 12_000;
12
+ const NODE_WAKE_RECONNECT_POLL_MS = 150;
13
+ const NODE_WAKE_THROTTLE_MS = 15_000;
14
+ const NODE_WAKE_NUDGE_THROTTLE_MS = 10 * 60_000;
15
+ const nodeWakeById = new Map();
16
+ const nodeWakeNudgeById = new Map();
7
17
  function isNodeEntry(entry) {
8
- if (entry.clientMode === "node")
18
+ if (entry.role === "node") {
9
19
  return true;
10
- if (entry.role === "node")
11
- return true;
12
- if (Array.isArray(entry.roles) && entry.roles.includes("node"))
20
+ }
21
+ if (Array.isArray(entry.roles) && entry.roles.includes("node")) {
13
22
  return true;
23
+ }
14
24
  return false;
15
25
  }
16
- function normalizeNodeInvokeResultParams(params) {
17
- if (!params || typeof params !== "object")
18
- return params;
19
- const raw = params;
20
- const normalized = { ...raw };
21
- if (normalized.payloadJSON === null) {
22
- delete normalized.payloadJSON;
26
+ async function delayMs(ms) {
27
+ await new Promise((resolve) => setTimeout(resolve, ms));
28
+ }
29
+ async function maybeWakeNodeWithApns(nodeId, opts) {
30
+ const state = nodeWakeById.get(nodeId) ?? { lastWakeAtMs: 0 };
31
+ nodeWakeById.set(nodeId, state);
32
+ if (state.inFlight) {
33
+ return await state.inFlight;
34
+ }
35
+ const now = Date.now();
36
+ const force = opts?.force === true;
37
+ if (!force && state.lastWakeAtMs > 0 && now - state.lastWakeAtMs < NODE_WAKE_THROTTLE_MS) {
38
+ return { available: true, throttled: true, path: "throttled", durationMs: 0 };
39
+ }
40
+ state.inFlight = (async () => {
41
+ const startedAtMs = Date.now();
42
+ const withDuration = (attempt) => ({
43
+ ...attempt,
44
+ durationMs: Math.max(0, Date.now() - startedAtMs),
45
+ });
46
+ try {
47
+ const registration = await loadApnsRegistration(nodeId);
48
+ if (!registration) {
49
+ return withDuration({ available: false, throttled: false, path: "no-registration" });
50
+ }
51
+ const auth = await resolveApnsAuthConfigFromEnv(process.env);
52
+ if (!auth.ok) {
53
+ return withDuration({
54
+ available: false,
55
+ throttled: false,
56
+ path: "no-auth",
57
+ apnsReason: auth.error,
58
+ });
59
+ }
60
+ state.lastWakeAtMs = Date.now();
61
+ const wakeResult = await sendApnsBackgroundWake({
62
+ auth: auth.value,
63
+ registration,
64
+ nodeId,
65
+ wakeReason: "node.invoke",
66
+ });
67
+ if (!wakeResult.ok) {
68
+ return withDuration({
69
+ available: true,
70
+ throttled: false,
71
+ path: "send-error",
72
+ apnsStatus: wakeResult.status,
73
+ apnsReason: wakeResult.reason,
74
+ });
75
+ }
76
+ return withDuration({
77
+ available: true,
78
+ throttled: false,
79
+ path: "sent",
80
+ apnsStatus: wakeResult.status,
81
+ apnsReason: wakeResult.reason,
82
+ });
83
+ }
84
+ catch (err) {
85
+ // Best-effort wake only.
86
+ const message = err instanceof Error ? err.message : String(err);
87
+ if (state.lastWakeAtMs === 0) {
88
+ return withDuration({
89
+ available: false,
90
+ throttled: false,
91
+ path: "send-error",
92
+ apnsReason: message,
93
+ });
94
+ }
95
+ return withDuration({
96
+ available: true,
97
+ throttled: false,
98
+ path: "send-error",
99
+ apnsReason: message,
100
+ });
101
+ }
102
+ })();
103
+ try {
104
+ return await state.inFlight;
105
+ }
106
+ finally {
107
+ state.inFlight = undefined;
108
+ }
109
+ }
110
+ async function maybeSendNodeWakeNudge(nodeId) {
111
+ const startedAtMs = Date.now();
112
+ const withDuration = (attempt) => ({
113
+ ...attempt,
114
+ durationMs: Math.max(0, Date.now() - startedAtMs),
115
+ });
116
+ const lastNudgeAtMs = nodeWakeNudgeById.get(nodeId) ?? 0;
117
+ if (lastNudgeAtMs > 0 && Date.now() - lastNudgeAtMs < NODE_WAKE_NUDGE_THROTTLE_MS) {
118
+ return withDuration({ sent: false, throttled: true, reason: "throttled" });
119
+ }
120
+ const registration = await loadApnsRegistration(nodeId);
121
+ if (!registration) {
122
+ return withDuration({ sent: false, throttled: false, reason: "no-registration" });
123
+ }
124
+ const auth = await resolveApnsAuthConfigFromEnv(process.env);
125
+ if (!auth.ok) {
126
+ return withDuration({
127
+ sent: false,
128
+ throttled: false,
129
+ reason: "no-auth",
130
+ apnsReason: auth.error,
131
+ });
23
132
  }
24
- else if (normalized.payloadJSON !== undefined && typeof normalized.payloadJSON !== "string") {
25
- if (normalized.payload === undefined) {
26
- normalized.payload = normalized.payloadJSON;
133
+ try {
134
+ const result = await sendApnsAlert({
135
+ auth: auth.value,
136
+ registration,
137
+ nodeId,
138
+ title: "Pool Bot needs a quick reopen",
139
+ body: "Tap to reopen Pool Bot and restore the node connection.",
140
+ });
141
+ if (!result.ok) {
142
+ return withDuration({
143
+ sent: false,
144
+ throttled: false,
145
+ reason: "apns-not-ok",
146
+ apnsStatus: result.status,
147
+ apnsReason: result.reason,
148
+ });
27
149
  }
28
- delete normalized.payloadJSON;
150
+ nodeWakeNudgeById.set(nodeId, Date.now());
151
+ return withDuration({
152
+ sent: true,
153
+ throttled: false,
154
+ reason: "sent",
155
+ apnsStatus: result.status,
156
+ apnsReason: result.reason,
157
+ });
29
158
  }
30
- if (normalized.error === null) {
31
- delete normalized.error;
159
+ catch (err) {
160
+ const message = err instanceof Error ? err.message : String(err);
161
+ return withDuration({
162
+ sent: false,
163
+ throttled: false,
164
+ reason: "send-error",
165
+ apnsReason: message,
166
+ });
167
+ }
168
+ }
169
+ async function waitForNodeReconnect(params) {
170
+ const timeoutMs = Math.max(250, params.timeoutMs ?? NODE_WAKE_RECONNECT_WAIT_MS);
171
+ const pollMs = Math.max(50, params.pollMs ?? NODE_WAKE_RECONNECT_POLL_MS);
172
+ const deadline = Date.now() + timeoutMs;
173
+ while (Date.now() < deadline) {
174
+ if (params.context.nodeRegistry.get(params.nodeId)) {
175
+ return true;
176
+ }
177
+ await delayMs(pollMs);
32
178
  }
33
- return normalized;
179
+ return Boolean(params.context.nodeRegistry.get(params.nodeId));
34
180
  }
35
181
  export const nodeHandlers = {
36
182
  "node.pair.request": async ({ params, respond, context }) => {
@@ -227,14 +373,17 @@ export const nodeHandlers = {
227
373
  };
228
374
  });
229
375
  nodes.sort((a, b) => {
230
- if (a.connected !== b.connected)
376
+ if (a.connected !== b.connected) {
231
377
  return a.connected ? -1 : 1;
378
+ }
232
379
  const an = (a.displayName ?? a.nodeId).toLowerCase();
233
380
  const bn = (b.displayName ?? b.nodeId).toLowerCase();
234
- if (an < bn)
381
+ if (an < bn) {
235
382
  return -1;
236
- if (an > bn)
383
+ }
384
+ if (an > bn) {
237
385
  return 1;
386
+ }
238
387
  return a.nodeId.localeCompare(b.nodeId);
239
388
  });
240
389
  respond(true, { ts: Date.now(), nodes }, undefined);
@@ -287,7 +436,7 @@ export const nodeHandlers = {
287
436
  }, undefined);
288
437
  });
289
438
  },
290
- "node.invoke": async ({ params, respond, context }) => {
439
+ "node.invoke": async ({ params, respond, context, client, req }) => {
291
440
  if (!validateNodeInvokeParams(params)) {
292
441
  respondInvalidParams({
293
442
  respond,
@@ -303,13 +452,69 @@ export const nodeHandlers = {
303
452
  respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId and command required"));
304
453
  return;
305
454
  }
455
+ if (command === "system.execApprovals.get" || command === "system.execApprovals.set") {
456
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "node.invoke does not allow system.execApprovals.*; use exec.approvals.node.*", { details: { command } }));
457
+ return;
458
+ }
306
459
  await respondUnavailableOnThrow(respond, async () => {
307
- const nodeSession = context.nodeRegistry.get(nodeId);
460
+ let nodeSession = context.nodeRegistry.get(nodeId);
308
461
  if (!nodeSession) {
309
- respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "node not connected", {
310
- details: { code: "NOT_CONNECTED" },
311
- }));
312
- return;
462
+ const wakeReqId = req.id;
463
+ const wakeFlowStartedAtMs = Date.now();
464
+ context.logGateway.info(`node wake start node=${nodeId} req=${wakeReqId} command=${command}`);
465
+ const wake = await maybeWakeNodeWithApns(nodeId);
466
+ context.logGateway.info(`node wake stage=wake1 node=${nodeId} req=${wakeReqId} ` +
467
+ `available=${wake.available} throttled=${wake.throttled} ` +
468
+ `path=${wake.path} durationMs=${wake.durationMs} ` +
469
+ `apnsStatus=${wake.apnsStatus ?? -1} apnsReason=${wake.apnsReason ?? "-"}`);
470
+ if (wake.available) {
471
+ const waitStartedAtMs = Date.now();
472
+ const waitTimeoutMs = NODE_WAKE_RECONNECT_WAIT_MS;
473
+ const reconnected = await waitForNodeReconnect({
474
+ nodeId,
475
+ context,
476
+ timeoutMs: waitTimeoutMs,
477
+ });
478
+ const waitDurationMs = Math.max(0, Date.now() - waitStartedAtMs);
479
+ context.logGateway.info(`node wake stage=wait1 node=${nodeId} req=${wakeReqId} ` +
480
+ `reconnected=${reconnected} timeoutMs=${waitTimeoutMs} durationMs=${waitDurationMs}`);
481
+ }
482
+ nodeSession = context.nodeRegistry.get(nodeId);
483
+ if (!nodeSession && wake.available) {
484
+ const retryWake = await maybeWakeNodeWithApns(nodeId, { force: true });
485
+ context.logGateway.info(`node wake stage=wake2 node=${nodeId} req=${wakeReqId} force=true ` +
486
+ `available=${retryWake.available} throttled=${retryWake.throttled} ` +
487
+ `path=${retryWake.path} durationMs=${retryWake.durationMs} ` +
488
+ `apnsStatus=${retryWake.apnsStatus ?? -1} apnsReason=${retryWake.apnsReason ?? "-"}`);
489
+ if (retryWake.available) {
490
+ const waitStartedAtMs = Date.now();
491
+ const waitTimeoutMs = NODE_WAKE_RECONNECT_RETRY_WAIT_MS;
492
+ const reconnected = await waitForNodeReconnect({
493
+ nodeId,
494
+ context,
495
+ timeoutMs: waitTimeoutMs,
496
+ });
497
+ const waitDurationMs = Math.max(0, Date.now() - waitStartedAtMs);
498
+ context.logGateway.info(`node wake stage=wait2 node=${nodeId} req=${wakeReqId} ` +
499
+ `reconnected=${reconnected} timeoutMs=${waitTimeoutMs} durationMs=${waitDurationMs}`);
500
+ }
501
+ nodeSession = context.nodeRegistry.get(nodeId);
502
+ }
503
+ if (!nodeSession) {
504
+ const totalDurationMs = Math.max(0, Date.now() - wakeFlowStartedAtMs);
505
+ const nudge = await maybeSendNodeWakeNudge(nodeId);
506
+ context.logGateway.info(`node wake nudge node=${nodeId} req=${wakeReqId} sent=${nudge.sent} ` +
507
+ `throttled=${nudge.throttled} reason=${nudge.reason} durationMs=${nudge.durationMs} ` +
508
+ `apnsStatus=${nudge.apnsStatus ?? -1} apnsReason=${nudge.apnsReason ?? "-"}`);
509
+ context.logGateway.warn(`node wake done node=${nodeId} req=${wakeReqId} connected=false ` +
510
+ `reason=not_connected totalMs=${totalDurationMs}`);
511
+ respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "node not connected", {
512
+ details: { code: "NOT_CONNECTED" },
513
+ }));
514
+ return;
515
+ }
516
+ const totalDurationMs = Math.max(0, Date.now() - wakeFlowStartedAtMs);
517
+ context.logGateway.info(`node wake done node=${nodeId} req=${wakeReqId} connected=true totalMs=${totalDurationMs}`);
313
518
  }
314
519
  const cfg = loadConfig();
315
520
  const allowlist = resolveNodeCommandAllowlist(cfg, nodeSession);
@@ -324,17 +529,26 @@ export const nodeHandlers = {
324
529
  }));
325
530
  return;
326
531
  }
532
+ const forwardedParams = sanitizeNodeInvokeParamsForForwarding({
533
+ command,
534
+ rawParams: p.params,
535
+ client,
536
+ execApprovalManager: context.execApprovalManager,
537
+ });
538
+ if (!forwardedParams.ok) {
539
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, forwardedParams.message, {
540
+ details: forwardedParams.details ?? null,
541
+ }));
542
+ return;
543
+ }
327
544
  const res = await context.nodeRegistry.invoke({
328
545
  nodeId,
329
546
  command,
330
- params: p.params,
547
+ params: forwardedParams.params,
331
548
  timeoutMs: p.timeoutMs,
332
549
  idempotencyKey: p.idempotencyKey,
333
550
  });
334
- if (!res.ok) {
335
- respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", {
336
- details: { nodeError: res.error ?? null },
337
- }));
551
+ if (!respondUnavailableOnNodeInvokeError(respond, res)) {
338
552
  return;
339
553
  }
340
554
  const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;
@@ -347,39 +561,7 @@ export const nodeHandlers = {
347
561
  }, undefined);
348
562
  });
349
563
  },
350
- "node.invoke.result": async ({ params, respond, context, client }) => {
351
- const normalizedParams = normalizeNodeInvokeResultParams(params);
352
- if (!validateNodeInvokeResultParams(normalizedParams)) {
353
- respondInvalidParams({
354
- respond,
355
- method: "node.invoke.result",
356
- validator: validateNodeInvokeResultParams,
357
- });
358
- return;
359
- }
360
- const p = normalizedParams;
361
- const callerNodeId = client?.connect?.device?.id ?? client?.connect?.client?.id;
362
- if (callerNodeId && callerNodeId !== p.nodeId) {
363
- respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId mismatch"));
364
- return;
365
- }
366
- const ok = context.nodeRegistry.handleInvokeResult({
367
- id: p.id,
368
- nodeId: p.nodeId,
369
- ok: p.ok,
370
- payload: p.payload,
371
- payloadJSON: p.payloadJSON ?? null,
372
- error: p.error ?? null,
373
- });
374
- if (!ok) {
375
- // Late-arriving results (after invoke timeout) are expected and harmless.
376
- // Return success instead of error to reduce log noise; client can discard.
377
- context.logGateway.debug(`late invoke result ignored: id=${p.id} node=${p.nodeId}`);
378
- respond(true, { ok: true, ignored: true }, undefined);
379
- return;
380
- }
381
- respond(true, { ok: true }, undefined);
382
- },
564
+ "node.invoke.result": handleNodeInvokeResult,
383
565
  "node.event": async ({ params, respond, context, client }) => {
384
566
  if (!validateNodeEventParams(params)) {
385
567
  respondInvalidParams({
@@ -0,0 +1,53 @@
1
+ import { loadApnsRegistration, normalizeApnsEnvironment, resolveApnsAuthConfigFromEnv, sendApnsAlert, } from "../../infra/push-apns.js";
2
+ import { ErrorCodes, errorShape, validatePushTestParams } from "../protocol/index.js";
3
+ import { respondInvalidParams, respondUnavailableOnThrow } from "./nodes.helpers.js";
4
+ function normalizeOptionalString(value) {
5
+ if (typeof value !== "string") {
6
+ return undefined;
7
+ }
8
+ const trimmed = value.trim();
9
+ return trimmed.length > 0 ? trimmed : undefined;
10
+ }
11
+ export const pushHandlers = {
12
+ "push.test": async ({ params, respond }) => {
13
+ if (!validatePushTestParams(params)) {
14
+ respondInvalidParams({
15
+ respond,
16
+ method: "push.test",
17
+ validator: validatePushTestParams,
18
+ });
19
+ return;
20
+ }
21
+ const nodeId = String(params.nodeId ?? "").trim();
22
+ if (!nodeId) {
23
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId required"));
24
+ return;
25
+ }
26
+ const title = normalizeOptionalString(params.title) ?? "Pool Bot";
27
+ const body = normalizeOptionalString(params.body) ?? `Push test for node ${nodeId}`;
28
+ await respondUnavailableOnThrow(respond, async () => {
29
+ const registration = await loadApnsRegistration(nodeId);
30
+ if (!registration) {
31
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `node ${nodeId} has no APNs registration (connect iOS node first)`));
32
+ return;
33
+ }
34
+ const auth = await resolveApnsAuthConfigFromEnv(process.env);
35
+ if (!auth.ok) {
36
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, auth.error));
37
+ return;
38
+ }
39
+ const overrideEnvironment = normalizeApnsEnvironment(params.environment);
40
+ const result = await sendApnsAlert({
41
+ auth: auth.value,
42
+ registration: {
43
+ ...registration,
44
+ environment: overrideEnvironment ?? registration.environment,
45
+ },
46
+ nodeId,
47
+ title,
48
+ body,
49
+ });
50
+ respond(true, result, undefined);
51
+ });
52
+ },
53
+ };
@@ -6,8 +6,10 @@ import { stopSubagentsForRequester } from "../../auto-reply/reply/abort.js";
6
6
  import { clearSessionQueues } from "../../auto-reply/reply/queue.js";
7
7
  import { loadConfig } from "../../config/config.js";
8
8
  import { loadSessionStore, snapshotSessionOrigin, resolveMainSessionKey, updateSessionStore, } from "../../config/sessions.js";
9
+ import { unbindThreadBindingsBySessionKey } from "../../discord/monitor/thread-bindings.js";
9
10
  import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
10
- import { normalizeAgentId, parseAgentSessionKey } from "../../routing/session-key.js";
11
+ import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
12
+ import { isSubagentSessionKey, normalizeAgentId, parseAgentSessionKey, } from "../../routing/session-key.js";
11
13
  import { ErrorCodes, errorShape, validateSessionsCompactParams, validateSessionsDeleteParams, validateSessionsListParams, validateSessionsPatchParams, validateSessionsPreviewParams, validateSessionsResetParams, validateSessionsResolveParams, } from "../protocol/index.js";
12
14
  import { archiveFileOnDisk, archiveSessionTranscripts, listSessionsFromStore, loadCombinedSessionStoreForGateway, loadSessionEntry, pruneLegacyStoreKeys, readSessionPreviewItemsFromTranscript, resolveGatewaySessionStoreTarget, resolveSessionModelRef, resolveSessionTranscriptCandidates, } from "../session-utils.js";
13
15
  import { applySessionsPatchToStore } from "../sessions-patch.js";
@@ -33,6 +35,13 @@ function resolveGatewaySessionTargetFromKey(key) {
33
35
  const target = resolveGatewaySessionStoreTarget({ cfg, key });
34
36
  return { cfg, target, storePath: target.storePath };
35
37
  }
38
+ function rejectWebchatSessionMutation(params) {
39
+ if (!params.client?.connect || !params.isWebchatConnect(params.client.connect)) {
40
+ return false;
41
+ }
42
+ params.respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `webchat clients cannot ${params.action} sessions; use chat.send for session-scoped updates`));
43
+ return true;
44
+ }
36
45
  function migrateAndPruneSessionStoreKey(params) {
37
46
  const target = resolveGatewaySessionStoreTarget({
38
47
  cfg: params.cfg,
@@ -65,6 +74,31 @@ function archiveSessionTranscriptsForSession(params) {
65
74
  reason: params.reason,
66
75
  });
67
76
  }
77
+ async function emitSessionUnboundLifecycleEvent(params) {
78
+ const targetKind = isSubagentSessionKey(params.targetSessionKey) ? "subagent" : "acp";
79
+ unbindThreadBindingsBySessionKey({
80
+ targetSessionKey: params.targetSessionKey,
81
+ targetKind,
82
+ reason: params.reason,
83
+ sendFarewell: true,
84
+ });
85
+ if (params.emitHooks === false) {
86
+ return;
87
+ }
88
+ const hookRunner = getGlobalHookRunner();
89
+ if (!hookRunner?.hasHooks("subagent_ended")) {
90
+ return;
91
+ }
92
+ await hookRunner.runSubagentEnded({
93
+ targetSessionKey: params.targetSessionKey,
94
+ targetKind,
95
+ reason: params.reason,
96
+ sendFarewell: true,
97
+ outcome: params.reason === "session-reset" ? "reset" : "deleted",
98
+ }, {
99
+ childSessionKey: params.targetSessionKey,
100
+ });
101
+ }
68
102
  async function ensureSessionRuntimeCleanup(params) {
69
103
  const queueKeys = new Set(params.target.storeKeys);
70
104
  queueKeys.add(params.target.canonicalKey);
@@ -161,7 +195,7 @@ export const sessionsHandlers = {
161
195
  }
162
196
  respond(true, { ok: true, key: resolved.key }, undefined);
163
197
  },
164
- "sessions.patch": async ({ params, respond, context }) => {
198
+ "sessions.patch": async ({ params, respond, context, client, isWebchatConnect }) => {
165
199
  if (!assertValidParams(params, validateSessionsPatchParams, "sessions.patch", respond)) {
166
200
  return;
167
201
  }
@@ -170,6 +204,9 @@ export const sessionsHandlers = {
170
204
  if (!key) {
171
205
  return;
172
206
  }
207
+ if (rejectWebchatSessionMutation({ action: "patch", client, isWebchatConnect, respond })) {
208
+ return;
209
+ }
173
210
  const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
174
211
  const applied = await updateSessionStore(storePath, async (store) => {
175
212
  const { primaryKey } = migrateAndPruneSessionStoreKey({ cfg, key, store });
@@ -211,6 +248,7 @@ export const sessionsHandlers = {
211
248
  }
212
249
  const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
213
250
  const { entry } = loadSessionEntry(key);
251
+ const hadExistingEntry = Boolean(entry);
214
252
  const commandReason = p.reason === "new" ? "new" : "reset";
215
253
  const hookEvent = createInternalHookEvent("command", commandReason, target.canonicalKey ?? key, {
216
254
  sessionEntry: entry,
@@ -267,9 +305,15 @@ export const sessionsHandlers = {
267
305
  agentId: target.agentId,
268
306
  reason: "reset",
269
307
  });
308
+ if (hadExistingEntry) {
309
+ await emitSessionUnboundLifecycleEvent({
310
+ targetSessionKey: target.canonicalKey ?? key,
311
+ reason: "session-reset",
312
+ });
313
+ }
270
314
  respond(true, { ok: true, key: target.canonicalKey, entry: next }, undefined);
271
315
  },
272
- "sessions.delete": async ({ params, respond }) => {
316
+ "sessions.delete": async ({ params, respond, client, isWebchatConnect }) => {
273
317
  if (!assertValidParams(params, validateSessionsDeleteParams, "sessions.delete", respond)) {
274
318
  return;
275
319
  }
@@ -278,6 +322,9 @@ export const sessionsHandlers = {
278
322
  if (!key) {
279
323
  return;
280
324
  }
325
+ if (rejectWebchatSessionMutation({ action: "delete", client, isWebchatConnect, respond })) {
326
+ return;
327
+ }
281
328
  const { cfg, target, storePath } = resolveGatewaySessionTargetFromKey(key);
282
329
  const mainKey = resolveMainSessionKey(cfg);
283
330
  if (target.canonicalKey === mainKey) {
@@ -287,19 +334,20 @@ export const sessionsHandlers = {
287
334
  const deleteTranscript = typeof p.deleteTranscript === "boolean" ? p.deleteTranscript : true;
288
335
  const { entry } = loadSessionEntry(key);
289
336
  const sessionId = entry?.sessionId;
290
- const existed = Boolean(entry);
291
337
  const cleanupError = await ensureSessionRuntimeCleanup({ cfg, key, target, sessionId });
292
338
  if (cleanupError) {
293
339
  respond(false, undefined, cleanupError);
294
340
  return;
295
341
  }
296
- await updateSessionStore(storePath, (store) => {
342
+ const deleted = await updateSessionStore(storePath, (store) => {
297
343
  const { primaryKey } = migrateAndPruneSessionStoreKey({ cfg, key, store });
298
- if (store[primaryKey]) {
344
+ const hadEntry = Boolean(store[primaryKey]);
345
+ if (hadEntry) {
299
346
  delete store[primaryKey];
300
347
  }
348
+ return hadEntry;
301
349
  });
302
- const archived = deleteTranscript
350
+ const archived = deleted && deleteTranscript
303
351
  ? archiveSessionTranscriptsForSession({
304
352
  sessionId,
305
353
  storePath,
@@ -308,7 +356,15 @@ export const sessionsHandlers = {
308
356
  reason: "deleted",
309
357
  })
310
358
  : [];
311
- respond(true, { ok: true, key: target.canonicalKey, deleted: existed, archived }, undefined);
359
+ if (deleted) {
360
+ const emitLifecycleHooks = p.emitLifecycleHooks !== false;
361
+ await emitSessionUnboundLifecycleEvent({
362
+ targetSessionKey: target.canonicalKey ?? key,
363
+ reason: "session-delete",
364
+ emitHooks: emitLifecycleHooks,
365
+ });
366
+ }
367
+ respond(true, { ok: true, key: target.canonicalKey, deleted, archived }, undefined);
312
368
  },
313
369
  "sessions.compact": async ({ params, respond }) => {
314
370
  if (!assertValidParams(params, validateSessionsCompactParams, "sessions.compact", respond)) {