@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
@@ -31,8 +31,8 @@ function compileSafeBinProfile(fixture) {
31
31
  return {
32
32
  minPositional: fixture.minPositional,
33
33
  maxPositional: fixture.maxPositional,
34
- valueFlags: toFlagSet(fixture.valueFlags),
35
- blockedFlags: toFlagSet(fixture.blockedFlags),
34
+ allowedValueFlags: toFlagSet(fixture.allowedValueFlags),
35
+ deniedFlags: toFlagSet(fixture.deniedFlags),
36
36
  };
37
37
  }
38
38
  function compileSafeBinProfiles(fixtures) {
@@ -42,19 +42,8 @@ export const SAFE_BIN_GENERIC_PROFILE_FIXTURE = {};
42
42
  export const SAFE_BIN_PROFILE_FIXTURES = {
43
43
  jq: {
44
44
  maxPositional: 1,
45
- valueFlags: [
46
- "--arg",
47
- "--argjson",
48
- "--argstr",
49
- "--argfile",
50
- "--rawfile",
51
- "--slurpfile",
52
- "--from-file",
53
- "--library-path",
54
- "-L",
55
- "-f",
56
- ],
57
- blockedFlags: [
45
+ allowedValueFlags: ["--arg", "--argjson", "--argstr"],
46
+ deniedFlags: [
58
47
  "--argfile",
59
48
  "--rawfile",
60
49
  "--slurpfile",
@@ -65,31 +54,29 @@ export const SAFE_BIN_PROFILE_FIXTURES = {
65
54
  ],
66
55
  },
67
56
  grep: {
68
- maxPositional: 1,
69
- valueFlags: [
57
+ // Keep grep stdin-only: pattern must come from -e/--regexp.
58
+ // Allowing one positional is ambiguous because -e consumes the pattern and
59
+ // frees the positional slot for a filename.
60
+ maxPositional: 0,
61
+ allowedValueFlags: [
70
62
  "--regexp",
71
- "--file",
72
63
  "--max-count",
73
64
  "--after-context",
74
65
  "--before-context",
75
66
  "--context",
76
67
  "--devices",
77
- "--directories",
78
68
  "--binary-files",
79
69
  "--exclude",
80
- "--exclude-from",
81
70
  "--include",
82
71
  "--label",
83
72
  "-e",
84
- "-f",
85
73
  "-m",
86
74
  "-A",
87
75
  "-B",
88
76
  "-C",
89
77
  "-D",
90
- "-d",
91
78
  ],
92
- blockedFlags: [
79
+ deniedFlags: [
93
80
  "--file",
94
81
  "--exclude-from",
95
82
  "--dereference-recursive",
@@ -103,7 +90,7 @@ export const SAFE_BIN_PROFILE_FIXTURES = {
103
90
  },
104
91
  cut: {
105
92
  maxPositional: 0,
106
- valueFlags: [
93
+ allowedValueFlags: [
107
94
  "--bytes",
108
95
  "--characters",
109
96
  "--fields",
@@ -117,36 +104,41 @@ export const SAFE_BIN_PROFILE_FIXTURES = {
117
104
  },
118
105
  sort: {
119
106
  maxPositional: 0,
120
- valueFlags: [
107
+ allowedValueFlags: [
121
108
  "--key",
122
109
  "--field-separator",
123
110
  "--buffer-size",
124
111
  "--temporary-directory",
125
- "--compress-program",
126
112
  "--parallel",
127
113
  "--batch-size",
128
114
  "--random-source",
129
- "--files0-from",
130
- "--output",
131
115
  "-k",
132
116
  "-t",
133
117
  "-S",
134
118
  "-T",
135
- "-o",
136
119
  ],
137
- blockedFlags: ["--files0-from", "--output", "-o"],
120
+ // --compress-program can invoke an external executable and breaks stdin-only guarantees.
121
+ deniedFlags: ["--compress-program", "--files0-from", "--output", "-o"],
138
122
  },
139
123
  uniq: {
140
124
  maxPositional: 0,
141
- valueFlags: ["--skip-fields", "--skip-chars", "--check-chars", "--group", "-f", "-s", "-w"],
125
+ allowedValueFlags: [
126
+ "--skip-fields",
127
+ "--skip-chars",
128
+ "--check-chars",
129
+ "--group",
130
+ "-f",
131
+ "-s",
132
+ "-w",
133
+ ],
142
134
  },
143
135
  head: {
144
136
  maxPositional: 0,
145
- valueFlags: ["--lines", "--bytes", "-n", "-c"],
137
+ allowedValueFlags: ["--lines", "--bytes", "-n", "-c"],
146
138
  },
147
139
  tail: {
148
140
  maxPositional: 0,
149
- valueFlags: [
141
+ allowedValueFlags: [
150
142
  "--lines",
151
143
  "--bytes",
152
144
  "--sleep-interval",
@@ -162,12 +154,28 @@ export const SAFE_BIN_PROFILE_FIXTURES = {
162
154
  },
163
155
  wc: {
164
156
  maxPositional: 0,
165
- valueFlags: ["--files0-from"],
166
- blockedFlags: ["--files0-from"],
157
+ deniedFlags: ["--files0-from"],
167
158
  },
168
159
  };
169
160
  export const SAFE_BIN_GENERIC_PROFILE = compileSafeBinProfile(SAFE_BIN_GENERIC_PROFILE_FIXTURE);
170
161
  export const SAFE_BIN_PROFILES = compileSafeBinProfiles(SAFE_BIN_PROFILE_FIXTURES);
162
+ export function resolveSafeBinDeniedFlags(fixtures = SAFE_BIN_PROFILE_FIXTURES) {
163
+ const out = {};
164
+ for (const [name, fixture] of Object.entries(fixtures)) {
165
+ const denied = Array.from(new Set(fixture.deniedFlags ?? [])).toSorted();
166
+ if (denied.length > 0) {
167
+ out[name] = denied;
168
+ }
169
+ }
170
+ return out;
171
+ }
172
+ export function renderSafeBinDeniedFlagsDocBullets(fixtures = SAFE_BIN_PROFILE_FIXTURES) {
173
+ const deniedByBin = resolveSafeBinDeniedFlags(fixtures);
174
+ const bins = Object.keys(deniedByBin).toSorted();
175
+ return bins
176
+ .map((bin) => `- \`${bin}\`: ${deniedByBin[bin].map((flag) => `\`${flag}\``).join(", ")}`)
177
+ .join("\n");
178
+ }
171
179
  function isSafeLiteralToken(value) {
172
180
  if (!value || value === "-") {
173
181
  return true;
@@ -177,25 +185,25 @@ function isSafeLiteralToken(value) {
177
185
  function isInvalidValueToken(value) {
178
186
  return !value || !isSafeLiteralToken(value);
179
187
  }
180
- function consumeLongOptionToken(args, index, flag, inlineValue, valueFlags, blockedFlags) {
181
- if (blockedFlags.has(flag)) {
188
+ function consumeLongOptionToken(args, index, flag, inlineValue, allowedValueFlags, deniedFlags) {
189
+ if (deniedFlags.has(flag)) {
182
190
  return -1;
183
191
  }
184
192
  if (inlineValue !== undefined) {
185
193
  return isSafeLiteralToken(inlineValue) ? index + 1 : -1;
186
194
  }
187
- if (!valueFlags.has(flag)) {
195
+ if (!allowedValueFlags.has(flag)) {
188
196
  return index + 1;
189
197
  }
190
198
  return isInvalidValueToken(args[index + 1]) ? -1 : index + 2;
191
199
  }
192
- function consumeShortOptionClusterToken(args, index, raw, cluster, flags, valueFlags, blockedFlags) {
200
+ function consumeShortOptionClusterToken(args, index, raw, cluster, flags, allowedValueFlags, deniedFlags) {
193
201
  for (let j = 0; j < flags.length; j += 1) {
194
202
  const flag = flags[j];
195
- if (blockedFlags.has(flag)) {
203
+ if (deniedFlags.has(flag)) {
196
204
  return -1;
197
205
  }
198
- if (!valueFlags.has(flag)) {
206
+ if (!allowedValueFlags.has(flag)) {
199
207
  continue;
200
208
  }
201
209
  const inlineValue = cluster.slice(j + 1);
@@ -221,8 +229,8 @@ function validatePositionalCount(positional, profile) {
221
229
  return typeof profile.maxPositional !== "number" || positional.length <= profile.maxPositional;
222
230
  }
223
231
  export function validateSafeBinArgv(args, profile) {
224
- const valueFlags = profile.valueFlags ?? NO_FLAGS;
225
- const blockedFlags = profile.blockedFlags ?? NO_FLAGS;
232
+ const allowedValueFlags = profile.allowedValueFlags ?? NO_FLAGS;
233
+ const deniedFlags = profile.deniedFlags ?? NO_FLAGS;
226
234
  const positional = [];
227
235
  let i = 0;
228
236
  while (i < args.length) {
@@ -252,14 +260,14 @@ export function validateSafeBinArgv(args, profile) {
252
260
  continue;
253
261
  }
254
262
  if (token.style === "long") {
255
- const nextIndex = consumeLongOptionToken(args, i, token.flag, token.inlineValue, valueFlags, blockedFlags);
263
+ const nextIndex = consumeLongOptionToken(args, i, token.flag, token.inlineValue, allowedValueFlags, deniedFlags);
256
264
  if (nextIndex < 0) {
257
265
  return false;
258
266
  }
259
267
  i = nextIndex;
260
268
  continue;
261
269
  }
262
- const nextIndex = consumeShortOptionClusterToken(args, i, token.raw, token.cluster, token.flags, valueFlags, blockedFlags);
270
+ const nextIndex = consumeShortOptionClusterToken(args, i, token.raw, token.cluster, token.flags, allowedValueFlags, deniedFlags);
263
271
  if (nextIndex < 0) {
264
272
  return false;
265
273
  }
@@ -1,76 +1,108 @@
1
1
  import { constants as fsConstants } from "node:fs";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
+ import { isNotFoundPathError, isPathInside, isSymlinkOpenError } from "./path-guards.js";
4
5
  export class SafeOpenError extends Error {
5
6
  code;
6
- constructor(code, message) {
7
- super(message);
7
+ constructor(code, message, options) {
8
+ super(message, options);
8
9
  this.code = code;
9
10
  this.name = "SafeOpenError";
10
11
  }
11
12
  }
12
- const NOT_FOUND_CODES = new Set(["ENOENT", "ENOTDIR"]);
13
+ const SUPPORTS_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in fsConstants;
14
+ const OPEN_READ_FLAGS = fsConstants.O_RDONLY | (SUPPORTS_NOFOLLOW ? fsConstants.O_NOFOLLOW : 0);
13
15
  const ensureTrailingSep = (value) => (value.endsWith(path.sep) ? value : value + path.sep);
14
- const isNodeError = (err) => Boolean(err && typeof err === "object" && "code" in err);
15
- const isNotFoundError = (err) => isNodeError(err) && typeof err.code === "string" && NOT_FOUND_CODES.has(err.code);
16
- const isSymlinkOpenError = (err) => isNodeError(err) && (err.code === "ELOOP" || err.code === "EINVAL" || err.code === "ENOTSUP");
17
- export async function openFileWithinRoot(params) {
18
- let rootReal;
19
- try {
20
- rootReal = await fs.realpath(params.rootDir);
21
- }
22
- catch (err) {
23
- if (isNotFoundError(err)) {
24
- throw new SafeOpenError("not-found", "root dir not found");
25
- }
26
- throw err;
27
- }
28
- const rootWithSep = ensureTrailingSep(rootReal);
29
- const resolved = path.resolve(rootWithSep, params.relativePath);
30
- if (!resolved.startsWith(rootWithSep)) {
31
- throw new SafeOpenError("invalid-path", "path escapes root");
32
- }
33
- const supportsNoFollow = process.platform !== "win32" && "O_NOFOLLOW" in fsConstants;
34
- const flags = fsConstants.O_RDONLY | (supportsNoFollow ? fsConstants.O_NOFOLLOW : 0);
16
+ async function openVerifiedLocalFile(filePath) {
35
17
  let handle;
36
18
  try {
37
- handle = await fs.open(resolved, flags);
19
+ handle = await fs.open(filePath, OPEN_READ_FLAGS);
38
20
  }
39
21
  catch (err) {
40
- if (isNotFoundError(err)) {
22
+ if (isNotFoundPathError(err)) {
41
23
  throw new SafeOpenError("not-found", "file not found");
42
24
  }
43
25
  if (isSymlinkOpenError(err)) {
44
- throw new SafeOpenError("invalid-path", "symlink open blocked");
26
+ throw new SafeOpenError("symlink", "symlink open blocked", { cause: err });
45
27
  }
46
28
  throw err;
47
29
  }
48
30
  try {
49
- const lstat = await fs.lstat(resolved).catch(() => null);
50
- if (lstat?.isSymbolicLink()) {
51
- throw new SafeOpenError("invalid-path", "symlink not allowed");
52
- }
53
- const realPath = await fs.realpath(resolved);
54
- if (!realPath.startsWith(rootWithSep)) {
55
- throw new SafeOpenError("invalid-path", "path escapes root");
31
+ const [stat, lstat] = await Promise.all([handle.stat(), fs.lstat(filePath)]);
32
+ if (lstat.isSymbolicLink()) {
33
+ throw new SafeOpenError("symlink", "symlink not allowed");
56
34
  }
57
- const stat = await handle.stat();
58
35
  if (!stat.isFile()) {
59
- throw new SafeOpenError("invalid-path", "not a file");
36
+ throw new SafeOpenError("not-file", "not a file");
60
37
  }
38
+ if (stat.ino !== lstat.ino || stat.dev !== lstat.dev) {
39
+ throw new SafeOpenError("path-mismatch", "path changed during read");
40
+ }
41
+ const realPath = await fs.realpath(filePath);
61
42
  const realStat = await fs.stat(realPath);
62
43
  if (stat.ino !== realStat.ino || stat.dev !== realStat.dev) {
63
- throw new SafeOpenError("invalid-path", "path mismatch");
44
+ throw new SafeOpenError("path-mismatch", "path mismatch");
64
45
  }
65
46
  return { handle, realPath, stat };
66
47
  }
67
48
  catch (err) {
68
49
  await handle.close().catch(() => { });
69
- if (err instanceof SafeOpenError)
50
+ if (err instanceof SafeOpenError) {
70
51
  throw err;
71
- if (isNotFoundError(err)) {
52
+ }
53
+ if (isNotFoundPathError(err)) {
72
54
  throw new SafeOpenError("not-found", "file not found");
73
55
  }
74
56
  throw err;
75
57
  }
76
58
  }
59
+ export async function openFileWithinRoot(params) {
60
+ let rootReal;
61
+ try {
62
+ rootReal = await fs.realpath(params.rootDir);
63
+ }
64
+ catch (err) {
65
+ if (isNotFoundPathError(err)) {
66
+ throw new SafeOpenError("not-found", "root dir not found");
67
+ }
68
+ throw err;
69
+ }
70
+ const rootWithSep = ensureTrailingSep(rootReal);
71
+ const resolved = path.resolve(rootWithSep, params.relativePath);
72
+ if (!isPathInside(rootWithSep, resolved)) {
73
+ throw new SafeOpenError("invalid-path", "path escapes root");
74
+ }
75
+ let opened;
76
+ try {
77
+ opened = await openVerifiedLocalFile(resolved);
78
+ }
79
+ catch (err) {
80
+ if (err instanceof SafeOpenError) {
81
+ if (err.code === "not-found") {
82
+ throw err;
83
+ }
84
+ throw new SafeOpenError("invalid-path", "path is not a regular file under root", {
85
+ cause: err,
86
+ });
87
+ }
88
+ throw err;
89
+ }
90
+ if (!isPathInside(rootWithSep, opened.realPath)) {
91
+ await opened.handle.close().catch(() => { });
92
+ throw new SafeOpenError("invalid-path", "path escapes root");
93
+ }
94
+ return opened;
95
+ }
96
+ export async function readLocalFileSafely(params) {
97
+ const opened = await openVerifiedLocalFile(params.filePath);
98
+ try {
99
+ if (params.maxBytes !== undefined && opened.stat.size > params.maxBytes) {
100
+ throw new SafeOpenError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${opened.stat.size})`);
101
+ }
102
+ const buffer = await opened.handle.readFile();
103
+ return { buffer, realPath: opened.realPath, stat: opened.stat };
104
+ }
105
+ finally {
106
+ await opened.handle.close().catch(() => { });
107
+ }
108
+ }
@@ -118,7 +118,7 @@ async function readLockPayload(lockPath) {
118
118
  function resolveGatewayLockPath(env) {
119
119
  const stateDir = resolveStateDir(env);
120
120
  const configPath = resolveConfigPath(env, stateDir);
121
- const hash = createHash("sha1").update(configPath).digest("hex").slice(0, 8);
121
+ const hash = createHash("sha256").update(configPath).digest("hex").slice(0, 8);
122
122
  const lockDir = resolveGatewayLockDir();
123
123
  const lockPath = path.join(lockDir, `gateway.${hash}.lock`);
124
124
  return { lockPath, configPath };
@@ -186,7 +186,11 @@ export async function acquireGatewayLock(opts = {}) {
186
186
  stale = Date.now() - st.mtimeMs > staleMs;
187
187
  }
188
188
  catch {
189
- stale = true;
189
+ // On Windows or locked filesystems we may be unable to stat the
190
+ // lock file even though the existing gateway is still healthy.
191
+ // Treat the lock as non-stale so we keep waiting instead of
192
+ // forcefully removing another gateway's lock.
193
+ stale = false;
190
194
  }
191
195
  }
192
196
  if (stale) {
@@ -1,3 +1,4 @@
1
+ import { isHeartbeatActionWakeReason, normalizeHeartbeatWakeReason, resolveHeartbeatReasonKind, } from "./heartbeat-reason.js";
1
2
  let handler = null;
2
3
  let handlerGeneration = 0;
3
4
  const pendingWakes = new Map();
@@ -8,34 +9,27 @@ let timerDueAt = null;
8
9
  let timerKind = null;
9
10
  const DEFAULT_COALESCE_MS = 250;
10
11
  const DEFAULT_RETRY_MS = 1_000;
11
- const HOOK_REASON_PREFIX = "hook:";
12
12
  const REASON_PRIORITY = {
13
13
  RETRY: 0,
14
14
  INTERVAL: 1,
15
15
  DEFAULT: 2,
16
16
  ACTION: 3,
17
17
  };
18
- function isActionWakeReason(reason) {
19
- return reason === "manual" || reason === "exec-event" || reason.startsWith(HOOK_REASON_PREFIX);
20
- }
21
18
  function resolveReasonPriority(reason) {
22
- if (reason === "retry") {
19
+ const kind = resolveHeartbeatReasonKind(reason);
20
+ if (kind === "retry") {
23
21
  return REASON_PRIORITY.RETRY;
24
22
  }
25
- if (reason === "interval") {
23
+ if (kind === "interval") {
26
24
  return REASON_PRIORITY.INTERVAL;
27
25
  }
28
- if (isActionWakeReason(reason)) {
26
+ if (isHeartbeatActionWakeReason(reason)) {
29
27
  return REASON_PRIORITY.ACTION;
30
28
  }
31
29
  return REASON_PRIORITY.DEFAULT;
32
30
  }
33
31
  function normalizeWakeReason(reason) {
34
- if (typeof reason !== "string") {
35
- return "requested";
36
- }
37
- const trimmed = reason.trim();
38
- return trimmed.length > 0 ? trimmed : "requested";
32
+ return normalizeHeartbeatWakeReason(reason);
39
33
  }
40
34
  function normalizeWakeTarget(value) {
41
35
  const trimmed = typeof value === "string" ? value.trim() : "";
@@ -0,0 +1,19 @@
1
+ {
2
+ "blockedKeys": [
3
+ "NODE_OPTIONS",
4
+ "NODE_PATH",
5
+ "PYTHONHOME",
6
+ "PYTHONPATH",
7
+ "PERL5LIB",
8
+ "PERL5OPT",
9
+ "RUBYLIB",
10
+ "RUBYOPT",
11
+ "BASH_ENV",
12
+ "ENV",
13
+ "SHELL",
14
+ "GCONV_PATH",
15
+ "IFS",
16
+ "SSLKEYLOGFILE"
17
+ ],
18
+ "blockedPrefixes": ["DYLD_", "LD_", "BASH_FUNC_"]
19
+ }
@@ -0,0 +1,66 @@
1
+ import HOST_ENV_SECURITY_POLICY_JSON from "./host-env-security-policy.json" with { type: "json" };
2
+ const PORTABLE_ENV_VAR_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
3
+ const HOST_ENV_SECURITY_POLICY = HOST_ENV_SECURITY_POLICY_JSON;
4
+ export const HOST_DANGEROUS_ENV_KEY_VALUES = Object.freeze(HOST_ENV_SECURITY_POLICY.blockedKeys.map((key) => key.toUpperCase()));
5
+ export const HOST_DANGEROUS_ENV_PREFIXES = Object.freeze(HOST_ENV_SECURITY_POLICY.blockedPrefixes.map((prefix) => prefix.toUpperCase()));
6
+ export const HOST_DANGEROUS_ENV_KEYS = new Set(HOST_DANGEROUS_ENV_KEY_VALUES);
7
+ export function normalizeEnvVarKey(rawKey, options) {
8
+ const key = rawKey.trim();
9
+ if (!key) {
10
+ return null;
11
+ }
12
+ if (options?.portable && !PORTABLE_ENV_VAR_KEY.test(key)) {
13
+ return null;
14
+ }
15
+ return key;
16
+ }
17
+ export function isDangerousHostEnvVarName(rawKey) {
18
+ const key = normalizeEnvVarKey(rawKey);
19
+ if (!key) {
20
+ return false;
21
+ }
22
+ const upper = key.toUpperCase();
23
+ if (HOST_DANGEROUS_ENV_KEYS.has(upper)) {
24
+ return true;
25
+ }
26
+ return HOST_DANGEROUS_ENV_PREFIXES.some((prefix) => upper.startsWith(prefix));
27
+ }
28
+ export function sanitizeHostExecEnv(params) {
29
+ const baseEnv = params?.baseEnv ?? process.env;
30
+ const overrides = params?.overrides ?? undefined;
31
+ const blockPathOverrides = params?.blockPathOverrides ?? true;
32
+ const merged = {};
33
+ for (const [rawKey, value] of Object.entries(baseEnv)) {
34
+ if (typeof value !== "string") {
35
+ continue;
36
+ }
37
+ const key = normalizeEnvVarKey(rawKey, { portable: true });
38
+ if (!key || isDangerousHostEnvVarName(key)) {
39
+ continue;
40
+ }
41
+ merged[key] = value;
42
+ }
43
+ if (!overrides) {
44
+ return merged;
45
+ }
46
+ for (const [rawKey, value] of Object.entries(overrides)) {
47
+ if (typeof value !== "string") {
48
+ continue;
49
+ }
50
+ const key = normalizeEnvVarKey(rawKey, { portable: true });
51
+ if (!key) {
52
+ continue;
53
+ }
54
+ const upper = key.toUpperCase();
55
+ // PATH is part of the security boundary (command resolution + safe-bin checks). Never allow
56
+ // request-scoped PATH overrides from agents/gateways.
57
+ if (blockPathOverrides && upper === "PATH") {
58
+ continue;
59
+ }
60
+ if (isDangerousHostEnvVarName(upper)) {
61
+ continue;
62
+ }
63
+ merged[key] = value;
64
+ }
65
+ return merged;
66
+ }