@poolzin/pool-bot 2026.2.25 → 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 (506) hide show
  1. package/dist/acp/event-mapper.js +87 -22
  2. package/dist/acp/meta.js +12 -6
  3. package/dist/agents/agent-paths.js +8 -9
  4. package/dist/agents/agent-scope.js +7 -5
  5. package/dist/agents/auth-profiles/oauth.js +148 -64
  6. package/dist/agents/auth-profiles/session-override.js +13 -7
  7. package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
  8. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  9. package/dist/agents/bedrock-discovery.js +3 -1
  10. package/dist/agents/byteplus-models.js +97 -0
  11. package/dist/agents/chutes-oauth.js +1 -0
  12. package/dist/agents/cli-runner/helpers.js +4 -0
  13. package/dist/agents/compaction.js +41 -14
  14. package/dist/agents/doubao-models.js +121 -0
  15. package/dist/agents/failover-error.js +2 -0
  16. package/dist/agents/huggingface-models.js +5 -3
  17. package/dist/agents/live-model-filter.js +5 -0
  18. package/dist/agents/minimax-vlm.js +10 -8
  19. package/dist/agents/model-auth.js +6 -0
  20. package/dist/agents/model-catalog.js +3 -1
  21. package/dist/agents/model-selection.js +7 -1
  22. package/dist/agents/models-config.providers.js +93 -11
  23. package/dist/agents/ollama-stream.js +117 -4
  24. package/dist/agents/opencode-zen-models.js +22 -11
  25. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  26. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  27. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  28. package/dist/agents/pi-embedded-helpers.js +1 -1
  29. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  30. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  31. package/dist/agents/pi-embedded-runner/google.js +20 -8
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  33. package/dist/agents/pi-embedded-runner/run.js +71 -12
  34. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  35. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  36. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  37. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  38. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  39. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  40. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  41. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  42. package/dist/agents/pi-embedded-subscribe.js +9 -4
  43. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  44. package/dist/agents/pi-embedded-utils.js +3 -0
  45. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  46. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  47. package/dist/agents/pi-settings.js +40 -0
  48. package/dist/agents/pi-tools.policy.js +2 -1
  49. package/dist/agents/provider/config-loader.js +1 -1
  50. package/dist/agents/sandbox/browser.js +170 -33
  51. package/dist/agents/sandbox/config-hash.js +14 -27
  52. package/dist/agents/sandbox/config.js +21 -2
  53. package/dist/agents/sandbox/constants.js +2 -0
  54. package/dist/agents/sandbox/docker.js +16 -2
  55. package/dist/agents/sandbox/novnc-auth.js +62 -0
  56. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  57. package/dist/agents/sandbox/shared.js +10 -6
  58. package/dist/agents/sandbox-paths.js +24 -11
  59. package/dist/agents/schema/clean-for-gemini.js +132 -85
  60. package/dist/agents/session-slug.js +10 -5
  61. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  62. package/dist/agents/session-tool-result-guard.js +3 -1
  63. package/dist/agents/session-transcript-repair.js +40 -6
  64. package/dist/agents/skills/bundled-dir.js +19 -5
  65. package/dist/agents/skills/env-overrides.js +124 -43
  66. package/dist/agents/skills/frontmatter.js +6 -6
  67. package/dist/agents/skills/plugin-skills.js +14 -7
  68. package/dist/agents/skills/workspace.js +1 -0
  69. package/dist/agents/subagent-announce.js +251 -49
  70. package/dist/agents/subagent-lifecycle-events.js +19 -0
  71. package/dist/agents/subagent-registry-cleanup.js +31 -0
  72. package/dist/agents/subagent-registry-completion.js +68 -0
  73. package/dist/agents/subagent-registry-queries.js +117 -0
  74. package/dist/agents/subagent-registry-state.js +46 -0
  75. package/dist/agents/subagent-registry.js +252 -221
  76. package/dist/agents/subagent-registry.store.js +1 -0
  77. package/dist/agents/subagent-registry.types.js +1 -0
  78. package/dist/agents/subagent-spawn.js +195 -7
  79. package/dist/agents/system-prompt.js +22 -6
  80. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  81. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  82. package/dist/agents/timeout.js +18 -6
  83. package/dist/agents/tool-call-id.js +1 -1
  84. package/dist/agents/tool-display-common.js +162 -29
  85. package/dist/agents/tool-images.js +82 -9
  86. package/dist/agents/tool-policy.js +51 -26
  87. package/dist/agents/tools/browser-tool.js +2 -2
  88. package/dist/agents/tools/canvas-tool.js +27 -1
  89. package/dist/agents/tools/common.js +45 -0
  90. package/dist/agents/tools/discord-actions-guild.js +4 -1
  91. package/dist/agents/tools/gateway-tool.js +3 -1
  92. package/dist/agents/tools/nodes-utils.js +1 -10
  93. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  94. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  95. package/dist/agents/tools/subagents-tool.js +2 -1
  96. package/dist/agents/tools/whatsapp-actions.js +10 -2
  97. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  98. package/dist/agents/transcript-policy.js +22 -8
  99. package/dist/agents/venice-models.js +11 -3
  100. package/dist/auto-reply/commands-registry.data.js +51 -0
  101. package/dist/auto-reply/commands-registry.js +4 -3
  102. package/dist/auto-reply/group-activation.js +10 -5
  103. package/dist/auto-reply/inbound-debounce.js +10 -5
  104. package/dist/auto-reply/reply/abort.js +1 -1
  105. package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
  106. package/dist/auto-reply/reply/bash-command.js +41 -39
  107. package/dist/auto-reply/reply/command-gates.js +25 -0
  108. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  109. package/dist/auto-reply/reply/commands-bash.js +6 -5
  110. package/dist/auto-reply/reply/commands-config.js +30 -28
  111. package/dist/auto-reply/reply/commands-core.js +2 -1
  112. package/dist/auto-reply/reply/commands-info.js +1 -0
  113. package/dist/auto-reply/reply/commands-models.js +65 -14
  114. package/dist/auto-reply/reply/commands-session.js +237 -82
  115. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  116. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  117. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  118. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  119. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  120. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  121. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  122. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  123. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  124. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  125. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  126. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  127. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  128. package/dist/auto-reply/reply/commands-tts.js +10 -5
  129. package/dist/auto-reply/reply/config-value.js +10 -5
  130. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  131. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  132. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  133. package/dist/auto-reply/reply/followup-runner.js +1 -0
  134. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  135. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  136. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  137. package/dist/auto-reply/reply/get-reply.js +71 -12
  138. package/dist/auto-reply/reply/model-selection.js +80 -39
  139. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  140. package/dist/auto-reply/reply/queue/state.js +13 -12
  141. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  142. package/dist/auto-reply/reply/reply-reference.js +9 -8
  143. package/dist/auto-reply/reply/route-reply.js +15 -8
  144. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  145. package/dist/auto-reply/reply/session.js +22 -6
  146. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  147. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  148. package/dist/auto-reply/reply/typing.js +46 -21
  149. package/dist/auto-reply/send-policy.js +14 -7
  150. package/dist/auto-reply/status.js +140 -16
  151. package/dist/auto-reply/templating.js +10 -5
  152. package/dist/auto-reply/thinking.js +7 -16
  153. package/dist/auto-reply/tokens.js +21 -5
  154. package/dist/browser/bridge-server.js +36 -20
  155. package/dist/browser/cdp.helpers.js +7 -14
  156. package/dist/browser/cdp.js +35 -15
  157. package/dist/browser/chrome.profile-decoration.js +7 -4
  158. package/dist/browser/config.js +4 -0
  159. package/dist/browser/extension-relay-auth.js +55 -0
  160. package/dist/browser/extension-relay.js +74 -29
  161. package/dist/browser/navigation-guard.js +9 -1
  162. package/dist/browser/paths.js +77 -0
  163. package/dist/browser/profiles.js +13 -8
  164. package/dist/browser/pw-ai-module.js +10 -5
  165. package/dist/browser/pw-session.js +76 -39
  166. package/dist/browser/pw-tools-core.interactions.js +14 -7
  167. package/dist/browser/pw-tools-core.state.js +12 -6
  168. package/dist/browser/routes/agent.act.js +2 -2
  169. package/dist/browser/server-context.js +7 -0
  170. package/dist/build-info.json +3 -3
  171. package/dist/channels/allow-from.js +2 -1
  172. package/dist/channels/allowlists/resolve-utils.js +43 -19
  173. package/dist/channels/channel-config.js +14 -7
  174. package/dist/channels/draft-stream-loop.js +7 -0
  175. package/dist/channels/model-overrides.js +82 -0
  176. package/dist/channels/plugins/normalize/imessage.js +14 -7
  177. package/dist/channels/plugins/normalize/slack.js +10 -5
  178. package/dist/channels/plugins/normalize/telegram.js +14 -7
  179. package/dist/channels/plugins/outbound/discord.js +80 -8
  180. package/dist/channels/plugins/outbound/signal.js +11 -11
  181. package/dist/channels/plugins/setup-helpers.js +10 -5
  182. package/dist/channels/sender-label.js +14 -7
  183. package/dist/channels/session.js +4 -2
  184. package/dist/channels/status-reactions.js +297 -0
  185. package/dist/cli/banner.js +1 -1
  186. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  187. package/dist/cli/cli-name.js +11 -11
  188. package/dist/cli/cli-utils.js +13 -3
  189. package/dist/cli/command-format.js +1 -1
  190. package/dist/cli/config-cli.js +1 -1
  191. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  192. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  193. package/dist/cli/daemon-cli/restart-health.js +126 -0
  194. package/dist/cli/daemon-cli/status.gather.js +9 -13
  195. package/dist/cli/daemon-cli/status.print.js +2 -10
  196. package/dist/cli/deps.js +27 -22
  197. package/dist/cli/gateway-cli/run-loop.js +23 -5
  198. package/dist/cli/node-cli/register.js +14 -5
  199. package/dist/cli/nodes-media-utils.js +7 -2
  200. package/dist/cli/outbound-send-deps.js +2 -9
  201. package/dist/cli/outbound-send-mapping.js +11 -0
  202. package/dist/cli/pairing-cli.js +40 -14
  203. package/dist/cli/plugins-cli.js +34 -41
  204. package/dist/cli/ports.js +11 -10
  205. package/dist/cli/program/command-registry.js +2 -11
  206. package/dist/cli/program/command-tree.js +16 -0
  207. package/dist/cli/program/preaction.js +13 -9
  208. package/dist/cli/program/register.configure.js +3 -18
  209. package/dist/cli/program/register.maintenance.js +2 -2
  210. package/dist/cli/program/register.onboard.js +2 -0
  211. package/dist/cli/program/register.status-health-sessions.js +16 -17
  212. package/dist/cli/program/register.subclis.js +93 -52
  213. package/dist/cli/route.js +11 -7
  214. package/dist/cli/system-cli.js +36 -46
  215. package/dist/cli/update-cli/shared.js +22 -9
  216. package/dist/cli/update-cli/update-command.js +89 -14
  217. package/dist/cli/update-cli/wizard.js +6 -12
  218. package/dist/commands/agent/run-context.js +18 -5
  219. package/dist/commands/agent/session-store.js +17 -4
  220. package/dist/commands/agent.js +22 -2
  221. package/dist/commands/agents.bindings.js +14 -7
  222. package/dist/commands/agents.commands.add.js +13 -9
  223. package/dist/commands/agents.commands.identity.js +12 -6
  224. package/dist/commands/agents.commands.list.js +11 -6
  225. package/dist/commands/agents.config.js +8 -10
  226. package/dist/commands/agents.providers.js +12 -6
  227. package/dist/commands/auth-choice-options.js +103 -75
  228. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  229. package/dist/commands/auth-choice.apply.js +4 -0
  230. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  231. package/dist/commands/auth-choice.apply.openai.js +3 -1
  232. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  233. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  234. package/dist/commands/channels/remove.js +13 -6
  235. package/dist/commands/channels/shared.js +4 -14
  236. package/dist/commands/configure.commands.js +14 -0
  237. package/dist/commands/configure.gateway.js +2 -4
  238. package/dist/commands/configure.js +1 -1
  239. package/dist/commands/configure.shared.js +11 -0
  240. package/dist/commands/daemon-install-helpers.js +2 -2
  241. package/dist/commands/dashboard.js +12 -10
  242. package/dist/commands/docs.js +14 -8
  243. package/dist/commands/doctor-config-flow.js +11 -9
  244. package/dist/commands/doctor-legacy-config.js +281 -0
  245. package/dist/commands/doctor-state-integrity.js +99 -23
  246. package/dist/commands/doctor-update.js +12 -9
  247. package/dist/commands/models/list.list-command.js +7 -5
  248. package/dist/commands/models/set-image.js +2 -21
  249. package/dist/commands/node-daemon-install-helpers.js +10 -8
  250. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  251. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  252. package/dist/commands/onboard-auth.credentials.js +90 -13
  253. package/dist/commands/onboard-auth.js +1 -1
  254. package/dist/commands/onboard-auth.models.js +6 -5
  255. package/dist/commands/onboard-hooks.js +1 -1
  256. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  257. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  258. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  259. package/dist/commands/onboard-remote.js +14 -7
  260. package/dist/commands/onboard.js +11 -13
  261. package/dist/commands/sandbox-display.js +6 -5
  262. package/dist/commands/status-all/diagnosis.js +14 -10
  263. package/dist/commands/status-all/format.js +1 -0
  264. package/dist/commands/status.gateway-probe.js +1 -16
  265. package/dist/commands/systemd-linger.js +12 -6
  266. package/dist/config/agent-limits.js +2 -0
  267. package/dist/config/commands.js +30 -16
  268. package/dist/config/config-paths.js +9 -11
  269. package/dist/config/defaults.js +22 -2
  270. package/dist/config/discord-preview-streaming.js +104 -0
  271. package/dist/config/env-vars.js +37 -8
  272. package/dist/config/includes.js +4 -0
  273. package/dist/config/io.js +97 -12
  274. package/dist/config/legacy.migrations.part-1.js +189 -78
  275. package/dist/config/legacy.shared.js +3 -1
  276. package/dist/config/merge-patch.js +4 -0
  277. package/dist/config/prototype-keys.js +4 -0
  278. package/dist/config/schema.help.js +44 -7
  279. package/dist/config/schema.labels.js +38 -6
  280. package/dist/config/sessions/delivery-info.js +10 -3
  281. package/dist/config/sessions/main-session.js +10 -5
  282. package/dist/config/sessions/session-file.js +33 -0
  283. package/dist/config/sessions/session-key.js +10 -5
  284. package/dist/config/sessions/store.js +1 -1
  285. package/dist/config/sessions.js +1 -0
  286. package/dist/config/zod-schema.agent-runtime.js +11 -0
  287. package/dist/config/zod-schema.js +148 -13
  288. package/dist/config/zod-schema.providers-core.js +78 -4
  289. package/dist/config/zod-schema.providers.js +6 -1
  290. package/dist/config/zod-schema.session.js +41 -2
  291. package/dist/cron/run-log.js +3 -0
  292. package/dist/cron/schedule.js +21 -10
  293. package/dist/cron/service/ops.js +35 -21
  294. package/dist/cron/service/timer.js +116 -16
  295. package/dist/cron/stagger.js +3 -1
  296. package/dist/discord/api.js +12 -6
  297. package/dist/discord/draft-chunking.js +22 -0
  298. package/dist/discord/draft-stream.js +124 -0
  299. package/dist/discord/monitor/agent-components.js +1 -1
  300. package/dist/discord/monitor/commands.js +5 -0
  301. package/dist/discord/monitor/gateway-plugin.js +2 -1
  302. package/dist/discord/monitor/listeners.js +37 -27
  303. package/dist/discord/monitor/message-handler.js +4 -1
  304. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  305. package/dist/discord/monitor/message-handler.process.js +246 -217
  306. package/dist/discord/monitor/message-utils.js +143 -6
  307. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  308. package/dist/discord/monitor/model-picker.js +651 -0
  309. package/dist/discord/monitor/native-command.js +573 -16
  310. package/dist/discord/monitor/provider.allowlist.js +223 -0
  311. package/dist/discord/monitor/provider.js +275 -347
  312. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  313. package/dist/discord/monitor/reply-delivery.js +123 -16
  314. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  315. package/dist/discord/monitor/thread-bindings.js +4 -0
  316. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  317. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  318. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  319. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  320. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  321. package/dist/discord/resolve-users.js +33 -21
  322. package/dist/discord/send.channels.js +15 -0
  323. package/dist/discord/send.js +3 -2
  324. package/dist/discord/send.outbound.js +82 -26
  325. package/dist/discord/send.permissions.js +83 -30
  326. package/dist/discord/send.reactions.js +8 -4
  327. package/dist/discord/token.js +10 -5
  328. package/dist/discord/voice/command.js +263 -0
  329. package/dist/discord/voice/manager.js +531 -0
  330. package/dist/gateway/auth.js +34 -10
  331. package/dist/gateway/call.js +4 -16
  332. package/dist/gateway/client.js +28 -4
  333. package/dist/gateway/config-reload.js +3 -4
  334. package/dist/gateway/control-ui.js +219 -96
  335. package/dist/gateway/hooks-mapping.js +88 -38
  336. package/dist/gateway/http-auth-helpers.js +3 -2
  337. package/dist/gateway/http-endpoint-helpers.js +1 -0
  338. package/dist/gateway/net.js +54 -12
  339. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  340. package/dist/gateway/node-registry.js +10 -5
  341. package/dist/gateway/openai-http.js +1 -0
  342. package/dist/gateway/openresponses-http.js +1 -0
  343. package/dist/gateway/origin-check.js +1 -18
  344. package/dist/gateway/protocol/index.js +4 -3
  345. package/dist/gateway/protocol/schema/cron.js +1 -0
  346. package/dist/gateway/protocol/schema/devices.js +1 -0
  347. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
  348. package/dist/gateway/protocol/schema/sessions.js +6 -0
  349. package/dist/gateway/role-policy.js +17 -0
  350. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  351. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  352. package/dist/gateway/server-chat.js +83 -25
  353. package/dist/gateway/server-constants.js +10 -9
  354. package/dist/gateway/server-cron.js +1 -0
  355. package/dist/gateway/server-http.js +16 -7
  356. package/dist/gateway/server-maintenance.js +20 -5
  357. package/dist/gateway/server-methods/chat.js +10 -6
  358. package/dist/gateway/server-methods/config.js +12 -14
  359. package/dist/gateway/server-methods/devices.js +17 -3
  360. package/dist/gateway/server-methods/models.js +11 -1
  361. package/dist/gateway/server-methods/sessions.js +64 -8
  362. package/dist/gateway/server-methods/usage.js +162 -75
  363. package/dist/gateway/server-node-events.js +29 -0
  364. package/dist/gateway/server-runtime-config.js +34 -13
  365. package/dist/gateway/server-startup-memory.js +17 -11
  366. package/dist/gateway/session-utils.fs.js +32 -34
  367. package/dist/gateway/sessions-resolve.js +17 -5
  368. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  369. package/dist/gateway/tools-invoke-http.js +21 -10
  370. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  371. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  372. package/dist/hooks/bundled/session-memory/handler.js +6 -5
  373. package/dist/hooks/frontmatter.js +6 -6
  374. package/dist/hooks/gmail-watcher.js +11 -6
  375. package/dist/hooks/internal-hooks.js +11 -1
  376. package/dist/hooks/llm-slug-generator.js +4 -1
  377. package/dist/hooks/workspace.js +47 -17
  378. package/dist/imessage/accounts.js +9 -20
  379. package/dist/imessage/monitor/inbound-processing.js +2 -1
  380. package/dist/infra/archive.js +174 -73
  381. package/dist/infra/control-ui-assets.js +14 -6
  382. package/dist/infra/device-pairing.js +108 -29
  383. package/dist/infra/env.js +10 -5
  384. package/dist/infra/exec-approvals-allowlist.js +122 -0
  385. package/dist/infra/exec-approvals-analysis.js +34 -3
  386. package/dist/infra/exec-approvals.js +5 -17
  387. package/dist/infra/exec-safe-bin-policy.js +53 -45
  388. package/dist/infra/fs-safe.js +71 -39
  389. package/dist/infra/gateway-lock.js +6 -2
  390. package/dist/infra/heartbeat-wake.js +6 -12
  391. package/dist/infra/host-env-security-policy.json +19 -0
  392. package/dist/infra/host-env-security.js +66 -0
  393. package/dist/infra/net/ssrf.js +131 -38
  394. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  395. package/dist/infra/outbound/channel-selection.js +12 -6
  396. package/dist/infra/outbound/envelope.js +1 -1
  397. package/dist/infra/outbound/format.js +12 -6
  398. package/dist/infra/outbound/payloads.js +14 -7
  399. package/dist/infra/outbound/session-binding-service.js +123 -0
  400. package/dist/infra/path-guards.js +25 -0
  401. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  402. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  403. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  404. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  405. package/dist/infra/retry-policy.js +4 -2
  406. package/dist/infra/retry.js +9 -5
  407. package/dist/infra/session-cost-usage.js +107 -59
  408. package/dist/infra/session-maintenance-warning.js +3 -1
  409. package/dist/infra/shell-env.js +98 -34
  410. package/dist/infra/ssh-config.js +12 -6
  411. package/dist/infra/system-run-command.js +49 -4
  412. package/dist/infra/update-channels.js +10 -5
  413. package/dist/line/accounts.js +5 -7
  414. package/dist/line/bot-access.js +8 -20
  415. package/dist/line/bot-handlers.js +3 -1
  416. package/dist/link-understanding/detect.js +15 -7
  417. package/dist/media/constants.js +15 -6
  418. package/dist/media/image-ops.js +7 -0
  419. package/dist/media/local-roots.js +3 -2
  420. package/dist/media-understanding/apply.js +4 -1
  421. package/dist/media-understanding/concurrency.js +8 -20
  422. package/dist/memory/backend-config.js +45 -6
  423. package/dist/memory/embeddings.js +10 -4
  424. package/dist/memory/fs-utils.js +23 -0
  425. package/dist/memory/manager-search.js +12 -6
  426. package/dist/memory/manager-sync-ops.js +12 -2
  427. package/dist/memory/qmd-manager.js +466 -53
  428. package/dist/memory/query-expansion.js +167 -3
  429. package/dist/memory/status-format.js +10 -5
  430. package/dist/memory/sync-memory-files.js +1 -1
  431. package/dist/node-host/invoke-system-run.js +281 -0
  432. package/dist/node-host/invoke.js +55 -337
  433. package/dist/pairing/pairing-store.js +22 -0
  434. package/dist/plugin-sdk/allow-from.js +1 -1
  435. package/dist/plugin-sdk/command-auth.js +3 -1
  436. package/dist/plugin-sdk/index.js +6 -3
  437. package/dist/plugin-sdk/webhook-targets.js +32 -0
  438. package/dist/plugins/bundled-dir.js +9 -6
  439. package/dist/plugins/hooks.js +50 -0
  440. package/dist/plugins/install.js +28 -16
  441. package/dist/plugins/runtime.js +3 -17
  442. package/dist/plugins/update.js +78 -12
  443. package/dist/process/spawn-utils.js +14 -7
  444. package/dist/providers/github-copilot-token.js +11 -6
  445. package/dist/providers/qwen-portal-oauth.js +14 -6
  446. package/dist/routing/account-id.js +30 -0
  447. package/dist/routing/resolve-route.js +3 -7
  448. package/dist/routing/session-key.js +2 -16
  449. package/dist/security/audit-channel.js +93 -2
  450. package/dist/security/audit-extra.async.js +159 -5
  451. package/dist/security/audit-extra.js +1 -1
  452. package/dist/security/audit-extra.sync.js +85 -6
  453. package/dist/security/audit.js +40 -4
  454. package/dist/security/dm-policy-shared.js +44 -0
  455. package/dist/security/external-content.js +26 -6
  456. package/dist/shared/entry-status.js +6 -0
  457. package/dist/shared/frontmatter.js +5 -5
  458. package/dist/shared/node-match.js +11 -4
  459. package/dist/shared/operator-scope-compat.js +8 -3
  460. package/dist/signal/accounts.js +7 -20
  461. package/dist/signal/monitor/event-handler.js +3 -1
  462. package/dist/slack/accounts.js +6 -19
  463. package/dist/slack/actions.js +11 -3
  464. package/dist/slack/monitor/auth.js +1 -1
  465. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  466. package/dist/slack/monitor/replies.js +15 -7
  467. package/dist/slack/monitor/slash.js +22 -13
  468. package/dist/slack/resolve-channels.js +10 -5
  469. package/dist/slack/send.js +102 -12
  470. package/dist/slack/stream-mode.js +10 -0
  471. package/dist/slack/streaming.js +4 -2
  472. package/dist/telegram/accounts.js +19 -14
  473. package/dist/telegram/bot/helpers.js +3 -5
  474. package/dist/telegram/bot-access.js +35 -36
  475. package/dist/telegram/bot-handlers.js +120 -148
  476. package/dist/telegram/bot-message-context.js +68 -9
  477. package/dist/telegram/bot-message-dispatch.js +155 -90
  478. package/dist/telegram/bot-native-commands.js +16 -0
  479. package/dist/telegram/draft-stream.js +14 -1
  480. package/dist/telegram/inline-buttons.js +5 -15
  481. package/dist/telegram/monitor.js +11 -7
  482. package/dist/telegram/network-config.js +19 -7
  483. package/dist/telegram/send.js +3 -2
  484. package/dist/telegram/sent-message-cache.js +5 -6
  485. package/dist/telegram/status-reaction-variants.js +208 -0
  486. package/dist/telegram/sticker-cache.js +11 -9
  487. package/dist/terminal/theme.js +12 -12
  488. package/dist/tts/tts.js +80 -567
  489. package/dist/tui/components/chat-log.js +41 -8
  490. package/dist/tui/theme/theme.js +10 -12
  491. package/dist/tui/tui-local-shell.js +16 -6
  492. package/dist/tui/tui.js +58 -6
  493. package/dist/utils/account-id.js +2 -4
  494. package/dist/utils/boolean.js +10 -5
  495. package/dist/utils/directive-tags.js +11 -0
  496. package/dist/utils/queue-helpers.js +67 -12
  497. package/dist/web/auto-reply/deliver-reply.js +8 -4
  498. package/dist/web/auto-reply/mentions.js +10 -5
  499. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  500. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  501. package/dist/web/inbound/access-control.js +5 -2
  502. package/dist/web/login-qr.js +12 -6
  503. package/dist/web/media.js +123 -16
  504. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  505. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  506. package/package.json +1 -1
@@ -8,7 +8,11 @@ export class SsrFBlockedError extends Error {
8
8
  this.name = "SsrFBlockedError";
9
9
  }
10
10
  }
11
- const BLOCKED_HOSTNAMES = new Set(["localhost", "metadata.google.internal"]);
11
+ const BLOCKED_HOSTNAMES = new Set([
12
+ "localhost",
13
+ "localhost.localdomain",
14
+ "metadata.google.internal",
15
+ ]);
12
16
  function normalizeHostnameSet(values) {
13
17
  if (!values || values.length === 0) {
14
18
  return new Set();
@@ -39,16 +43,72 @@ function matchesHostnameAllowlist(hostname, allowlist) {
39
43
  }
40
44
  return allowlist.some((pattern) => isHostnameAllowedByPattern(hostname, pattern));
41
45
  }
46
+ function parseStrictIpv4Octet(part) {
47
+ if (!/^[0-9]+$/.test(part)) {
48
+ return null;
49
+ }
50
+ const value = Number.parseInt(part, 10);
51
+ if (Number.isNaN(value) || value < 0 || value > 255) {
52
+ return null;
53
+ }
54
+ // Accept only canonical decimal octets (no leading zeros, no alternate radices).
55
+ if (part !== String(value)) {
56
+ return null;
57
+ }
58
+ return value;
59
+ }
42
60
  function parseIpv4(address) {
43
61
  const parts = address.split(".");
44
62
  if (parts.length !== 4) {
45
63
  return null;
46
64
  }
47
- const numbers = parts.map((part) => Number.parseInt(part, 10));
48
- if (numbers.some((value) => Number.isNaN(value) || value < 0 || value > 255)) {
49
- return null;
65
+ for (const part of parts) {
66
+ if (parseStrictIpv4Octet(part) === null) {
67
+ return null;
68
+ }
69
+ }
70
+ return parts.map((part) => Number.parseInt(part, 10));
71
+ }
72
+ function classifyIpv4Part(part) {
73
+ if (/^0x[0-9a-f]+$/i.test(part)) {
74
+ return "hex";
75
+ }
76
+ if (/^0x/i.test(part)) {
77
+ return "invalid-hex";
78
+ }
79
+ if (/^[0-9]+$/.test(part)) {
80
+ return "decimal";
81
+ }
82
+ return "non-numeric";
83
+ }
84
+ function isUnsupportedLegacyIpv4Literal(address) {
85
+ const parts = address.split(".");
86
+ if (parts.length === 0 || parts.length > 4) {
87
+ return false;
88
+ }
89
+ if (parts.some((part) => part.length === 0)) {
90
+ return true;
91
+ }
92
+ const partKinds = parts.map(classifyIpv4Part);
93
+ if (partKinds.some((kind) => kind === "non-numeric")) {
94
+ return false;
50
95
  }
51
- return numbers;
96
+ if (partKinds.some((kind) => kind === "invalid-hex")) {
97
+ return true;
98
+ }
99
+ if (parts.length !== 4) {
100
+ return true;
101
+ }
102
+ for (const part of parts) {
103
+ if (/^0x/i.test(part)) {
104
+ return true;
105
+ }
106
+ const value = Number.parseInt(part, 10);
107
+ if (Number.isNaN(value) || value > 255 || part !== String(value)) {
108
+ return true;
109
+ }
110
+ }
111
+ return false;
52
112
  }
53
113
  function stripIpv6ZoneId(address) {
54
114
  const index = address.indexOf("%");
@@ -148,6 +208,12 @@ const EMBEDDED_IPV4_RULES = [
148
208
  matches: (hextets) => hextets[0] === 0x2001 && hextets[1] === 0x0000,
149
209
  extract: (hextets) => [hextets[6] ^ 0xffff, hextets[7] ^ 0xffff],
150
210
  },
211
+ {
212
+ // ISATAP IID format: 000000ug00000000:5efe:w.x.y.z (RFC 5214 section 6.1).
213
+ // Match only the IID marker bits to avoid over-broad :5efe: detection.
214
+ matches: (hextets) => (hextets[4] & 0xfcff) === 0 && hextets[5] === 0x5efe,
215
+ extract: (hextets) => [hextets[6], hextets[7]],
216
+ },
151
217
  ];
152
218
  function extractIpv4FromEmbeddedIpv6(hextets) {
153
219
  for (const rule of EMBEDDED_IPV4_RULES) {
@@ -159,31 +225,49 @@ function extractIpv4FromEmbeddedIpv6(hextets) {
159
225
  }
160
226
  return null;
161
227
  }
162
- function isPrivateIpv4(parts) {
163
- const [octet1, octet2] = parts;
164
- if (octet1 === 0) {
165
- return true;
166
- }
167
- if (octet1 === 10) {
168
- return true;
169
- }
170
- if (octet1 === 127) {
171
- return true;
172
- }
173
- if (octet1 === 169 && octet2 === 254) {
174
- return true;
175
- }
176
- if (octet1 === 172 && octet2 >= 16 && octet2 <= 31) {
177
- return true;
178
- }
179
- if (octet1 === 192 && octet2 === 168) {
180
- return true;
228
+ function ipv4ToUint(parts) {
229
+ const [a, b, c, d] = parts;
230
+ return (((a << 24) >>> 0) | (b << 16) | (c << 8) | d) >>> 0;
231
+ }
232
+ function ipv4RangeFromCidr(cidr) {
233
+ const base = ipv4ToUint(cidr.base);
234
+ const hostBits = 32 - cidr.prefixLength;
235
+ const mask = cidr.prefixLength === 0 ? 0 : (0xffffffff << hostBits) >>> 0;
236
+ const start = (base & mask) >>> 0;
237
+ const end = (start | (~mask >>> 0)) >>> 0;
238
+ return [start, end];
239
+ }
240
+ const BLOCKED_IPV4_SPECIAL_USE_CIDRS = [
241
+ { base: [0, 0, 0, 0], prefixLength: 8 },
242
+ { base: [10, 0, 0, 0], prefixLength: 8 },
243
+ { base: [100, 64, 0, 0], prefixLength: 10 },
244
+ { base: [127, 0, 0, 0], prefixLength: 8 },
245
+ { base: [169, 254, 0, 0], prefixLength: 16 },
246
+ { base: [172, 16, 0, 0], prefixLength: 12 },
247
+ { base: [192, 0, 0, 0], prefixLength: 24 },
248
+ { base: [192, 0, 2, 0], prefixLength: 24 },
249
+ { base: [192, 88, 99, 0], prefixLength: 24 },
250
+ { base: [192, 168, 0, 0], prefixLength: 16 },
251
+ { base: [198, 18, 0, 0], prefixLength: 15 },
252
+ { base: [198, 51, 100, 0], prefixLength: 24 },
253
+ { base: [203, 0, 113, 0], prefixLength: 24 },
254
+ { base: [224, 0, 0, 0], prefixLength: 4 },
255
+ { base: [240, 0, 0, 0], prefixLength: 4 },
256
+ ];
257
+ const BLOCKED_IPV4_SPECIAL_USE_RANGES = BLOCKED_IPV4_SPECIAL_USE_CIDRS.map(ipv4RangeFromCidr);
258
+ function isBlockedIpv4SpecialUse(parts) {
259
+ if (parts.length !== 4) {
260
+ return false;
181
261
  }
182
- if (octet1 === 100 && octet2 >= 64 && octet2 <= 127) {
183
- return true;
262
+ const value = ipv4ToUint(parts);
263
+ for (const [start, end] of BLOCKED_IPV4_SPECIAL_USE_RANGES) {
264
+ if (value >= start && value <= end) {
265
+ return true;
266
+ }
184
267
  }
185
268
  return false;
186
269
  }
270
+ // Returns true for private/internal and special-use non-global addresses.
187
271
  export function isPrivateIpAddress(address) {
188
272
  let normalized = address.trim().toLowerCase();
189
273
  if (normalized.startsWith("[") && normalized.endsWith("]")) {
@@ -219,7 +303,7 @@ export function isPrivateIpAddress(address) {
219
303
  }
220
304
  const embeddedIpv4 = extractIpv4FromEmbeddedIpv6(hextets);
221
305
  if (embeddedIpv4) {
222
- return isPrivateIpv4(embeddedIpv4);
306
+ return isBlockedIpv4SpecialUse(embeddedIpv4);
223
307
  }
224
308
  // IPv6 private/internal ranges
225
309
  // - link-local: fe80::/10
@@ -238,16 +322,23 @@ export function isPrivateIpAddress(address) {
238
322
  return false;
239
323
  }
240
324
  const ipv4 = parseIpv4(normalized);
241
- if (!ipv4) {
242
- return false;
325
+ if (ipv4) {
326
+ return isBlockedIpv4SpecialUse(ipv4);
243
327
  }
244
- return isPrivateIpv4(ipv4);
328
+ // Reject non-canonical IPv4 literal forms (octal/hex/short/packed) by default.
329
+ if (isUnsupportedLegacyIpv4Literal(normalized)) {
330
+ return true;
331
+ }
332
+ return false;
245
333
  }
246
334
  export function isBlockedHostname(hostname) {
247
335
  const normalized = normalizeHostname(hostname);
248
336
  if (!normalized) {
249
337
  return false;
250
338
  }
339
+ return isBlockedHostnameNormalized(normalized);
340
+ }
341
+ function isBlockedHostnameNormalized(normalized) {
251
342
  if (BLOCKED_HOSTNAMES.has(normalized)) {
252
343
  return true;
253
344
  }
@@ -255,6 +346,13 @@ export function isBlockedHostname(hostname) {
255
346
  normalized.endsWith(".local") ||
256
347
  normalized.endsWith(".internal"));
257
348
  }
349
+ export function isBlockedHostnameOrIp(hostname) {
350
+ const normalized = normalizeHostname(hostname);
351
+ if (!normalized) {
352
+ return false;
353
+ }
354
+ return isBlockedHostnameNormalized(normalized) || isPrivateIpAddress(normalized);
355
+ }
258
356
  export function createPinnedLookup(params) {
259
357
  const normalizedHost = normalizeHostname(params.hostname);
260
358
  const fallback = params.fallback ?? dnsLookupCb;
@@ -306,13 +404,8 @@ export async function resolvePinnedHostnameWithPolicy(hostname, params = {}) {
306
404
  if (!matchesHostnameAllowlist(normalized, hostnameAllowlist)) {
307
405
  throw new SsrFBlockedError(`Blocked hostname (not in allowlist): ${hostname}`);
308
406
  }
309
- if (!allowPrivateNetwork && !isExplicitAllowed) {
310
- if (isBlockedHostname(normalized)) {
311
- throw new SsrFBlockedError(`Blocked hostname: ${hostname}`);
312
- }
313
- if (isPrivateIpAddress(normalized)) {
314
- throw new SsrFBlockedError("Blocked: private/internal IP address");
315
- }
407
+ if (!allowPrivateNetwork && !isExplicitAllowed && isBlockedHostnameOrIp(normalized)) {
408
+ throw new SsrFBlockedError("Blocked hostname or private/internal/special-use IP address");
316
409
  }
317
410
  const lookupFn = params.lookupFn ?? dnsLookup;
318
411
  const results = await lookupFn(normalized, { all: true });
@@ -322,7 +415,7 @@ export async function resolvePinnedHostnameWithPolicy(hostname, params = {}) {
322
415
  if (!allowPrivateNetwork && !isExplicitAllowed) {
323
416
  for (const entry of results) {
324
417
  if (isPrivateIpAddress(entry.address)) {
325
- throw new SsrFBlockedError("Blocked: resolves to private/internal IP address");
418
+ throw new SsrFBlockedError("Blocked: resolves to private/internal/special-use IP address");
326
419
  }
327
420
  }
328
421
  }
@@ -0,0 +1,88 @@
1
+ import { getSessionBindingService, } from "./session-binding-service.js";
2
+ function isActiveBinding(record) {
3
+ return record.status === "active";
4
+ }
5
+ function resolveBindingForRequester(requester, bindings) {
6
+ const matchingChannelAccount = bindings.filter((entry) => entry.conversation.channel === requester.channel &&
7
+ entry.conversation.accountId === requester.accountId);
8
+ if (matchingChannelAccount.length === 0) {
9
+ return null;
10
+ }
11
+ const exactConversation = matchingChannelAccount.find((entry) => entry.conversation.conversationId === requester.conversationId);
12
+ if (exactConversation) {
13
+ return exactConversation;
14
+ }
15
+ if (matchingChannelAccount.length === 1) {
16
+ return matchingChannelAccount[0] ?? null;
17
+ }
18
+ return null;
19
+ }
20
+ export function createBoundDeliveryRouter(service = getSessionBindingService()) {
21
+ return {
22
+ resolveDestination: (input) => {
23
+ const targetSessionKey = input.targetSessionKey.trim();
24
+ if (!targetSessionKey) {
25
+ return {
26
+ binding: null,
27
+ mode: "fallback",
28
+ reason: "missing-target-session",
29
+ };
30
+ }
31
+ const activeBindings = service.listBySession(targetSessionKey).filter(isActiveBinding);
32
+ if (activeBindings.length === 0) {
33
+ return {
34
+ binding: null,
35
+ mode: "fallback",
36
+ reason: "no-active-binding",
37
+ };
38
+ }
39
+ if (!input.requester) {
40
+ if (activeBindings.length === 1) {
41
+ return {
42
+ binding: activeBindings[0] ?? null,
43
+ mode: "bound",
44
+ reason: "single-active-binding",
45
+ };
46
+ }
47
+ return {
48
+ binding: null,
49
+ mode: "fallback",
50
+ reason: "ambiguous-without-requester",
51
+ };
52
+ }
53
+ const requester = {
54
+ channel: input.requester.channel.trim().toLowerCase(),
55
+ accountId: input.requester.accountId.trim(),
56
+ conversationId: input.requester.conversationId.trim(),
57
+ parentConversationId: input.requester.parentConversationId?.trim() || undefined,
58
+ };
59
+ if (!requester.channel || !requester.conversationId) {
60
+ return {
61
+ binding: null,
62
+ mode: "fallback",
63
+ reason: "invalid-requester",
64
+ };
65
+ }
66
+ const fromRequester = resolveBindingForRequester(requester, activeBindings);
67
+ if (fromRequester) {
68
+ return {
69
+ binding: fromRequester,
70
+ mode: "bound",
71
+ reason: "requester-match",
72
+ };
73
+ }
74
+ if (activeBindings.length === 1 && !input.failClosed) {
75
+ return {
76
+ binding: activeBindings[0] ?? null,
77
+ mode: "bound",
78
+ reason: "single-active-binding-fallback",
79
+ };
80
+ }
81
+ return {
82
+ binding: null,
83
+ mode: "fallback",
84
+ reason: "no-requester-match",
85
+ };
86
+ },
87
+ };
88
+ }
@@ -5,35 +5,41 @@ function isKnownChannel(value) {
5
5
  return getMessageChannels().includes(value);
6
6
  }
7
7
  function isAccountEnabled(account) {
8
- if (!account || typeof account !== "object")
8
+ if (!account || typeof account !== "object") {
9
9
  return true;
10
+ }
10
11
  const enabled = account.enabled;
11
12
  return enabled !== false;
12
13
  }
13
14
  async function isPluginConfigured(plugin, cfg) {
14
15
  const accountIds = plugin.config.listAccountIds(cfg);
15
- if (accountIds.length === 0)
16
+ if (accountIds.length === 0) {
16
17
  return false;
18
+ }
17
19
  for (const accountId of accountIds) {
18
20
  const account = plugin.config.resolveAccount(cfg, accountId);
19
21
  const enabled = plugin.config.isEnabled
20
22
  ? plugin.config.isEnabled(account, cfg)
21
23
  : isAccountEnabled(account);
22
- if (!enabled)
24
+ if (!enabled) {
23
25
  continue;
24
- if (!plugin.config.isConfigured)
26
+ }
27
+ if (!plugin.config.isConfigured) {
25
28
  return true;
29
+ }
26
30
  const configured = await plugin.config.isConfigured(account, cfg);
27
- if (configured)
31
+ if (configured) {
28
32
  return true;
33
+ }
29
34
  }
30
35
  return false;
31
36
  }
32
37
  export async function listConfiguredMessageChannels(cfg) {
33
38
  const channels = [];
34
39
  for (const plugin of listChannelPlugins()) {
35
- if (!isKnownChannel(plugin.id))
40
+ if (!isKnownChannel(plugin.id)) {
36
41
  continue;
42
+ }
37
43
  if (await isPluginConfigured(plugin, cfg)) {
38
44
  channels.push(plugin.id);
39
45
  }
@@ -7,7 +7,7 @@ export function buildOutboundResultEnvelope(params) {
7
7
  : params.payloads.length === 0
8
8
  ? []
9
9
  : isOutboundPayloadJson(params.payloads[0])
10
- ? params.payloads
10
+ ? [...params.payloads]
11
11
  : normalizeOutboundPayloadsForJson(params.payloads);
12
12
  if (params.flattenDelivery !== false && params.delivery && !params.meta && !hasPayloads) {
13
13
  return params.delivery;
@@ -2,11 +2,13 @@ import { getChannelPlugin } from "../../channels/plugins/index.js";
2
2
  import { getChatChannelMeta, normalizeChatChannelId } from "../../channels/registry.js";
3
3
  const resolveChannelLabel = (channel) => {
4
4
  const pluginLabel = getChannelPlugin(channel)?.meta.label;
5
- if (pluginLabel)
5
+ if (pluginLabel) {
6
6
  return pluginLabel;
7
+ }
7
8
  const normalized = normalizeChatChannelId(channel);
8
- if (normalized)
9
+ if (normalized) {
9
10
  return getChatChannelMeta(normalized).label;
11
+ }
10
12
  return channel;
11
13
  };
12
14
  export function formatOutboundDeliverySummary(channel, result) {
@@ -15,14 +17,18 @@ export function formatOutboundDeliverySummary(channel, result) {
15
17
  }
16
18
  const label = resolveChannelLabel(result.channel);
17
19
  const base = `✅ Sent via ${label}. Message ID: ${result.messageId}`;
18
- if ("chatId" in result)
20
+ if ("chatId" in result) {
19
21
  return `${base} (chat ${result.chatId})`;
20
- if ("channelId" in result)
22
+ }
23
+ if ("channelId" in result) {
21
24
  return `${base} (channel ${result.channelId})`;
22
- if ("roomId" in result)
25
+ }
26
+ if ("roomId" in result) {
23
27
  return `${base} (room ${result.roomId})`;
24
- if ("conversationId" in result)
28
+ }
29
+ if ("conversationId" in result) {
25
30
  return `${base} (conversation ${result.conversationId})`;
31
+ }
26
32
  return base;
27
33
  }
28
34
  export function buildOutboundDeliveryJson(params) {
@@ -4,14 +4,17 @@ function mergeMediaUrls(...lists) {
4
4
  const seen = new Set();
5
5
  const merged = [];
6
6
  for (const list of lists) {
7
- if (!list)
7
+ if (!list) {
8
8
  continue;
9
+ }
9
10
  for (const entry of list) {
10
11
  const trimmed = entry?.trim();
11
- if (!trimmed)
12
+ if (!trimmed) {
12
13
  continue;
13
- if (seen.has(trimmed))
14
+ }
15
+ if (seen.has(trimmed)) {
14
16
  continue;
17
+ }
15
18
  seen.add(trimmed);
16
19
  merged.push(trimmed);
17
20
  }
@@ -36,10 +39,12 @@ export function normalizeReplyPayloadsForDelivery(payloads) {
36
39
  replyToCurrent: payload.replyToCurrent || parsed.replyToCurrent,
37
40
  audioAsVoice: Boolean(payload.audioAsVoice || parsed.audioAsVoice),
38
41
  };
39
- if (parsed.isSilent && mergedMedia.length === 0)
42
+ if (parsed.isSilent && mergedMedia.length === 0) {
40
43
  return [];
41
- if (!isRenderablePayload(next))
44
+ }
45
+ if (!isRenderablePayload(next)) {
42
46
  return [];
47
+ }
43
48
  return [next];
44
49
  });
45
50
  }
@@ -70,9 +75,11 @@ export function normalizeOutboundPayloadsForJson(payloads) {
70
75
  }
71
76
  export function formatOutboundPayloadLog(payload) {
72
77
  const lines = [];
73
- if (payload.text)
78
+ if (payload.text) {
74
79
  lines.push(payload.text.trimEnd());
75
- for (const url of payload.mediaUrls)
80
+ }
81
+ for (const url of payload.mediaUrls) {
76
82
  lines.push(`MEDIA:${url}`);
83
+ }
77
84
  return lines.join("\n");
78
85
  }
@@ -0,0 +1,123 @@
1
+ import { normalizeAccountId } from "../../routing/session-key.js";
2
+ function normalizeConversationRef(ref) {
3
+ return {
4
+ channel: ref.channel.trim().toLowerCase(),
5
+ accountId: normalizeAccountId(ref.accountId),
6
+ conversationId: ref.conversationId.trim(),
7
+ parentConversationId: ref.parentConversationId?.trim() || undefined,
8
+ };
9
+ }
10
+ function toAdapterKey(params) {
11
+ return `${params.channel.trim().toLowerCase()}:${normalizeAccountId(params.accountId)}`;
12
+ }
13
+ const ADAPTERS_BY_CHANNEL_ACCOUNT = new Map();
14
+ export function registerSessionBindingAdapter(adapter) {
15
+ const key = toAdapterKey({
16
+ channel: adapter.channel,
17
+ accountId: adapter.accountId,
18
+ });
19
+ ADAPTERS_BY_CHANNEL_ACCOUNT.set(key, {
20
+ ...adapter,
21
+ channel: adapter.channel.trim().toLowerCase(),
22
+ accountId: normalizeAccountId(adapter.accountId),
23
+ });
24
+ }
25
+ export function unregisterSessionBindingAdapter(params) {
26
+ ADAPTERS_BY_CHANNEL_ACCOUNT.delete(toAdapterKey(params));
27
+ }
28
+ function resolveAdapterForConversation(ref) {
29
+ const normalized = normalizeConversationRef(ref);
30
+ const key = toAdapterKey({
31
+ channel: normalized.channel,
32
+ accountId: normalized.accountId,
33
+ });
34
+ return ADAPTERS_BY_CHANNEL_ACCOUNT.get(key) ?? null;
35
+ }
36
+ function dedupeBindings(records) {
37
+ const byId = new Map();
38
+ for (const record of records) {
39
+ if (!record?.bindingId) {
40
+ continue;
41
+ }
42
+ byId.set(record.bindingId, record);
43
+ }
44
+ return [...byId.values()];
45
+ }
46
+ function createDefaultSessionBindingService() {
47
+ return {
48
+ bind: async (input) => {
49
+ const normalizedConversation = normalizeConversationRef(input.conversation);
50
+ const adapter = resolveAdapterForConversation(normalizedConversation);
51
+ if (!adapter?.bind) {
52
+ throw new Error(`Session binding adapter unavailable for ${normalizedConversation.channel}:${normalizedConversation.accountId}`);
53
+ }
54
+ const bound = await adapter.bind({
55
+ ...input,
56
+ conversation: normalizedConversation,
57
+ });
58
+ if (!bound) {
59
+ throw new Error("Session binding adapter failed to bind target conversation");
60
+ }
61
+ return bound;
62
+ },
63
+ listBySession: (targetSessionKey) => {
64
+ const key = targetSessionKey.trim();
65
+ if (!key) {
66
+ return [];
67
+ }
68
+ const results = [];
69
+ for (const adapter of ADAPTERS_BY_CHANNEL_ACCOUNT.values()) {
70
+ const entries = adapter.listBySession(key);
71
+ if (entries.length > 0) {
72
+ results.push(...entries);
73
+ }
74
+ }
75
+ return dedupeBindings(results);
76
+ },
77
+ resolveByConversation: (ref) => {
78
+ const normalized = normalizeConversationRef(ref);
79
+ if (!normalized.channel || !normalized.conversationId) {
80
+ return null;
81
+ }
82
+ const adapter = resolveAdapterForConversation(normalized);
83
+ if (!adapter) {
84
+ return null;
85
+ }
86
+ return adapter.resolveByConversation(normalized);
87
+ },
88
+ touch: (bindingId, at) => {
89
+ const normalizedBindingId = bindingId.trim();
90
+ if (!normalizedBindingId) {
91
+ return;
92
+ }
93
+ for (const adapter of ADAPTERS_BY_CHANNEL_ACCOUNT.values()) {
94
+ adapter.touch?.(normalizedBindingId, at);
95
+ }
96
+ },
97
+ unbind: async (input) => {
98
+ const removed = [];
99
+ for (const adapter of ADAPTERS_BY_CHANNEL_ACCOUNT.values()) {
100
+ if (!adapter.unbind) {
101
+ continue;
102
+ }
103
+ const entries = await adapter.unbind(input);
104
+ if (entries.length > 0) {
105
+ removed.push(...entries);
106
+ }
107
+ }
108
+ return dedupeBindings(removed);
109
+ },
110
+ };
111
+ }
112
+ const DEFAULT_SESSION_BINDING_SERVICE = createDefaultSessionBindingService();
113
+ export function getSessionBindingService() {
114
+ return DEFAULT_SESSION_BINDING_SERVICE;
115
+ }
116
+ export const __testing = {
117
+ resetSessionBindingAdaptersForTests() {
118
+ ADAPTERS_BY_CHANNEL_ACCOUNT.clear();
119
+ },
120
+ getRegisteredAdapterKeys() {
121
+ return [...ADAPTERS_BY_CHANNEL_ACCOUNT.keys()];
122
+ },
123
+ };
@@ -0,0 +1,25 @@
1
+ import path from "node:path";
2
+ const NOT_FOUND_CODES = new Set(["ENOENT", "ENOTDIR"]);
3
+ const SYMLINK_OPEN_CODES = new Set(["ELOOP", "EINVAL", "ENOTSUP"]);
4
+ export function isNodeError(value) {
5
+ return Boolean(value && typeof value === "object" && "code" in value);
6
+ }
7
+ export function hasNodeErrorCode(value, code) {
8
+ return isNodeError(value) && value.code === code;
9
+ }
10
+ export function isNotFoundPathError(value) {
11
+ return isNodeError(value) && typeof value.code === "string" && NOT_FOUND_CODES.has(value.code);
12
+ }
13
+ export function isSymlinkOpenError(value) {
14
+ return isNodeError(value) && typeof value.code === "string" && SYMLINK_OPEN_CODES.has(value.code);
15
+ }
16
+ export function isPathInside(root, target) {
17
+ const resolvedRoot = path.resolve(root);
18
+ const resolvedTarget = path.resolve(target);
19
+ if (process.platform === "win32") {
20
+ const relative = path.win32.relative(resolvedRoot.toLowerCase(), resolvedTarget.toLowerCase());
21
+ return relative === "" || (!relative.startsWith("..") && !path.win32.isAbsolute(relative));
22
+ }
23
+ const relative = path.relative(resolvedRoot, resolvedTarget);
24
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
25
+ }
@@ -1,4 +1,4 @@
1
- import { fetchJson } from "./provider-usage.fetch.shared.js";
1
+ import { buildUsageHttpErrorSnapshot, fetchJson } from "./provider-usage.fetch.shared.js";
2
2
  import { clampPercent, PROVIDER_LABELS } from "./provider-usage.shared.js";
3
3
  export async function fetchCodexUsage(token, accountId, timeoutMs, fetchFn) {
4
4
  const headers = {
@@ -6,24 +6,16 @@ export async function fetchCodexUsage(token, accountId, timeoutMs, fetchFn) {
6
6
  "User-Agent": "CodexBar",
7
7
  Accept: "application/json",
8
8
  };
9
- if (accountId)
9
+ if (accountId) {
10
10
  headers["ChatGPT-Account-Id"] = accountId;
11
- const res = await fetchJson("https://chatgpt.com/backend-api/wham/usage", { method: "GET", headers }, timeoutMs, fetchFn);
12
- if (res.status === 401 || res.status === 403) {
13
- return {
14
- provider: "openai-codex",
15
- displayName: PROVIDER_LABELS["openai-codex"],
16
- windows: [],
17
- error: "Token expired",
18
- };
19
11
  }
12
+ const res = await fetchJson("https://chatgpt.com/backend-api/wham/usage", { method: "GET", headers }, timeoutMs, fetchFn);
20
13
  if (!res.ok) {
21
- return {
14
+ return buildUsageHttpErrorSnapshot({
22
15
  provider: "openai-codex",
23
- displayName: PROVIDER_LABELS["openai-codex"],
24
- windows: [],
25
- error: `HTTP ${res.status}`,
26
- };
16
+ status: res.status,
17
+ tokenExpiredStatuses: [401, 403],
18
+ });
27
19
  }
28
20
  const data = (await res.json());
29
21
  const windows = [];