@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,277 @@
1
+ import { parseExecArgvToken } from "./exec-approvals-analysis.js";
2
+ function isPathLikeToken(value) {
3
+ const trimmed = value.trim();
4
+ if (!trimmed) {
5
+ return false;
6
+ }
7
+ if (trimmed === "-") {
8
+ return false;
9
+ }
10
+ if (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("~")) {
11
+ return true;
12
+ }
13
+ if (trimmed.startsWith("/")) {
14
+ return true;
15
+ }
16
+ return /^[A-Za-z]:[\\/]/.test(trimmed);
17
+ }
18
+ function hasGlobToken(value) {
19
+ // Safe bins are stdin-only; globbing is both surprising and a historical bypass vector.
20
+ // Note: we still harden execution-time expansion separately.
21
+ return /[*?[\]]/.test(value);
22
+ }
23
+ const NO_FLAGS = new Set();
24
+ const toFlagSet = (flags) => {
25
+ if (!flags || flags.length === 0) {
26
+ return NO_FLAGS;
27
+ }
28
+ return new Set(flags);
29
+ };
30
+ function compileSafeBinProfile(fixture) {
31
+ return {
32
+ minPositional: fixture.minPositional,
33
+ maxPositional: fixture.maxPositional,
34
+ allowedValueFlags: toFlagSet(fixture.allowedValueFlags),
35
+ deniedFlags: toFlagSet(fixture.deniedFlags),
36
+ };
37
+ }
38
+ function compileSafeBinProfiles(fixtures) {
39
+ return Object.fromEntries(Object.entries(fixtures).map(([name, fixture]) => [name, compileSafeBinProfile(fixture)]));
40
+ }
41
+ export const SAFE_BIN_GENERIC_PROFILE_FIXTURE = {};
42
+ export const SAFE_BIN_PROFILE_FIXTURES = {
43
+ jq: {
44
+ maxPositional: 1,
45
+ allowedValueFlags: ["--arg", "--argjson", "--argstr"],
46
+ deniedFlags: [
47
+ "--argfile",
48
+ "--rawfile",
49
+ "--slurpfile",
50
+ "--from-file",
51
+ "--library-path",
52
+ "-L",
53
+ "-f",
54
+ ],
55
+ },
56
+ grep: {
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: [
62
+ "--regexp",
63
+ "--max-count",
64
+ "--after-context",
65
+ "--before-context",
66
+ "--context",
67
+ "--devices",
68
+ "--binary-files",
69
+ "--exclude",
70
+ "--include",
71
+ "--label",
72
+ "-e",
73
+ "-m",
74
+ "-A",
75
+ "-B",
76
+ "-C",
77
+ "-D",
78
+ ],
79
+ deniedFlags: [
80
+ "--file",
81
+ "--exclude-from",
82
+ "--dereference-recursive",
83
+ "--directories",
84
+ "--recursive",
85
+ "-f",
86
+ "-d",
87
+ "-r",
88
+ "-R",
89
+ ],
90
+ },
91
+ cut: {
92
+ maxPositional: 0,
93
+ allowedValueFlags: [
94
+ "--bytes",
95
+ "--characters",
96
+ "--fields",
97
+ "--delimiter",
98
+ "--output-delimiter",
99
+ "-b",
100
+ "-c",
101
+ "-f",
102
+ "-d",
103
+ ],
104
+ },
105
+ sort: {
106
+ maxPositional: 0,
107
+ allowedValueFlags: [
108
+ "--key",
109
+ "--field-separator",
110
+ "--buffer-size",
111
+ "--temporary-directory",
112
+ "--parallel",
113
+ "--batch-size",
114
+ "--random-source",
115
+ "-k",
116
+ "-t",
117
+ "-S",
118
+ "-T",
119
+ ],
120
+ // --compress-program can invoke an external executable and breaks stdin-only guarantees.
121
+ deniedFlags: ["--compress-program", "--files0-from", "--output", "-o"],
122
+ },
123
+ uniq: {
124
+ maxPositional: 0,
125
+ allowedValueFlags: [
126
+ "--skip-fields",
127
+ "--skip-chars",
128
+ "--check-chars",
129
+ "--group",
130
+ "-f",
131
+ "-s",
132
+ "-w",
133
+ ],
134
+ },
135
+ head: {
136
+ maxPositional: 0,
137
+ allowedValueFlags: ["--lines", "--bytes", "-n", "-c"],
138
+ },
139
+ tail: {
140
+ maxPositional: 0,
141
+ allowedValueFlags: [
142
+ "--lines",
143
+ "--bytes",
144
+ "--sleep-interval",
145
+ "--max-unchanged-stats",
146
+ "--pid",
147
+ "-n",
148
+ "-c",
149
+ ],
150
+ },
151
+ tr: {
152
+ minPositional: 1,
153
+ maxPositional: 2,
154
+ },
155
+ wc: {
156
+ maxPositional: 0,
157
+ deniedFlags: ["--files0-from"],
158
+ },
159
+ };
160
+ export const SAFE_BIN_GENERIC_PROFILE = compileSafeBinProfile(SAFE_BIN_GENERIC_PROFILE_FIXTURE);
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
+ }
179
+ function isSafeLiteralToken(value) {
180
+ if (!value || value === "-") {
181
+ return true;
182
+ }
183
+ return !hasGlobToken(value) && !isPathLikeToken(value);
184
+ }
185
+ function isInvalidValueToken(value) {
186
+ return !value || !isSafeLiteralToken(value);
187
+ }
188
+ function consumeLongOptionToken(args, index, flag, inlineValue, allowedValueFlags, deniedFlags) {
189
+ if (deniedFlags.has(flag)) {
190
+ return -1;
191
+ }
192
+ if (inlineValue !== undefined) {
193
+ return isSafeLiteralToken(inlineValue) ? index + 1 : -1;
194
+ }
195
+ if (!allowedValueFlags.has(flag)) {
196
+ return index + 1;
197
+ }
198
+ return isInvalidValueToken(args[index + 1]) ? -1 : index + 2;
199
+ }
200
+ function consumeShortOptionClusterToken(args, index, raw, cluster, flags, allowedValueFlags, deniedFlags) {
201
+ for (let j = 0; j < flags.length; j += 1) {
202
+ const flag = flags[j];
203
+ if (deniedFlags.has(flag)) {
204
+ return -1;
205
+ }
206
+ if (!allowedValueFlags.has(flag)) {
207
+ continue;
208
+ }
209
+ const inlineValue = cluster.slice(j + 1);
210
+ if (inlineValue) {
211
+ return isSafeLiteralToken(inlineValue) ? index + 1 : -1;
212
+ }
213
+ return isInvalidValueToken(args[index + 1]) ? -1 : index + 2;
214
+ }
215
+ return hasGlobToken(raw) ? -1 : index + 1;
216
+ }
217
+ function consumePositionalToken(token, positional) {
218
+ if (!isSafeLiteralToken(token)) {
219
+ return false;
220
+ }
221
+ positional.push(token);
222
+ return true;
223
+ }
224
+ function validatePositionalCount(positional, profile) {
225
+ const minPositional = profile.minPositional ?? 0;
226
+ if (positional.length < minPositional) {
227
+ return false;
228
+ }
229
+ return typeof profile.maxPositional !== "number" || positional.length <= profile.maxPositional;
230
+ }
231
+ export function validateSafeBinArgv(args, profile) {
232
+ const allowedValueFlags = profile.allowedValueFlags ?? NO_FLAGS;
233
+ const deniedFlags = profile.deniedFlags ?? NO_FLAGS;
234
+ const positional = [];
235
+ let i = 0;
236
+ while (i < args.length) {
237
+ const rawToken = args[i] ?? "";
238
+ const token = parseExecArgvToken(rawToken);
239
+ if (token.kind === "empty" || token.kind === "stdin") {
240
+ i += 1;
241
+ continue;
242
+ }
243
+ if (token.kind === "terminator") {
244
+ for (let j = i + 1; j < args.length; j += 1) {
245
+ const rest = args[j];
246
+ if (!rest || rest === "-") {
247
+ continue;
248
+ }
249
+ if (!consumePositionalToken(rest, positional)) {
250
+ return false;
251
+ }
252
+ }
253
+ break;
254
+ }
255
+ if (token.kind === "positional") {
256
+ if (!consumePositionalToken(token.raw, positional)) {
257
+ return false;
258
+ }
259
+ i += 1;
260
+ continue;
261
+ }
262
+ if (token.style === "long") {
263
+ const nextIndex = consumeLongOptionToken(args, i, token.flag, token.inlineValue, allowedValueFlags, deniedFlags);
264
+ if (nextIndex < 0) {
265
+ return false;
266
+ }
267
+ i = nextIndex;
268
+ continue;
269
+ }
270
+ const nextIndex = consumeShortOptionClusterToken(args, i, token.raw, token.cluster, token.flags, allowedValueFlags, deniedFlags);
271
+ if (nextIndex < 0) {
272
+ return false;
273
+ }
274
+ i = nextIndex;
275
+ }
276
+ return validatePositionalCount(positional, profile);
277
+ }
@@ -0,0 +1,33 @@
1
+ export function createFixedWindowRateLimiter(params) {
2
+ const maxRequests = Math.max(1, Math.floor(params.maxRequests));
3
+ const windowMs = Math.max(1, Math.floor(params.windowMs));
4
+ const now = params.now ?? Date.now;
5
+ let count = 0;
6
+ let windowStartMs = 0;
7
+ return {
8
+ consume() {
9
+ const nowMs = now();
10
+ if (nowMs - windowStartMs >= windowMs) {
11
+ windowStartMs = nowMs;
12
+ count = 0;
13
+ }
14
+ if (count >= maxRequests) {
15
+ return {
16
+ allowed: false,
17
+ retryAfterMs: Math.max(0, windowStartMs + windowMs - nowMs),
18
+ remaining: 0,
19
+ };
20
+ }
21
+ count += 1;
22
+ return {
23
+ allowed: true,
24
+ retryAfterMs: 0,
25
+ remaining: Math.max(0, maxRequests - count),
26
+ };
27
+ },
28
+ reset() {
29
+ count = 0;
30
+ windowStartMs = 0;
31
+ },
32
+ };
33
+ }
@@ -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) {
@@ -0,0 +1,61 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ export const DEFAULT_GIT_DISCOVERY_MAX_DEPTH = 12;
4
+ function walkUpFrom(startDir, opts, resolveAtDir) {
5
+ let current = path.resolve(startDir);
6
+ const maxDepth = opts.maxDepth ?? DEFAULT_GIT_DISCOVERY_MAX_DEPTH;
7
+ for (let i = 0; i < maxDepth; i += 1) {
8
+ const resolved = resolveAtDir(current);
9
+ if (resolved !== null && resolved !== undefined) {
10
+ return resolved;
11
+ }
12
+ const parent = path.dirname(current);
13
+ if (parent === current) {
14
+ break;
15
+ }
16
+ current = parent;
17
+ }
18
+ return null;
19
+ }
20
+ function hasGitMarker(repoRoot) {
21
+ const gitPath = path.join(repoRoot, ".git");
22
+ try {
23
+ const stat = fs.statSync(gitPath);
24
+ return stat.isDirectory() || stat.isFile();
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ }
30
+ export function findGitRoot(startDir, opts = {}) {
31
+ // A `.git` file counts as a repo marker even if it is not a valid gitdir pointer.
32
+ return walkUpFrom(startDir, opts, (repoRoot) => (hasGitMarker(repoRoot) ? repoRoot : null));
33
+ }
34
+ function resolveGitDirFromMarker(repoRoot) {
35
+ const gitPath = path.join(repoRoot, ".git");
36
+ try {
37
+ const stat = fs.statSync(gitPath);
38
+ if (stat.isDirectory()) {
39
+ return gitPath;
40
+ }
41
+ if (!stat.isFile()) {
42
+ return null;
43
+ }
44
+ const raw = fs.readFileSync(gitPath, "utf-8");
45
+ const match = raw.match(/gitdir:\s*(.+)/i);
46
+ if (!match?.[1]) {
47
+ return null;
48
+ }
49
+ return path.resolve(repoRoot, match[1].trim());
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ }
55
+ export function resolveGitHeadPath(startDir, opts = {}) {
56
+ // Stricter than findGitRoot: keep walking until a resolvable git dir is found.
57
+ return walkUpFrom(startDir, opts, (repoRoot) => {
58
+ const gitDir = resolveGitDirFromMarker(repoRoot);
59
+ return gitDir ? path.join(gitDir, "HEAD") : null;
60
+ });
61
+ }
@@ -1,5 +1,5 @@
1
1
  import { resolveUserTimezone } from "../agents/date-time.js";
2
- const ACTIVE_HOURS_TIME_PATTERN = /^([01]\d|2[0-3]|24):([0-5]\d)$/;
2
+ const ACTIVE_HOURS_TIME_PATTERN = /^(?:([01]\d|2[0-3]):([0-5]\d)|24:00)$/;
3
3
  function resolveActiveHoursTimezone(cfg, raw) {
4
4
  const trimmed = raw?.trim();
5
5
  if (!trimmed || trimmed === "user") {
@@ -71,7 +71,7 @@ export function isWithinActiveHours(cfg, heartbeat, nowMs) {
71
71
  return true;
72
72
  }
73
73
  if (startMin === endMin) {
74
- return true;
74
+ return false;
75
75
  }
76
76
  const timeZone = resolveActiveHoursTimezone(cfg, active.timezone);
77
77
  const currentMin = resolveMinutesInTimeZone(nowMs ?? Date.now(), timeZone);
@@ -0,0 +1,40 @@
1
+ function trimReason(reason) {
2
+ return typeof reason === "string" ? reason.trim() : "";
3
+ }
4
+ export function normalizeHeartbeatWakeReason(reason) {
5
+ const trimmed = trimReason(reason);
6
+ return trimmed.length > 0 ? trimmed : "requested";
7
+ }
8
+ export function resolveHeartbeatReasonKind(reason) {
9
+ const trimmed = trimReason(reason);
10
+ if (trimmed === "retry") {
11
+ return "retry";
12
+ }
13
+ if (trimmed === "interval") {
14
+ return "interval";
15
+ }
16
+ if (trimmed === "manual") {
17
+ return "manual";
18
+ }
19
+ if (trimmed === "exec-event") {
20
+ return "exec-event";
21
+ }
22
+ if (trimmed === "wake") {
23
+ return "wake";
24
+ }
25
+ if (trimmed.startsWith("cron:")) {
26
+ return "cron";
27
+ }
28
+ if (trimmed.startsWith("hook:")) {
29
+ return "hook";
30
+ }
31
+ return "other";
32
+ }
33
+ export function isHeartbeatEventDrivenReason(reason) {
34
+ const kind = resolveHeartbeatReasonKind(reason);
35
+ return kind === "exec-event" || kind === "cron" || kind === "wake" || kind === "hook";
36
+ }
37
+ export function isHeartbeatActionWakeReason(reason) {
38
+ const kind = resolveHeartbeatReasonKind(reason);
39
+ return kind === "manual" || kind === "exec-event" || kind === "hook";
40
+ }