@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
@@ -0,0 +1,68 @@
1
+ import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
2
+ import { normalizeStringEntries } from "../shared/string-normalization.js";
3
+ export function resolveEffectiveAllowFromLists(params) {
4
+ const configAllowFrom = normalizeStringEntries(Array.isArray(params.allowFrom) ? params.allowFrom : undefined);
5
+ const configGroupAllowFrom = normalizeStringEntries(Array.isArray(params.groupAllowFrom) ? params.groupAllowFrom : undefined);
6
+ const storeAllowFrom = params.dmPolicy === "allowlist"
7
+ ? []
8
+ : normalizeStringEntries(Array.isArray(params.storeAllowFrom) ? params.storeAllowFrom : undefined);
9
+ const effectiveAllowFrom = normalizeStringEntries([...configAllowFrom, ...storeAllowFrom]);
10
+ const groupBase = configGroupAllowFrom.length > 0 ? configGroupAllowFrom : configAllowFrom;
11
+ const effectiveGroupAllowFrom = normalizeStringEntries([...groupBase, ...storeAllowFrom]);
12
+ return { effectiveAllowFrom, effectiveGroupAllowFrom };
13
+ }
14
+ export function resolveDmGroupAccessDecision(params) {
15
+ const dmPolicy = params.dmPolicy ?? "pairing";
16
+ const groupPolicy = params.groupPolicy ?? "allowlist";
17
+ const effectiveAllowFrom = normalizeStringEntries(params.effectiveAllowFrom);
18
+ const effectiveGroupAllowFrom = normalizeStringEntries(params.effectiveGroupAllowFrom);
19
+ if (params.isGroup) {
20
+ if (groupPolicy === "disabled") {
21
+ return { decision: "block", reason: "groupPolicy=disabled" };
22
+ }
23
+ if (groupPolicy === "allowlist") {
24
+ if (effectiveGroupAllowFrom.length === 0) {
25
+ return { decision: "block", reason: "groupPolicy=allowlist (empty allowlist)" };
26
+ }
27
+ if (!params.isSenderAllowed(effectiveGroupAllowFrom)) {
28
+ return { decision: "block", reason: "groupPolicy=allowlist (not allowlisted)" };
29
+ }
30
+ }
31
+ return { decision: "allow", reason: `groupPolicy=${groupPolicy}` };
32
+ }
33
+ if (dmPolicy === "disabled") {
34
+ return { decision: "block", reason: "dmPolicy=disabled" };
35
+ }
36
+ if (dmPolicy === "open") {
37
+ return { decision: "allow", reason: "dmPolicy=open" };
38
+ }
39
+ if (params.isSenderAllowed(effectiveAllowFrom)) {
40
+ return { decision: "allow", reason: `dmPolicy=${dmPolicy} (allowlisted)` };
41
+ }
42
+ if (dmPolicy === "pairing") {
43
+ return { decision: "pairing", reason: "dmPolicy=pairing (not allowlisted)" };
44
+ }
45
+ return { decision: "block", reason: `dmPolicy=${dmPolicy} (not allowlisted)` };
46
+ }
47
+ export async function resolveDmAllowState(params) {
48
+ const configAllowFrom = normalizeStringEntries(Array.isArray(params.allowFrom) ? params.allowFrom : undefined);
49
+ const hasWildcard = configAllowFrom.includes("*");
50
+ const storeAllowFrom = await (params.readStore ?? readChannelAllowFromStore)(params.provider).catch(() => []);
51
+ const normalizeEntry = params.normalizeEntry ?? ((value) => value);
52
+ const normalizedCfg = configAllowFrom
53
+ .filter((value) => value !== "*")
54
+ .map((value) => normalizeEntry(value))
55
+ .map((value) => value.trim())
56
+ .filter(Boolean);
57
+ const normalizedStore = storeAllowFrom
58
+ .map((value) => normalizeEntry(value))
59
+ .map((value) => value.trim())
60
+ .filter(Boolean);
61
+ const allowCount = Array.from(new Set([...normalizedCfg, ...normalizedStore])).length;
62
+ return {
63
+ configAllowFrom,
64
+ hasWildcard,
65
+ allowCount,
66
+ isMultiUserDm: hasWildcard || allowCount > 1,
67
+ };
68
+ }
@@ -1,3 +1,4 @@
1
+ import { randomBytes } from "node:crypto";
1
2
  /**
2
3
  * Security utilities for handling untrusted external content.
3
4
  *
@@ -40,9 +41,20 @@ export function detectSuspiciousPatterns(content) {
40
41
  /**
41
42
  * Unique boundary markers for external content.
42
43
  * Using XML-style tags that are unlikely to appear in legitimate content.
44
+ * Each wrapper gets a unique random ID to prevent spoofing attacks where
45
+ * malicious content injects fake boundary markers.
43
46
  */
44
- const EXTERNAL_CONTENT_START = "<<<EXTERNAL_UNTRUSTED_CONTENT>>>";
45
- const EXTERNAL_CONTENT_END = "<<<END_EXTERNAL_UNTRUSTED_CONTENT>>>";
47
+ const EXTERNAL_CONTENT_START_NAME = "EXTERNAL_UNTRUSTED_CONTENT";
48
+ const EXTERNAL_CONTENT_END_NAME = "END_EXTERNAL_UNTRUSTED_CONTENT";
49
+ function createExternalContentMarkerId() {
50
+ return randomBytes(8).toString("hex");
51
+ }
52
+ function createExternalContentStartMarker(id) {
53
+ return `<<<${EXTERNAL_CONTENT_START_NAME} id="${id}">>>`;
54
+ }
55
+ function createExternalContentEndMarker(id) {
56
+ return `<<<${EXTERNAL_CONTENT_END_NAME} id="${id}">>>`;
57
+ }
46
58
  /**
47
59
  * Security warning prepended to external content.
48
60
  */
@@ -62,14 +74,28 @@ const EXTERNAL_SOURCE_LABELS = {
62
74
  email: "Email",
63
75
  webhook: "Webhook",
64
76
  api: "API",
77
+ browser: "Browser",
65
78
  channel_metadata: "Channel metadata",
66
79
  web_search: "Web Search",
67
80
  web_fetch: "Web Fetch",
68
81
  unknown: "External",
69
82
  };
70
83
  const FULLWIDTH_ASCII_OFFSET = 0xfee0;
71
- const FULLWIDTH_LEFT_ANGLE = 0xff1c;
72
- const FULLWIDTH_RIGHT_ANGLE = 0xff1e;
84
+ // Map of Unicode angle bracket homoglyphs to their ASCII equivalents.
85
+ const ANGLE_BRACKET_MAP = {
86
+ 0xff1c: "<", // fullwidth <
87
+ 0xff1e: ">", // fullwidth >
88
+ 0x2329: "<", // left-pointing angle bracket
89
+ 0x232a: ">", // right-pointing angle bracket
90
+ 0x3008: "<", // CJK left angle bracket
91
+ 0x3009: ">", // CJK right angle bracket
92
+ 0x2039: "<", // single left-pointing angle quotation mark
93
+ 0x203a: ">", // single right-pointing angle quotation mark
94
+ 0x27e8: "<", // mathematical left angle bracket
95
+ 0x27e9: ">", // mathematical right angle bracket
96
+ 0xfe64: "<", // small less-than sign
97
+ 0xfe65: ">", // small greater-than sign
98
+ };
73
99
  function foldMarkerChar(char) {
74
100
  const code = char.charCodeAt(0);
75
101
  if (code >= 0xff21 && code <= 0xff3a) {
@@ -78,16 +104,14 @@ function foldMarkerChar(char) {
78
104
  if (code >= 0xff41 && code <= 0xff5a) {
79
105
  return String.fromCharCode(code - FULLWIDTH_ASCII_OFFSET);
80
106
  }
81
- if (code === FULLWIDTH_LEFT_ANGLE) {
82
- return "<";
83
- }
84
- if (code === FULLWIDTH_RIGHT_ANGLE) {
85
- return ">";
107
+ const bracket = ANGLE_BRACKET_MAP[code];
108
+ if (bracket) {
109
+ return bracket;
86
110
  }
87
111
  return char;
88
112
  }
89
113
  function foldMarkerText(input) {
90
- return input.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A\uFF1C\uFF1E]/g, (char) => foldMarkerChar(char));
114
+ return input.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A\uFF1C\uFF1E\u2329\u232A\u3008\u3009\u2039\u203A\u27E8\u27E9\uFE64\uFE65]/g, (char) => foldMarkerChar(char));
91
115
  }
92
116
  function replaceMarkers(content) {
93
117
  const folded = foldMarkerText(content);
@@ -95,9 +119,16 @@ function replaceMarkers(content) {
95
119
  return content;
96
120
  }
97
121
  const replacements = [];
122
+ // Match markers with or without id attribute (handles both legacy and spoofed markers)
98
123
  const patterns = [
99
- { regex: /<<<EXTERNAL_UNTRUSTED_CONTENT>>>/gi, value: "[[MARKER_SANITIZED]]" },
100
- { regex: /<<<END_EXTERNAL_UNTRUSTED_CONTENT>>>/gi, value: "[[END_MARKER_SANITIZED]]" },
124
+ {
125
+ regex: /<<<EXTERNAL_UNTRUSTED_CONTENT(?:\s+id="[^"]{1,128}")?\s*>>>/gi,
126
+ value: "[[MARKER_SANITIZED]]",
127
+ },
128
+ {
129
+ regex: /<<<END_EXTERNAL_UNTRUSTED_CONTENT(?:\s+id="[^"]{1,128}")?\s*>>>/gi,
130
+ value: "[[END_MARKER_SANITIZED]]",
131
+ },
101
132
  ];
102
133
  for (const pattern of patterns) {
103
134
  pattern.regex.lastIndex = 0;
@@ -156,13 +187,14 @@ export function wrapExternalContent(content, options) {
156
187
  }
157
188
  const metadata = metadataLines.join("\n");
158
189
  const warningBlock = includeWarning ? `${EXTERNAL_CONTENT_WARNING}\n\n` : "";
190
+ const markerId = createExternalContentMarkerId();
159
191
  return [
160
192
  warningBlock,
161
- EXTERNAL_CONTENT_START,
193
+ createExternalContentStartMarker(markerId),
162
194
  metadata,
163
195
  "---",
164
196
  sanitized,
165
- EXTERNAL_CONTENT_END,
197
+ createExternalContentEndMarker(markerId),
166
198
  ].join("\n");
167
199
  }
168
200
  /**
@@ -1,13 +1,12 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import JSON5 from "json5";
3
+ import { resolveDefaultAgentId } from "../agents/agent-scope.js";
4
4
  import { createConfigIO } from "../config/config.js";
5
+ import { collectIncludePathsRecursive } from "../config/includes-scan.js";
5
6
  import { resolveConfigPath, resolveOAuthDir, resolveStateDir } from "../config/paths.js";
6
- import { resolveDefaultAgentId } from "../agents/agent-scope.js";
7
- import { INCLUDE_KEY, MAX_INCLUDE_DEPTH } from "../config/includes.js";
8
- import { normalizeAgentId } from "../routing/session-key.js";
9
7
  import { readChannelAllowFromStore } from "../pairing/pairing-store.js";
10
8
  import { runExec } from "../process/exec.js";
9
+ import { normalizeAgentId } from "../routing/session-key.js";
11
10
  import { createIcaclsResetCommand, formatIcaclsResetCommand } from "./windows-acl.js";
12
11
  async function safeChmod(params) {
13
12
  try {
@@ -144,11 +143,13 @@ async function safeAclReset(params) {
144
143
  }
145
144
  }
146
145
  function setGroupPolicyAllowlist(params) {
147
- if (!params.cfg.channels)
146
+ if (!params.cfg.channels) {
148
147
  return;
148
+ }
149
149
  const section = params.cfg.channels[params.channel];
150
- if (!section || typeof section !== "object")
150
+ if (!section || typeof section !== "object") {
151
151
  return;
152
+ }
152
153
  const topPolicy = section.groupPolicy;
153
154
  if (topPolicy === "open") {
154
155
  section.groupPolicy = "allowlist";
@@ -156,13 +157,16 @@ function setGroupPolicyAllowlist(params) {
156
157
  params.policyFlips.add(`channels.${params.channel}.`);
157
158
  }
158
159
  const accounts = section.accounts;
159
- if (!accounts || typeof accounts !== "object")
160
+ if (!accounts || typeof accounts !== "object") {
160
161
  return;
162
+ }
161
163
  for (const [accountId, accountValue] of Object.entries(accounts)) {
162
- if (!accountId)
164
+ if (!accountId) {
163
165
  continue;
164
- if (!accountValue || typeof accountValue !== "object")
166
+ }
167
+ if (!accountValue || typeof accountValue !== "object") {
165
168
  continue;
169
+ }
166
170
  const account = accountValue;
167
171
  if (account.groupPolicy === "open") {
168
172
  account.groupPolicy = "allowlist";
@@ -173,29 +177,36 @@ function setGroupPolicyAllowlist(params) {
173
177
  }
174
178
  function setWhatsAppGroupAllowFromFromStore(params) {
175
179
  const section = params.cfg.channels?.whatsapp;
176
- if (!section || typeof section !== "object")
180
+ if (!section || typeof section !== "object") {
177
181
  return;
178
- if (params.storeAllowFrom.length === 0)
182
+ }
183
+ if (params.storeAllowFrom.length === 0) {
179
184
  return;
185
+ }
180
186
  const maybeApply = (prefix, obj) => {
181
- if (!params.policyFlips.has(prefix))
187
+ if (!params.policyFlips.has(prefix)) {
182
188
  return;
189
+ }
183
190
  const allowFrom = Array.isArray(obj.allowFrom) ? obj.allowFrom : [];
184
191
  const groupAllowFrom = Array.isArray(obj.groupAllowFrom) ? obj.groupAllowFrom : [];
185
- if (allowFrom.length > 0)
192
+ if (allowFrom.length > 0) {
186
193
  return;
187
- if (groupAllowFrom.length > 0)
194
+ }
195
+ if (groupAllowFrom.length > 0) {
188
196
  return;
197
+ }
189
198
  obj.groupAllowFrom = params.storeAllowFrom;
190
199
  params.changes.push(`${prefix}groupAllowFrom=pairing-store`);
191
200
  };
192
201
  maybeApply("channels.whatsapp.", section);
193
202
  const accounts = section.accounts;
194
- if (!accounts || typeof accounts !== "object")
203
+ if (!accounts || typeof accounts !== "object") {
195
204
  return;
205
+ }
196
206
  for (const [accountId, accountValue] of Object.entries(accounts)) {
197
- if (!accountValue || typeof accountValue !== "object")
207
+ if (!accountValue || typeof accountValue !== "object") {
198
208
  continue;
209
+ }
199
210
  const account = accountValue;
200
211
  maybeApply(`channels.whatsapp.accounts.${accountId}.`, account);
201
212
  }
@@ -221,80 +232,17 @@ function applyConfigFixes(params) {
221
232
  }
222
233
  return { cfg: next, changes, policyFlips };
223
234
  }
224
- function listDirectIncludes(parsed) {
225
- const out = [];
226
- const visit = (value) => {
227
- if (!value)
228
- return;
229
- if (Array.isArray(value)) {
230
- for (const item of value)
231
- visit(item);
232
- return;
233
- }
234
- if (typeof value !== "object")
235
- return;
236
- const rec = value;
237
- const includeVal = rec[INCLUDE_KEY];
238
- if (typeof includeVal === "string")
239
- out.push(includeVal);
240
- else if (Array.isArray(includeVal)) {
241
- for (const item of includeVal) {
242
- if (typeof item === "string")
243
- out.push(item);
244
- }
245
- }
246
- for (const v of Object.values(rec))
247
- visit(v);
248
- };
249
- visit(parsed);
250
- return out;
251
- }
252
- function resolveIncludePath(baseConfigPath, includePath) {
253
- return path.normalize(path.isAbsolute(includePath)
254
- ? includePath
255
- : path.resolve(path.dirname(baseConfigPath), includePath));
256
- }
257
- async function collectIncludePathsRecursive(params) {
258
- const visited = new Set();
259
- const result = [];
260
- const walk = async (basePath, parsed, depth) => {
261
- if (depth > MAX_INCLUDE_DEPTH)
262
- return;
263
- for (const raw of listDirectIncludes(parsed)) {
264
- const resolved = resolveIncludePath(basePath, raw);
265
- if (visited.has(resolved))
266
- continue;
267
- visited.add(resolved);
268
- result.push(resolved);
269
- const rawText = await fs.readFile(resolved, "utf-8").catch(() => null);
270
- if (!rawText)
271
- continue;
272
- const nestedParsed = (() => {
273
- try {
274
- return JSON5.parse(rawText);
275
- }
276
- catch {
277
- return null;
278
- }
279
- })();
280
- if (nestedParsed) {
281
- // eslint-disable-next-line no-await-in-loop
282
- await walk(resolved, nestedParsed, depth + 1);
283
- }
284
- }
285
- };
286
- await walk(params.configPath, params.parsed, 0);
287
- return result;
288
- }
289
235
  async function chmodCredentialsAndAgentState(params) {
290
236
  const credsDir = resolveOAuthDir(params.env, params.stateDir);
291
237
  params.actions.push(await safeChmod({ path: credsDir, mode: 0o700, require: "dir" }));
292
238
  const credsEntries = await fs.readdir(credsDir, { withFileTypes: true }).catch(() => []);
293
239
  for (const entry of credsEntries) {
294
- if (!entry.isFile())
240
+ if (!entry.isFile()) {
295
241
  continue;
296
- if (!entry.name.endsWith(".json"))
242
+ }
243
+ if (!entry.name.endsWith(".json")) {
297
244
  continue;
245
+ }
298
246
  const p = path.join(credsDir, entry.name);
299
247
  // eslint-disable-next-line no-await-in-loop
300
248
  params.actions.push(await safeChmod({ path: p, mode: 0o600, require: "file" }));
@@ -303,11 +251,13 @@ async function chmodCredentialsAndAgentState(params) {
303
251
  ids.add(resolveDefaultAgentId(params.cfg));
304
252
  const list = Array.isArray(params.cfg.agents?.list) ? params.cfg.agents?.list : [];
305
253
  for (const agent of list ?? []) {
306
- if (!agent || typeof agent !== "object")
254
+ if (!agent || typeof agent !== "object") {
307
255
  continue;
256
+ }
308
257
  const id = typeof agent.id === "string" ? agent.id.trim() : "";
309
- if (id)
258
+ if (id) {
310
259
  ids.add(id);
260
+ }
311
261
  }
312
262
  for (const agentId of ids) {
313
263
  const normalizedAgentId = normalizeAgentId(agentId);
@@ -326,6 +276,20 @@ async function chmodCredentialsAndAgentState(params) {
326
276
  const storePath = path.join(sessionsDir, "sessions.json");
327
277
  // eslint-disable-next-line no-await-in-loop
328
278
  params.actions.push(await params.applyPerms({ path: storePath, mode: 0o600, require: "file" }));
279
+ // Fix permissions on session transcript files (*.jsonl)
280
+ // eslint-disable-next-line no-await-in-loop
281
+ const sessionEntries = await fs.readdir(sessionsDir, { withFileTypes: true }).catch(() => []);
282
+ for (const entry of sessionEntries) {
283
+ if (!entry.isFile()) {
284
+ continue;
285
+ }
286
+ if (!entry.name.endsWith(".jsonl")) {
287
+ continue;
288
+ }
289
+ const p = path.join(sessionsDir, entry.name);
290
+ // eslint-disable-next-line no-await-in-loop
291
+ params.actions.push(await params.applyPerms({ path: p, mode: 0o600, require: "file" }));
292
+ }
329
293
  }
330
294
  }
331
295
  export async function fixSecurityFootguns(opts) {
@@ -1,3 +1,4 @@
1
+ import fs from "node:fs";
1
2
  import path from "node:path";
2
3
  export function isPathInside(basePath, candidatePath) {
3
4
  const base = path.resolve(basePath);
@@ -5,6 +6,25 @@ export function isPathInside(basePath, candidatePath) {
5
6
  const rel = path.relative(base, candidate);
6
7
  return rel === "" || (!rel.startsWith(`..${path.sep}`) && rel !== ".." && !path.isAbsolute(rel));
7
8
  }
9
+ function safeRealpathSync(filePath) {
10
+ try {
11
+ return fs.realpathSync(filePath);
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ export function isPathInsideWithRealpath(basePath, candidatePath, opts) {
18
+ if (!isPathInside(basePath, candidatePath)) {
19
+ return false;
20
+ }
21
+ const baseReal = safeRealpathSync(basePath);
22
+ const candidateReal = safeRealpathSync(candidatePath);
23
+ if (!baseReal || !candidateReal) {
24
+ return opts?.requireRealpath !== true;
25
+ }
26
+ return isPathInside(baseReal, candidateReal);
27
+ }
8
28
  export function extensionUsesSkippedScannerPath(entry) {
9
29
  const segments = entry.split(/[\\/]+/).filter(Boolean);
10
30
  return segments.some((segment) => segment === "node_modules" ||
@@ -1,12 +1,8 @@
1
- import { timingSafeEqual } from "node:crypto";
1
+ import { createHash, timingSafeEqual } from "node:crypto";
2
2
  export function safeEqualSecret(provided, expected) {
3
3
  if (typeof provided !== "string" || typeof expected !== "string") {
4
4
  return false;
5
5
  }
6
- const providedBuffer = Buffer.from(provided);
7
- const expectedBuffer = Buffer.from(expected);
8
- if (providedBuffer.length !== expectedBuffer.length) {
9
- return false;
10
- }
11
- return timingSafeEqual(providedBuffer, expectedBuffer);
6
+ const hash = (s) => createHash("sha256").update(s).digest();
7
+ return timingSafeEqual(hash(provided), hash(expected));
12
8
  }
@@ -19,8 +19,9 @@ const TRUSTED_SUFFIXES = ["\\administrators", "\\system"];
19
19
  const normalize = (value) => value.trim().toLowerCase();
20
20
  export function resolveWindowsUserPrincipal(env) {
21
21
  const username = env?.USERNAME?.trim() || os.userInfo().username?.trim();
22
- if (!username)
22
+ if (!username) {
23
23
  return null;
24
+ }
24
25
  const domain = env?.USERDOMAIN?.trim();
25
26
  return domain ? `${domain}\\${username}` : username;
26
27
  }
@@ -31,18 +32,21 @@ function buildTrustedPrincipals(env) {
31
32
  trusted.add(normalize(principal));
32
33
  const parts = principal.split("\\");
33
34
  const userOnly = parts.at(-1);
34
- if (userOnly)
35
+ if (userOnly) {
35
36
  trusted.add(normalize(userOnly));
37
+ }
36
38
  }
37
39
  return trusted;
38
40
  }
39
41
  function classifyPrincipal(principal, env) {
40
42
  const normalized = normalize(principal);
41
43
  const trusted = buildTrustedPrincipals(env);
42
- if (trusted.has(normalized) || TRUSTED_SUFFIXES.some((s) => normalized.endsWith(s)))
44
+ if (trusted.has(normalized) || TRUSTED_SUFFIXES.some((s) => normalized.endsWith(s))) {
43
45
  return "trusted";
44
- if (WORLD_PRINCIPALS.has(normalized) || WORLD_SUFFIXES.some((s) => normalized.endsWith(s)))
46
+ }
47
+ if (WORLD_PRINCIPALS.has(normalized) || WORLD_SUFFIXES.some((s) => normalized.endsWith(s))) {
45
48
  return "world";
49
+ }
46
50
  return "group";
47
51
  }
48
52
  function rightsFromTokens(tokens) {
@@ -59,8 +63,9 @@ export function parseIcaclsOutput(output, targetPath) {
59
63
  const quotedLower = quotedTarget.toLowerCase();
60
64
  for (const rawLine of output.split(/\r?\n/)) {
61
65
  const line = rawLine.trimEnd();
62
- if (!line.trim())
66
+ if (!line.trim()) {
63
67
  continue;
68
+ }
64
69
  const trimmed = line.trim();
65
70
  const lower = trimmed.toLowerCase();
66
71
  if (lower.startsWith("successfully processed") ||
@@ -76,22 +81,26 @@ export function parseIcaclsOutput(output, targetPath) {
76
81
  else if (lower.startsWith(quotedLower)) {
77
82
  entry = trimmed.slice(quotedTarget.length).trim();
78
83
  }
79
- if (!entry)
84
+ if (!entry) {
80
85
  continue;
86
+ }
81
87
  const idx = entry.indexOf(":");
82
- if (idx === -1)
88
+ if (idx === -1) {
83
89
  continue;
90
+ }
84
91
  const principal = entry.slice(0, idx).trim();
85
92
  const rawRights = entry.slice(idx + 1).trim();
86
93
  const tokens = rawRights
87
94
  .match(/\(([^)]+)\)/g)
88
95
  ?.map((token) => token.slice(1, -1).trim())
89
96
  .filter(Boolean) ?? [];
90
- if (tokens.some((token) => token.toUpperCase() === "DENY"))
97
+ if (tokens.some((token) => token.toUpperCase() === "DENY")) {
91
98
  continue;
99
+ }
92
100
  const rights = tokens.filter((token) => !INHERIT_FLAGS.has(token.toUpperCase()));
93
- if (rights.length === 0)
101
+ if (rights.length === 0) {
94
102
  continue;
103
+ }
95
104
  const { canRead, canWrite } = rightsFromTokens(rights);
96
105
  entries.push({ principal, rights, rawRights, canRead, canWrite });
97
106
  }
@@ -103,12 +112,15 @@ export function summarizeWindowsAcl(entries, env) {
103
112
  const untrustedGroup = [];
104
113
  for (const entry of entries) {
105
114
  const classification = classifyPrincipal(entry.principal, env);
106
- if (classification === "trusted")
115
+ if (classification === "trusted") {
107
116
  trusted.push(entry);
108
- else if (classification === "world")
117
+ }
118
+ else if (classification === "world") {
109
119
  untrustedWorld.push(entry);
110
- else
120
+ }
121
+ else {
111
122
  untrustedGroup.push(entry);
123
+ }
112
124
  }
113
125
  return { trusted, untrustedWorld, untrustedGroup };
114
126
  }
@@ -133,11 +145,13 @@ export async function inspectWindowsAcl(targetPath, opts) {
133
145
  }
134
146
  }
135
147
  export function formatWindowsAclSummary(summary) {
136
- if (!summary.ok)
148
+ if (!summary.ok) {
137
149
  return "unknown";
150
+ }
138
151
  const untrusted = [...summary.untrustedWorld, ...summary.untrustedGroup];
139
- if (untrusted.length === 0)
152
+ if (untrusted.length === 0) {
140
153
  return "trusted-only";
154
+ }
141
155
  return untrusted.map((entry) => `${entry.principal}:${entry.rawRights}`).join(", ");
142
156
  }
143
157
  export function formatIcaclsResetCommand(targetPath, opts) {
@@ -147,8 +161,9 @@ export function formatIcaclsResetCommand(targetPath, opts) {
147
161
  }
148
162
  export function createIcaclsResetCommand(targetPath, opts) {
149
163
  const user = resolveWindowsUserPrincipal(opts.env);
150
- if (!user)
164
+ if (!user) {
151
165
  return null;
166
+ }
152
167
  const grant = opts.isDir ? "(OI)(CI)F" : "F";
153
168
  const args = [
154
169
  targetPath,
@@ -23,3 +23,9 @@ export function evaluateEntryMetadataRequirements(params) {
23
23
  configChecks,
24
24
  };
25
25
  }
26
+ export function evaluateEntryMetadataRequirementsForCurrentPlatform(params) {
27
+ return evaluateEntryMetadataRequirements({
28
+ ...params,
29
+ localPlatform: process.platform,
30
+ });
31
+ }
@@ -24,7 +24,7 @@ export function parseFrontmatterBool(value, fallback) {
24
24
  const parsed = parseBooleanValue(value);
25
25
  return parsed === undefined ? fallback : parsed;
26
26
  }
27
- export function resolvePoolbotManifestBlock(params) {
27
+ export function resolvePoolBotManifestBlock(params) {
28
28
  const raw = getFrontmatterString(params.frontmatter, params.key ?? "metadata");
29
29
  if (!raw) {
30
30
  return undefined;
@@ -47,7 +47,7 @@ export function resolvePoolbotManifestBlock(params) {
47
47
  return undefined;
48
48
  }
49
49
  }
50
- export function resolvePoolbotManifestRequires(metadataObj) {
50
+ export function resolvePoolBotManifestRequires(metadataObj) {
51
51
  const requiresRaw = typeof metadataObj.requires === "object" && metadataObj.requires !== null
52
52
  ? metadataObj.requires
53
53
  : undefined;
@@ -61,16 +61,16 @@ export function resolvePoolbotManifestRequires(metadataObj) {
61
61
  config: normalizeStringList(requiresRaw.config),
62
62
  };
63
63
  }
64
- export function resolvePoolbotManifestInstall(metadataObj, parseInstallSpec) {
64
+ export function resolvePoolBotManifestInstall(metadataObj, parseInstallSpec) {
65
65
  const installRaw = Array.isArray(metadataObj.install) ? metadataObj.install : [];
66
66
  return installRaw
67
67
  .map((entry) => parseInstallSpec(entry))
68
68
  .filter((entry) => Boolean(entry));
69
69
  }
70
- export function resolvePoolbotManifestOs(metadataObj) {
70
+ export function resolvePoolBotManifestOs(metadataObj) {
71
71
  return normalizeStringList(metadataObj.os);
72
72
  }
73
- export function parsePoolbotManifestInstallBase(input, allowedKinds) {
73
+ export function parsePoolBotManifestInstallBase(input, allowedKinds) {
74
74
  if (!input || typeof input !== "object") {
75
75
  return undefined;
76
76
  }
@@ -0,0 +1,13 @@
1
+ function asRecord(value) {
2
+ return typeof value === "object" && value !== null ? value : {};
3
+ }
4
+ export function parsePairingList(value) {
5
+ const obj = asRecord(value);
6
+ const pending = Array.isArray(obj.pending) ? obj.pending : [];
7
+ const paired = Array.isArray(obj.paired) ? obj.paired : [];
8
+ return { pending, paired };
9
+ }
10
+ export function parseNodeList(value) {
11
+ const obj = asRecord(value);
12
+ return Array.isArray(obj.nodes) ? obj.nodes : [];
13
+ }
@@ -39,14 +39,21 @@ export function resolveNodeIdFromCandidates(nodes, query) {
39
39
  if (!q) {
40
40
  throw new Error("node required");
41
41
  }
42
- const matches = resolveNodeMatches(nodes, q);
43
- if (matches.length === 1) {
44
- return matches[0]?.nodeId ?? "";
42
+ const rawMatches = resolveNodeMatches(nodes, q);
43
+ if (rawMatches.length === 1) {
44
+ return rawMatches[0]?.nodeId ?? "";
45
45
  }
46
- if (matches.length === 0) {
46
+ if (rawMatches.length === 0) {
47
47
  const known = listKnownNodes(nodes);
48
48
  throw new Error(`unknown node: ${q}${known ? ` (known: ${known})` : ""}`);
49
49
  }
50
+ // Re-pair/reinstall flows can leave multiple nodes with the same display name.
51
+ // Prefer a unique connected match when available.
52
+ const connectedMatches = rawMatches.filter((match) => match.connected === true);
53
+ const matches = connectedMatches.length > 0 ? connectedMatches : rawMatches;
54
+ if (matches.length === 1) {
55
+ return matches[0]?.nodeId ?? "";
56
+ }
50
57
  throw new Error(`ambiguous node: ${q} (matches: ${matches
51
58
  .map((n) => n.displayName || n.remoteIp || n.nodeId)
52
59
  .join(", ")})`);