@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
@@ -4,6 +4,7 @@ import { parseDurationMs } from "../cli/parse-duration.js";
4
4
  import { ElevatedAllowFromSchema } from "./zod-schema.agent-runtime.js";
5
5
  import { createAllowDenyChannelRulesSchema } from "./zod-schema.allowdeny.js";
6
6
  import { GroupChatSchema, InboundDebounceSchema, NativeCommandsSettingSchema, QueueSchema, TtsConfigSchema, } from "./zod-schema.core.js";
7
+ import { sensitive } from "./zod-schema.sensitive.js";
7
8
  const SessionResetConfigSchema = z
8
9
  .object({
9
10
  mode: z.union([z.literal("daily"), z.literal("idle")]).optional(),
@@ -56,6 +57,13 @@ export const SessionSchema = z
56
57
  })
57
58
  .strict()
58
59
  .optional(),
60
+ threadBindings: z
61
+ .object({
62
+ enabled: z.boolean().optional(),
63
+ ttlHours: z.number().nonnegative().optional(),
64
+ })
65
+ .strict()
66
+ .optional(),
59
67
  maintenance: z
60
68
  .object({
61
69
  mode: z.enum(["enforce", "warn"]).optional(),
@@ -106,6 +114,35 @@ export const MessagesSchema = z
106
114
  ackReaction: z.string().optional(),
107
115
  ackReactionScope: z.enum(["group-mentions", "group-all", "direct", "all"]).optional(),
108
116
  removeAckAfterReply: z.boolean().optional(),
117
+ statusReactions: z
118
+ .object({
119
+ enabled: z.boolean().optional(),
120
+ emojis: z
121
+ .object({
122
+ thinking: z.string().optional(),
123
+ tool: z.string().optional(),
124
+ coding: z.string().optional(),
125
+ web: z.string().optional(),
126
+ done: z.string().optional(),
127
+ error: z.string().optional(),
128
+ stallSoft: z.string().optional(),
129
+ stallHard: z.string().optional(),
130
+ })
131
+ .strict()
132
+ .optional(),
133
+ timing: z
134
+ .object({
135
+ debounceMs: z.number().int().min(0).optional(),
136
+ stallSoftMs: z.number().int().min(0).optional(),
137
+ stallHardMs: z.number().int().min(0).optional(),
138
+ doneHoldMs: z.number().int().min(0).optional(),
139
+ errorHoldMs: z.number().int().min(0).optional(),
140
+ })
141
+ .strict()
142
+ .optional(),
143
+ })
144
+ .strict()
145
+ .optional(),
109
146
  suppressToolErrors: z.boolean().optional(),
110
147
  tts: TtsConfigSchema,
111
148
  })
@@ -120,11 +157,13 @@ export const CommandsSchema = z
120
157
  bashForegroundMs: z.number().int().min(0).max(30_000).optional(),
121
158
  config: z.boolean().optional(),
122
159
  debug: z.boolean().optional(),
123
- restart: z.boolean().optional(),
160
+ restart: z.boolean().optional().default(true),
124
161
  useAccessGroups: z.boolean().optional(),
125
162
  ownerAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
163
+ ownerDisplay: z.enum(["raw", "hash"]).optional().default("raw"),
164
+ ownerDisplaySecret: z.string().optional().register(sensitive),
126
165
  allowFrom: ElevatedAllowFromSchema.optional(),
127
166
  })
128
167
  .strict()
129
168
  .optional()
130
- .default({ native: "auto", nativeSkills: "auto" });
169
+ .default(() => ({ native: "auto", nativeSkills: "auto", restart: true, ownerDisplay: "raw" }));
@@ -93,6 +93,9 @@ export async function readCronRunLogEntries(filePath, opts) {
93
93
  }
94
94
  : undefined,
95
95
  };
96
+ if (typeof obj.delivered === "boolean") {
97
+ entry.delivered = obj.delivered;
98
+ }
96
99
  if (typeof obj.sessionId === "string" && obj.sessionId.trim().length > 0) {
97
100
  entry.sessionId = obj.sessionId;
98
101
  }
@@ -35,7 +35,11 @@ export function computeNextRunAtMs(schedule, nowMs) {
35
35
  const steps = Math.max(1, Math.floor((elapsed + everyMs - 1) / everyMs));
36
36
  return anchor + steps * everyMs;
37
37
  }
38
- const expr = schedule.expr.trim();
38
+ const exprSource = schedule.expr;
39
+ if (typeof exprSource !== "string") {
40
+ throw new Error("invalid cron schedule: expr is required");
41
+ }
42
+ const expr = exprSource.trim();
39
43
  if (!expr) {
40
44
  return undefined;
41
45
  }
@@ -43,17 +47,24 @@ export function computeNextRunAtMs(schedule, nowMs) {
43
47
  timezone: resolveCronTimezone(schedule.tz),
44
48
  catch: false,
45
49
  });
46
- // Cron operates at second granularity, so floor nowMs to the start of the
47
- // current second. This prevents the lookback from landing inside a matching
48
- // second — if nowMs is e.g. 12:00:00.500 and the pattern fires at second 0,
49
- // a 1ms lookback (12:00:00.499) is still *within* that second, causing
50
- // croner to skip ahead to the next occurrence (e.g. the following day).
51
- // Flooring first ensures the lookback always falls in the *previous* second.
52
- const nowSecondMs = Math.floor(nowMs / 1000) * 1000;
53
- const next = cron.nextRun(new Date(nowSecondMs - 1));
50
+ const next = cron.nextRun(new Date(nowMs));
54
51
  if (!next) {
55
52
  return undefined;
56
53
  }
57
54
  const nextMs = next.getTime();
58
- return Number.isFinite(nextMs) && nextMs >= nowSecondMs ? nextMs : undefined;
55
+ if (!Number.isFinite(nextMs)) {
56
+ return undefined;
57
+ }
58
+ if (nextMs > nowMs) {
59
+ return nextMs;
60
+ }
61
+ // Guard against same-second rescheduling loops: if croner returns
62
+ // "now" (or an earlier instant), retry from the next whole second.
63
+ const nextSecondMs = Math.floor(nowMs / 1000) * 1000 + 1000;
64
+ const retry = cron.nextRun(new Date(nextSecondMs));
65
+ if (!retry) {
66
+ return undefined;
67
+ }
68
+ const retryMs = retry.getTime();
69
+ return Number.isFinite(retryMs) && retryMs > nowMs ? retryMs : undefined;
59
70
  }
@@ -1,22 +1,40 @@
1
- import { applyJobPatch, computeJobNextRunAtMs, createJob, findJobOrThrow, isJobDue, nextWakeAtMs, recomputeNextRuns, } from "./jobs.js";
1
+ import { applyJobPatch, computeJobNextRunAtMs, createJob, findJobOrThrow, isJobDue, nextWakeAtMs, recomputeNextRuns, recomputeNextRunsForMaintenance, } from "./jobs.js";
2
2
  import { locked } from "./locked.js";
3
3
  import { ensureLoaded, persist, warnIfDisabled } from "./store.js";
4
4
  import { armTimer, emit, executeJob, runMissedJobs, stopTimer, wake } from "./timer.js";
5
+ async function ensureLoadedForRead(state) {
6
+ await ensureLoaded(state, { skipRecompute: true });
7
+ if (!state.store) {
8
+ return;
9
+ }
10
+ // Use the maintenance-only version so that read-only operations never
11
+ // advance a past-due nextRunAtMs without executing the job (#16156).
12
+ const changed = recomputeNextRunsForMaintenance(state);
13
+ if (changed) {
14
+ await persist(state);
15
+ }
16
+ }
5
17
  export async function start(state) {
18
+ if (!state.deps.cronEnabled) {
19
+ state.deps.log.info({ enabled: false }, "cron: disabled");
20
+ return;
21
+ }
22
+ const startupInterruptedJobIds = new Set();
6
23
  await locked(state, async () => {
7
- if (!state.deps.cronEnabled) {
8
- state.deps.log.info({ enabled: false }, "cron: disabled");
9
- return;
10
- }
11
24
  await ensureLoaded(state, { skipRecompute: true });
12
25
  const jobs = state.store?.jobs ?? [];
13
26
  for (const job of jobs) {
14
27
  if (typeof job.state.runningAtMs === "number") {
15
28
  state.deps.log.warn({ jobId: job.id, runningAtMs: job.state.runningAtMs }, "cron: clearing stale running marker on startup");
16
29
  job.state.runningAtMs = undefined;
30
+ startupInterruptedJobIds.add(job.id);
17
31
  }
18
32
  }
19
- await runMissedJobs(state);
33
+ await persist(state);
34
+ });
35
+ await runMissedJobs(state, { skipJobIds: startupInterruptedJobIds });
36
+ await locked(state, async () => {
37
+ await ensureLoaded(state, { forceReload: true, skipRecompute: true });
20
38
  recomputeNextRuns(state);
21
39
  await persist(state);
22
40
  armTimer(state);
@@ -32,13 +50,7 @@ export function stop(state) {
32
50
  }
33
51
  export async function status(state) {
34
52
  return await locked(state, async () => {
35
- await ensureLoaded(state, { skipRecompute: true });
36
- if (state.store) {
37
- const changed = recomputeNextRuns(state);
38
- if (changed) {
39
- await persist(state);
40
- }
41
- }
53
+ await ensureLoadedForRead(state);
42
54
  return {
43
55
  enabled: state.deps.cronEnabled,
44
56
  storePath: state.deps.storePath,
@@ -49,13 +61,7 @@ export async function status(state) {
49
61
  }
50
62
  export async function list(state, opts) {
51
63
  return await locked(state, async () => {
52
- await ensureLoaded(state, { skipRecompute: true });
53
- if (state.store) {
54
- const changed = recomputeNextRuns(state);
55
- if (changed) {
56
- await persist(state);
57
- }
58
- }
64
+ await ensureLoadedForRead(state);
59
65
  const includeDisabled = opts?.includeDisabled === true;
60
66
  const jobs = (state.store?.jobs ?? []).filter((j) => includeDisabled || j.enabled);
61
67
  return jobs.toSorted((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0));
@@ -90,7 +96,7 @@ export async function add(state, input) {
90
96
  export async function update(state, id, patch) {
91
97
  return await locked(state, async () => {
92
98
  warnIfDisabled(state, "update");
93
- await ensureLoaded(state);
99
+ await ensureLoaded(state, { skipRecompute: true });
94
100
  const job = findJobOrThrow(state, id);
95
101
  const now = state.deps.nowMs();
96
102
  applyJobPatch(job, patch);
@@ -121,6 +127,14 @@ export async function update(state, id, patch) {
121
127
  job.state.runningAtMs = undefined;
122
128
  }
123
129
  }
130
+ else if (job.enabled) {
131
+ // Non-schedule edits should not mutate other jobs, but still repair a
132
+ // missing/corrupt nextRunAtMs for the updated job.
133
+ const nextRun = job.state.nextRunAtMs;
134
+ if (typeof nextRun !== "number" || !Number.isFinite(nextRun)) {
135
+ job.state.nextRunAtMs = computeJobNextRunAtMs(job, now);
136
+ }
137
+ }
124
138
  await persist(state);
125
139
  armTimer(state);
126
140
  emit(state, {
@@ -19,6 +19,13 @@ const MIN_REFIRE_GAP_MS = 2_000;
19
19
  * from wedging the entire cron lane.
20
20
  */
21
21
  const DEFAULT_JOB_TIMEOUT_MS = 10 * 60_000; // 10 minutes
22
+ function resolveRunConcurrency(state) {
23
+ const raw = state.deps.cronConfig?.maxConcurrentRuns;
24
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
25
+ return 1;
26
+ }
27
+ return Math.max(1, Math.floor(raw));
28
+ }
22
29
  /**
23
30
  * Exponential backoff delays (in ms) indexed by consecutive error count.
24
31
  * After the last entry the delay stays constant.
@@ -45,6 +52,7 @@ function applyJobResult(state, job, result) {
45
52
  job.state.lastStatus = result.status;
46
53
  job.state.lastDurationMs = Math.max(0, result.endedAt - result.startedAt);
47
54
  job.state.lastError = result.error;
55
+ job.state.lastDelivered = result.delivered;
48
56
  job.updatedAtMs = result.endedAt;
49
57
  // Track consecutive errors for backoff / auto-disable.
50
58
  if (result.status === "error") {
@@ -187,8 +195,8 @@ export async function onTimer(state) {
187
195
  job: j,
188
196
  }));
189
197
  });
190
- const results = [];
191
- for (const { id, job } of dueJobs) {
198
+ const runDueJob = async (params) => {
199
+ const { id, job } = params;
192
200
  const startedAt = state.deps.nowMs();
193
201
  job.state.runningAtMs = startedAt;
194
202
  emit(state, { jobId: job.id, action: "started", runAtMs: startedAt });
@@ -219,23 +227,41 @@ export async function onTimer(state) {
219
227
  }
220
228
  })()
221
229
  : await executeJobCore(state, job);
222
- results.push({ jobId: id, ...result, startedAt, endedAt: state.deps.nowMs() });
230
+ return { jobId: id, ...result, startedAt, endedAt: state.deps.nowMs() };
223
231
  }
224
232
  catch (err) {
225
233
  state.deps.log.warn({ jobId: id, jobName: job.name, timeoutMs: jobTimeoutMs ?? null }, `cron: job failed: ${String(err)}`);
226
- results.push({
234
+ return {
227
235
  jobId: id,
228
236
  status: "error",
229
237
  error: String(err),
230
238
  startedAt,
231
239
  endedAt: state.deps.nowMs(),
232
- });
240
+ };
233
241
  }
234
- }
235
- if (results.length > 0) {
242
+ };
243
+ const concurrency = Math.min(resolveRunConcurrency(state), Math.max(1, dueJobs.length));
244
+ const results = Array.from({ length: dueJobs.length });
245
+ let cursor = 0;
246
+ const workers = Array.from({ length: concurrency }, async () => {
247
+ for (;;) {
248
+ const index = cursor++;
249
+ if (index >= dueJobs.length) {
250
+ return;
251
+ }
252
+ const due = dueJobs[index];
253
+ if (!due) {
254
+ return;
255
+ }
256
+ results[index] = await runDueJob(due);
257
+ }
258
+ });
259
+ await Promise.all(workers);
260
+ const completedResults = results.filter((entry) => entry !== undefined);
261
+ if (completedResults.length > 0) {
236
262
  await locked(state, async () => {
237
263
  await ensureLoaded(state, { forceReload: true, skipRecompute: true });
238
- for (const result of results) {
264
+ for (const result of completedResults) {
239
265
  const job = state.store?.jobs.find((j) => j.id === result.jobId);
240
266
  if (!job) {
241
267
  continue;
@@ -243,6 +269,7 @@ export async function onTimer(state) {
243
269
  const shouldDelete = applyJobResult(state, job, {
244
270
  status: result.status,
245
271
  error: result.error,
272
+ delivered: result.delivered,
246
273
  startedAt: result.startedAt,
247
274
  endedAt: result.endedAt,
248
275
  });
@@ -342,18 +369,88 @@ function collectRunnableJobs(state, nowMs, opts) {
342
369
  }));
343
370
  }
344
371
  export async function runMissedJobs(state, opts) {
345
- if (!state.store) {
346
- return;
347
- }
348
- const now = state.deps.nowMs();
349
- const skipJobIds = opts?.skipJobIds;
350
- const missed = collectRunnableJobs(state, now, { skipJobIds, skipAtIfAlreadyRan: true });
351
- if (missed.length > 0) {
372
+ const startupCandidates = await locked(state, async () => {
373
+ await ensureLoaded(state, { skipRecompute: true });
374
+ if (!state.store) {
375
+ return [];
376
+ }
377
+ const now = state.deps.nowMs();
378
+ const skipJobIds = opts?.skipJobIds;
379
+ const missed = collectRunnableJobs(state, now, { skipJobIds, skipAtIfAlreadyRan: true });
380
+ if (missed.length === 0) {
381
+ return [];
382
+ }
352
383
  state.deps.log.info({ count: missed.length, jobIds: missed.map((j) => j.id) }, "cron: running missed jobs after restart");
353
384
  for (const job of missed) {
354
- await executeJob(state, job, now, { forced: false });
385
+ job.state.runningAtMs = now;
386
+ job.state.lastError = undefined;
387
+ }
388
+ await persist(state);
389
+ return missed.map((job) => ({ jobId: job.id, job }));
390
+ });
391
+ if (startupCandidates.length === 0) {
392
+ return;
393
+ }
394
+ const outcomes = [];
395
+ for (const candidate of startupCandidates) {
396
+ const startedAt = state.deps.nowMs();
397
+ emit(state, { jobId: candidate.job.id, action: "started", runAtMs: startedAt });
398
+ try {
399
+ const result = await executeJobCore(state, candidate.job);
400
+ outcomes.push({
401
+ jobId: candidate.jobId,
402
+ status: result.status,
403
+ error: result.error,
404
+ summary: result.summary,
405
+ delivered: result.delivered,
406
+ sessionId: result.sessionId,
407
+ sessionKey: result.sessionKey,
408
+ model: result.model,
409
+ provider: result.provider,
410
+ usage: result.usage,
411
+ startedAt,
412
+ endedAt: state.deps.nowMs(),
413
+ });
414
+ }
415
+ catch (err) {
416
+ outcomes.push({
417
+ jobId: candidate.jobId,
418
+ status: "error",
419
+ error: String(err),
420
+ startedAt,
421
+ endedAt: state.deps.nowMs(),
422
+ });
355
423
  }
356
424
  }
425
+ await locked(state, async () => {
426
+ await ensureLoaded(state, { forceReload: true, skipRecompute: true });
427
+ if (!state.store) {
428
+ return;
429
+ }
430
+ for (const result of outcomes) {
431
+ const job = state.store.jobs.find((entry) => entry.id === result.jobId);
432
+ if (!job) {
433
+ continue;
434
+ }
435
+ const shouldDelete = applyJobResult(state, job, {
436
+ status: result.status,
437
+ error: result.error,
438
+ delivered: result.delivered,
439
+ startedAt: result.startedAt,
440
+ endedAt: result.endedAt,
441
+ });
442
+ emitJobFinished(state, job, result, result.startedAt);
443
+ if (shouldDelete) {
444
+ state.store.jobs = state.store.jobs.filter((entry) => entry.id !== job.id);
445
+ emit(state, { jobId: job.id, action: "removed" });
446
+ }
447
+ }
448
+ // Preserve any new past-due nextRunAtMs values that became due while
449
+ // startup catch-up was running. They should execute on a future tick
450
+ // instead of being silently advanced.
451
+ recomputeNextRunsForMaintenance(state);
452
+ await persist(state);
453
+ });
357
454
  }
358
455
  export async function runDueJobs(state) {
359
456
  if (!state.store) {
@@ -463,6 +560,7 @@ async function executeJobCore(state, job) {
463
560
  status: res.status,
464
561
  error: res.error,
465
562
  summary: res.summary,
563
+ delivered: res.delivered,
466
564
  sessionId: res.sessionId,
467
565
  sessionKey: res.sessionKey,
468
566
  model: res.model,
@@ -493,6 +591,7 @@ export async function executeJob(state, job, _nowMs, _opts) {
493
591
  const shouldDelete = applyJobResult(state, job, {
494
592
  status: coreResult.status,
495
593
  error: coreResult.error,
594
+ delivered: coreResult.delivered,
496
595
  startedAt,
497
596
  endedAt,
498
597
  });
@@ -509,6 +608,7 @@ function emitJobFinished(state, job, result, runAtMs) {
509
608
  status: result.status,
510
609
  error: result.error,
511
610
  summary: result.summary,
611
+ delivered: result.delivered,
512
612
  sessionId: result.sessionId,
513
613
  sessionKey: result.sessionKey,
514
614
  runAtMs,
@@ -33,5 +33,7 @@ export function resolveCronStaggerMs(schedule) {
33
33
  if (explicit !== undefined) {
34
34
  return explicit;
35
35
  }
36
- return resolveDefaultCronStaggerMs(schedule.expr) ?? 0;
36
+ const expr = schedule.expr;
37
+ const cronExpr = typeof expr === "string" ? expr : "";
38
+ return resolveDefaultCronStaggerMs(cronExpr) ?? 0;
37
39
  }
@@ -0,0 +1,21 @@
1
+ import { splitArgsPreservingQuotes } from "./arg-split.js";
2
+ import { assertNoCmdLineBreak } from "./cmd-set.js";
3
+ export function quoteCmdScriptArg(value) {
4
+ assertNoCmdLineBreak(value, "Command argument");
5
+ if (!value) {
6
+ return '""';
7
+ }
8
+ const escaped = value.replace(/"/g, '\\"').replace(/%/g, "%%").replace(/!/g, "^!");
9
+ if (!/[ \t"&|<>^()%!]/g.test(value)) {
10
+ return escaped;
11
+ }
12
+ return `"${escaped}"`;
13
+ }
14
+ export function unescapeCmdScriptArg(value) {
15
+ return value.replace(/\^!/g, "!").replace(/%%/g, "%");
16
+ }
17
+ export function parseCmdScriptCommandLine(value) {
18
+ // Script renderer escapes quotes (`\"`) and cmd expansions (`%%`, `^!`).
19
+ // Keep all other backslashes literal so Windows drive/UNC paths survive.
20
+ return splitArgsPreservingQuotes(value, { escapeMode: "backslash-quote-only" }).map(unescapeCmdScriptArg);
21
+ }
@@ -0,0 +1,58 @@
1
+ export function assertNoCmdLineBreak(value, field) {
2
+ if (/[\r\n]/.test(value)) {
3
+ throw new Error(`${field} cannot contain CR or LF in Windows task scripts.`);
4
+ }
5
+ }
6
+ function escapeCmdSetAssignmentComponent(value) {
7
+ return value.replace(/\^/g, "^^").replace(/%/g, "%%").replace(/!/g, "^!").replace(/"/g, '^"');
8
+ }
9
+ function unescapeCmdSetAssignmentComponent(value) {
10
+ let out = "";
11
+ for (let i = 0; i < value.length; i += 1) {
12
+ const ch = value[i];
13
+ const next = value[i + 1];
14
+ if (ch === "^" && (next === "^" || next === '"' || next === "!")) {
15
+ out += next;
16
+ i += 1;
17
+ continue;
18
+ }
19
+ if (ch === "%" && next === "%") {
20
+ out += "%";
21
+ i += 1;
22
+ continue;
23
+ }
24
+ out += ch;
25
+ }
26
+ return out;
27
+ }
28
+ export function parseCmdSetAssignment(line) {
29
+ const raw = line.trim();
30
+ if (!raw) {
31
+ return null;
32
+ }
33
+ const quoted = raw.startsWith('"') && raw.endsWith('"') && raw.length >= 2;
34
+ const assignment = quoted ? raw.slice(1, -1) : raw;
35
+ const index = assignment.indexOf("=");
36
+ if (index <= 0) {
37
+ return null;
38
+ }
39
+ const key = assignment.slice(0, index).trim();
40
+ const value = assignment.slice(index + 1).trim();
41
+ if (!key) {
42
+ return null;
43
+ }
44
+ if (!quoted) {
45
+ return { key, value };
46
+ }
47
+ return {
48
+ key: unescapeCmdSetAssignmentComponent(key),
49
+ value: unescapeCmdSetAssignmentComponent(value),
50
+ };
51
+ }
52
+ export function renderCmdSetAssignment(key, value) {
53
+ assertNoCmdLineBreak(key, "Environment variable name");
54
+ assertNoCmdLineBreak(value, "Environment variable value");
55
+ const escapedKey = escapeCmdSetAssignmentComponent(key);
56
+ const escapedValue = escapeCmdSetAssignmentComponent(value);
57
+ return `set "${escapedKey}=${escapedValue}"`;
58
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -9,12 +9,14 @@ const DISCORD_API_RETRY_DEFAULTS = {
9
9
  };
10
10
  function parseDiscordApiErrorPayload(text) {
11
11
  const trimmed = text.trim();
12
- if (!trimmed.startsWith("{") || !trimmed.endsWith("}"))
12
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
13
13
  return null;
14
+ }
14
15
  try {
15
16
  const payload = JSON.parse(trimmed);
16
- if (payload && typeof payload === "object")
17
+ if (payload && typeof payload === "object") {
17
18
  return payload;
19
+ }
18
20
  }
19
21
  catch {
20
22
  return null;
@@ -26,24 +28,28 @@ function parseRetryAfterSeconds(text, response) {
26
28
  const retryAfter = payload && typeof payload.retry_after === "number" && Number.isFinite(payload.retry_after)
27
29
  ? payload.retry_after
28
30
  : undefined;
29
- if (retryAfter !== undefined)
31
+ if (retryAfter !== undefined) {
30
32
  return retryAfter;
33
+ }
31
34
  const header = response.headers.get("Retry-After");
32
- if (!header)
35
+ if (!header) {
33
36
  return undefined;
37
+ }
34
38
  const parsed = Number(header);
35
39
  return Number.isFinite(parsed) ? parsed : undefined;
36
40
  }
37
41
  function formatRetryAfterSeconds(value) {
38
- if (value === undefined || !Number.isFinite(value) || value < 0)
42
+ if (value === undefined || !Number.isFinite(value) || value < 0) {
39
43
  return undefined;
44
+ }
40
45
  const rounded = value < 10 ? value.toFixed(1) : Math.round(value).toString();
41
46
  return `${rounded}s`;
42
47
  }
43
48
  function formatDiscordApiErrorText(text) {
44
49
  const trimmed = text.trim();
45
- if (!trimmed)
50
+ if (!trimmed) {
46
51
  return undefined;
52
+ }
47
53
  const payload = parseDiscordApiErrorPayload(trimmed);
48
54
  if (!payload) {
49
55
  const looksJson = trimmed.startsWith("{") && trimmed.endsWith("}");
@@ -0,0 +1,22 @@
1
+ import { resolveTextChunkLimit } from "../auto-reply/chunk.js";
2
+ import { getChannelDock } from "../channels/dock.js";
3
+ import { normalizeAccountId } from "../routing/session-key.js";
4
+ const DEFAULT_DISCORD_DRAFT_STREAM_MIN = 200;
5
+ const DEFAULT_DISCORD_DRAFT_STREAM_MAX = 800;
6
+ export function resolveDiscordDraftStreamingChunking(cfg, accountId) {
7
+ const providerChunkLimit = getChannelDock("discord")?.outbound?.textChunkLimit;
8
+ const textLimit = resolveTextChunkLimit(cfg, "discord", accountId, {
9
+ fallbackLimit: providerChunkLimit,
10
+ });
11
+ const normalizedAccountId = normalizeAccountId(accountId);
12
+ const draftCfg = cfg?.channels?.discord?.accounts?.[normalizedAccountId]?.draftChunk ??
13
+ cfg?.channels?.discord?.draftChunk;
14
+ const maxRequested = Math.max(1, Math.floor(draftCfg?.maxChars ?? DEFAULT_DISCORD_DRAFT_STREAM_MAX));
15
+ const maxChars = Math.max(1, Math.min(maxRequested, textLimit));
16
+ const minRequested = Math.max(1, Math.floor(draftCfg?.minChars ?? DEFAULT_DISCORD_DRAFT_STREAM_MIN));
17
+ const minChars = Math.min(minRequested, maxChars);
18
+ const breakPreference = draftCfg?.breakPreference === "newline" || draftCfg?.breakPreference === "sentence"
19
+ ? draftCfg.breakPreference
20
+ : "paragraph";
21
+ return { minChars, maxChars, breakPreference };
22
+ }