@poolzin/pool-bot 2026.2.25 → 2026.2.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (506) hide show
  1. package/dist/acp/event-mapper.js +87 -22
  2. package/dist/acp/meta.js +12 -6
  3. package/dist/agents/agent-paths.js +8 -9
  4. package/dist/agents/agent-scope.js +7 -5
  5. package/dist/agents/auth-profiles/oauth.js +148 -64
  6. package/dist/agents/auth-profiles/session-override.js +13 -7
  7. package/dist/agents/bash-tools.exec-host-gateway.js +14 -4
  8. package/dist/agents/bash-tools.exec-runtime.js +2 -25
  9. package/dist/agents/bedrock-discovery.js +3 -1
  10. package/dist/agents/byteplus-models.js +97 -0
  11. package/dist/agents/chutes-oauth.js +1 -0
  12. package/dist/agents/cli-runner/helpers.js +4 -0
  13. package/dist/agents/compaction.js +41 -14
  14. package/dist/agents/doubao-models.js +121 -0
  15. package/dist/agents/failover-error.js +2 -0
  16. package/dist/agents/huggingface-models.js +5 -3
  17. package/dist/agents/live-model-filter.js +5 -0
  18. package/dist/agents/minimax-vlm.js +10 -8
  19. package/dist/agents/model-auth.js +6 -0
  20. package/dist/agents/model-catalog.js +3 -1
  21. package/dist/agents/model-selection.js +7 -1
  22. package/dist/agents/models-config.providers.js +93 -11
  23. package/dist/agents/ollama-stream.js +117 -4
  24. package/dist/agents/opencode-zen-models.js +22 -11
  25. package/dist/agents/pi-embedded-helpers/errors.js +55 -33
  26. package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
  27. package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
  28. package/dist/agents/pi-embedded-helpers.js +1 -1
  29. package/dist/agents/pi-embedded-runner/compact.js +29 -7
  30. package/dist/agents/pi-embedded-runner/extensions.js +28 -26
  31. package/dist/agents/pi-embedded-runner/google.js +20 -8
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
  33. package/dist/agents/pi-embedded-runner/run.js +71 -12
  34. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
  35. package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
  36. package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
  37. package/dist/agents/pi-embedded-runner/thinking.js +42 -0
  38. package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
  39. package/dist/agents/pi-embedded-runner/utils.js +7 -10
  40. package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
  41. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
  42. package/dist/agents/pi-embedded-subscribe.js +9 -4
  43. package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
  44. package/dist/agents/pi-embedded-utils.js +3 -0
  45. package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
  46. package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
  47. package/dist/agents/pi-settings.js +40 -0
  48. package/dist/agents/pi-tools.policy.js +2 -1
  49. package/dist/agents/provider/config-loader.js +1 -1
  50. package/dist/agents/sandbox/browser.js +170 -33
  51. package/dist/agents/sandbox/config-hash.js +14 -27
  52. package/dist/agents/sandbox/config.js +21 -2
  53. package/dist/agents/sandbox/constants.js +2 -0
  54. package/dist/agents/sandbox/docker.js +16 -2
  55. package/dist/agents/sandbox/novnc-auth.js +62 -0
  56. package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
  57. package/dist/agents/sandbox/shared.js +10 -6
  58. package/dist/agents/sandbox-paths.js +24 -11
  59. package/dist/agents/schema/clean-for-gemini.js +132 -85
  60. package/dist/agents/session-slug.js +10 -5
  61. package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
  62. package/dist/agents/session-tool-result-guard.js +3 -1
  63. package/dist/agents/session-transcript-repair.js +40 -6
  64. package/dist/agents/skills/bundled-dir.js +19 -5
  65. package/dist/agents/skills/env-overrides.js +124 -43
  66. package/dist/agents/skills/frontmatter.js +6 -6
  67. package/dist/agents/skills/plugin-skills.js +14 -7
  68. package/dist/agents/skills/workspace.js +1 -0
  69. package/dist/agents/subagent-announce.js +251 -49
  70. package/dist/agents/subagent-lifecycle-events.js +19 -0
  71. package/dist/agents/subagent-registry-cleanup.js +31 -0
  72. package/dist/agents/subagent-registry-completion.js +68 -0
  73. package/dist/agents/subagent-registry-queries.js +117 -0
  74. package/dist/agents/subagent-registry-state.js +46 -0
  75. package/dist/agents/subagent-registry.js +252 -221
  76. package/dist/agents/subagent-registry.store.js +1 -0
  77. package/dist/agents/subagent-registry.types.js +1 -0
  78. package/dist/agents/subagent-spawn.js +195 -7
  79. package/dist/agents/system-prompt.js +22 -6
  80. package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
  81. package/dist/agents/test-helpers/fast-core-tools.js +1 -17
  82. package/dist/agents/timeout.js +18 -6
  83. package/dist/agents/tool-call-id.js +1 -1
  84. package/dist/agents/tool-display-common.js +162 -29
  85. package/dist/agents/tool-images.js +82 -9
  86. package/dist/agents/tool-policy.js +51 -26
  87. package/dist/agents/tools/browser-tool.js +2 -2
  88. package/dist/agents/tools/canvas-tool.js +27 -1
  89. package/dist/agents/tools/common.js +45 -0
  90. package/dist/agents/tools/discord-actions-guild.js +4 -1
  91. package/dist/agents/tools/gateway-tool.js +3 -1
  92. package/dist/agents/tools/nodes-utils.js +1 -10
  93. package/dist/agents/tools/sessions-send-helpers.js +12 -6
  94. package/dist/agents/tools/sessions-spawn-tool.js +8 -2
  95. package/dist/agents/tools/subagents-tool.js +2 -1
  96. package/dist/agents/tools/whatsapp-actions.js +10 -2
  97. package/dist/agents/tools/whatsapp-target-auth.js +18 -0
  98. package/dist/agents/transcript-policy.js +22 -8
  99. package/dist/agents/venice-models.js +11 -3
  100. package/dist/auto-reply/commands-registry.data.js +51 -0
  101. package/dist/auto-reply/commands-registry.js +4 -3
  102. package/dist/auto-reply/group-activation.js +10 -5
  103. package/dist/auto-reply/inbound-debounce.js +10 -5
  104. package/dist/auto-reply/reply/abort.js +1 -1
  105. package/dist/auto-reply/reply/agent-runner-execution.js +4 -1
  106. package/dist/auto-reply/reply/bash-command.js +41 -39
  107. package/dist/auto-reply/reply/command-gates.js +25 -0
  108. package/dist/auto-reply/reply/commands-allowlist.js +111 -72
  109. package/dist/auto-reply/reply/commands-bash.js +6 -5
  110. package/dist/auto-reply/reply/commands-config.js +30 -28
  111. package/dist/auto-reply/reply/commands-core.js +2 -1
  112. package/dist/auto-reply/reply/commands-info.js +1 -0
  113. package/dist/auto-reply/reply/commands-models.js +65 -14
  114. package/dist/auto-reply/reply/commands-session.js +237 -82
  115. package/dist/auto-reply/reply/commands-setunset.js +45 -0
  116. package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
  117. package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
  118. package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
  119. package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
  120. package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
  121. package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
  122. package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
  123. package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
  124. package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
  125. package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
  126. package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
  127. package/dist/auto-reply/reply/commands-subagents.js +51 -587
  128. package/dist/auto-reply/reply/commands-tts.js +10 -5
  129. package/dist/auto-reply/reply/config-value.js +10 -5
  130. package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
  131. package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
  132. package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
  133. package/dist/auto-reply/reply/followup-runner.js +1 -0
  134. package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
  135. package/dist/auto-reply/reply/get-reply-directives.js +17 -28
  136. package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
  137. package/dist/auto-reply/reply/get-reply.js +71 -12
  138. package/dist/auto-reply/reply/model-selection.js +80 -39
  139. package/dist/auto-reply/reply/queue/enqueue.js +10 -5
  140. package/dist/auto-reply/reply/queue/state.js +13 -12
  141. package/dist/auto-reply/reply/reply-payloads.js +67 -36
  142. package/dist/auto-reply/reply/reply-reference.js +9 -8
  143. package/dist/auto-reply/reply/route-reply.js +15 -8
  144. package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
  145. package/dist/auto-reply/reply/session.js +22 -6
  146. package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
  147. package/dist/auto-reply/reply/subagents-utils.js +56 -30
  148. package/dist/auto-reply/reply/typing.js +46 -21
  149. package/dist/auto-reply/send-policy.js +14 -7
  150. package/dist/auto-reply/status.js +140 -16
  151. package/dist/auto-reply/templating.js +10 -5
  152. package/dist/auto-reply/thinking.js +7 -16
  153. package/dist/auto-reply/tokens.js +21 -5
  154. package/dist/browser/bridge-server.js +36 -20
  155. package/dist/browser/cdp.helpers.js +7 -14
  156. package/dist/browser/cdp.js +35 -15
  157. package/dist/browser/chrome.profile-decoration.js +7 -4
  158. package/dist/browser/config.js +4 -0
  159. package/dist/browser/extension-relay-auth.js +55 -0
  160. package/dist/browser/extension-relay.js +74 -29
  161. package/dist/browser/navigation-guard.js +9 -1
  162. package/dist/browser/paths.js +77 -0
  163. package/dist/browser/profiles.js +13 -8
  164. package/dist/browser/pw-ai-module.js +10 -5
  165. package/dist/browser/pw-session.js +76 -39
  166. package/dist/browser/pw-tools-core.interactions.js +14 -7
  167. package/dist/browser/pw-tools-core.state.js +12 -6
  168. package/dist/browser/routes/agent.act.js +2 -2
  169. package/dist/browser/server-context.js +7 -0
  170. package/dist/build-info.json +3 -3
  171. package/dist/channels/allow-from.js +2 -1
  172. package/dist/channels/allowlists/resolve-utils.js +43 -19
  173. package/dist/channels/channel-config.js +14 -7
  174. package/dist/channels/draft-stream-loop.js +7 -0
  175. package/dist/channels/model-overrides.js +82 -0
  176. package/dist/channels/plugins/normalize/imessage.js +14 -7
  177. package/dist/channels/plugins/normalize/slack.js +10 -5
  178. package/dist/channels/plugins/normalize/telegram.js +14 -7
  179. package/dist/channels/plugins/outbound/discord.js +80 -8
  180. package/dist/channels/plugins/outbound/signal.js +11 -11
  181. package/dist/channels/plugins/setup-helpers.js +10 -5
  182. package/dist/channels/sender-label.js +14 -7
  183. package/dist/channels/session.js +4 -2
  184. package/dist/channels/status-reactions.js +297 -0
  185. package/dist/cli/banner.js +1 -1
  186. package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
  187. package/dist/cli/cli-name.js +11 -11
  188. package/dist/cli/cli-utils.js +13 -3
  189. package/dist/cli/command-format.js +1 -1
  190. package/dist/cli/config-cli.js +1 -1
  191. package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
  192. package/dist/cli/daemon-cli/lifecycle.js +64 -2
  193. package/dist/cli/daemon-cli/restart-health.js +126 -0
  194. package/dist/cli/daemon-cli/status.gather.js +9 -13
  195. package/dist/cli/daemon-cli/status.print.js +2 -10
  196. package/dist/cli/deps.js +27 -22
  197. package/dist/cli/gateway-cli/run-loop.js +23 -5
  198. package/dist/cli/node-cli/register.js +14 -5
  199. package/dist/cli/nodes-media-utils.js +7 -2
  200. package/dist/cli/outbound-send-deps.js +2 -9
  201. package/dist/cli/outbound-send-mapping.js +11 -0
  202. package/dist/cli/pairing-cli.js +40 -14
  203. package/dist/cli/plugins-cli.js +34 -41
  204. package/dist/cli/ports.js +11 -10
  205. package/dist/cli/program/command-registry.js +2 -11
  206. package/dist/cli/program/command-tree.js +16 -0
  207. package/dist/cli/program/preaction.js +13 -9
  208. package/dist/cli/program/register.configure.js +3 -18
  209. package/dist/cli/program/register.maintenance.js +2 -2
  210. package/dist/cli/program/register.onboard.js +2 -0
  211. package/dist/cli/program/register.status-health-sessions.js +16 -17
  212. package/dist/cli/program/register.subclis.js +93 -52
  213. package/dist/cli/route.js +11 -7
  214. package/dist/cli/system-cli.js +36 -46
  215. package/dist/cli/update-cli/shared.js +22 -9
  216. package/dist/cli/update-cli/update-command.js +89 -14
  217. package/dist/cli/update-cli/wizard.js +6 -12
  218. package/dist/commands/agent/run-context.js +18 -5
  219. package/dist/commands/agent/session-store.js +17 -4
  220. package/dist/commands/agent.js +22 -2
  221. package/dist/commands/agents.bindings.js +14 -7
  222. package/dist/commands/agents.commands.add.js +13 -9
  223. package/dist/commands/agents.commands.identity.js +12 -6
  224. package/dist/commands/agents.commands.list.js +11 -6
  225. package/dist/commands/agents.config.js +8 -10
  226. package/dist/commands/agents.providers.js +12 -6
  227. package/dist/commands/auth-choice-options.js +103 -75
  228. package/dist/commands/auth-choice.apply.byteplus.js +55 -0
  229. package/dist/commands/auth-choice.apply.js +4 -0
  230. package/dist/commands/auth-choice.apply.minimax.js +61 -13
  231. package/dist/commands/auth-choice.apply.openai.js +3 -1
  232. package/dist/commands/auth-choice.apply.volcengine.js +55 -0
  233. package/dist/commands/auth-choice.preferred-provider.js +2 -0
  234. package/dist/commands/channels/remove.js +13 -6
  235. package/dist/commands/channels/shared.js +4 -14
  236. package/dist/commands/configure.commands.js +14 -0
  237. package/dist/commands/configure.gateway.js +2 -4
  238. package/dist/commands/configure.js +1 -1
  239. package/dist/commands/configure.shared.js +11 -0
  240. package/dist/commands/daemon-install-helpers.js +2 -2
  241. package/dist/commands/dashboard.js +12 -10
  242. package/dist/commands/docs.js +14 -8
  243. package/dist/commands/doctor-config-flow.js +11 -9
  244. package/dist/commands/doctor-legacy-config.js +281 -0
  245. package/dist/commands/doctor-state-integrity.js +99 -23
  246. package/dist/commands/doctor-update.js +12 -9
  247. package/dist/commands/models/list.list-command.js +7 -5
  248. package/dist/commands/models/set-image.js +2 -21
  249. package/dist/commands/node-daemon-install-helpers.js +10 -8
  250. package/dist/commands/onboard-auth.config-minimax.js +54 -80
  251. package/dist/commands/onboard-auth.config-opencode.js +2 -18
  252. package/dist/commands/onboard-auth.credentials.js +90 -13
  253. package/dist/commands/onboard-auth.js +1 -1
  254. package/dist/commands/onboard-auth.models.js +6 -5
  255. package/dist/commands/onboard-hooks.js +1 -1
  256. package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
  257. package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
  258. package/dist/commands/onboard-provider-auth-flags.js +14 -0
  259. package/dist/commands/onboard-remote.js +14 -7
  260. package/dist/commands/onboard.js +11 -13
  261. package/dist/commands/sandbox-display.js +6 -5
  262. package/dist/commands/status-all/diagnosis.js +14 -10
  263. package/dist/commands/status-all/format.js +1 -0
  264. package/dist/commands/status.gateway-probe.js +1 -16
  265. package/dist/commands/systemd-linger.js +12 -6
  266. package/dist/config/agent-limits.js +2 -0
  267. package/dist/config/commands.js +30 -16
  268. package/dist/config/config-paths.js +9 -11
  269. package/dist/config/defaults.js +22 -2
  270. package/dist/config/discord-preview-streaming.js +104 -0
  271. package/dist/config/env-vars.js +37 -8
  272. package/dist/config/includes.js +4 -0
  273. package/dist/config/io.js +97 -12
  274. package/dist/config/legacy.migrations.part-1.js +189 -78
  275. package/dist/config/legacy.shared.js +3 -1
  276. package/dist/config/merge-patch.js +4 -0
  277. package/dist/config/prototype-keys.js +4 -0
  278. package/dist/config/schema.help.js +44 -7
  279. package/dist/config/schema.labels.js +38 -6
  280. package/dist/config/sessions/delivery-info.js +10 -3
  281. package/dist/config/sessions/main-session.js +10 -5
  282. package/dist/config/sessions/session-file.js +33 -0
  283. package/dist/config/sessions/session-key.js +10 -5
  284. package/dist/config/sessions/store.js +1 -1
  285. package/dist/config/sessions.js +1 -0
  286. package/dist/config/zod-schema.agent-runtime.js +11 -0
  287. package/dist/config/zod-schema.js +148 -13
  288. package/dist/config/zod-schema.providers-core.js +78 -4
  289. package/dist/config/zod-schema.providers.js +6 -1
  290. package/dist/config/zod-schema.session.js +41 -2
  291. package/dist/cron/run-log.js +3 -0
  292. package/dist/cron/schedule.js +21 -10
  293. package/dist/cron/service/ops.js +35 -21
  294. package/dist/cron/service/timer.js +116 -16
  295. package/dist/cron/stagger.js +3 -1
  296. package/dist/discord/api.js +12 -6
  297. package/dist/discord/draft-chunking.js +22 -0
  298. package/dist/discord/draft-stream.js +124 -0
  299. package/dist/discord/monitor/agent-components.js +1 -1
  300. package/dist/discord/monitor/commands.js +5 -0
  301. package/dist/discord/monitor/gateway-plugin.js +2 -1
  302. package/dist/discord/monitor/listeners.js +37 -27
  303. package/dist/discord/monitor/message-handler.js +4 -1
  304. package/dist/discord/monitor/message-handler.preflight.js +65 -8
  305. package/dist/discord/monitor/message-handler.process.js +246 -217
  306. package/dist/discord/monitor/message-utils.js +143 -6
  307. package/dist/discord/monitor/model-picker-preferences.js +143 -0
  308. package/dist/discord/monitor/model-picker.js +651 -0
  309. package/dist/discord/monitor/native-command.js +573 -16
  310. package/dist/discord/monitor/provider.allowlist.js +223 -0
  311. package/dist/discord/monitor/provider.js +275 -347
  312. package/dist/discord/monitor/provider.lifecycle.js +100 -0
  313. package/dist/discord/monitor/reply-delivery.js +123 -16
  314. package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
  315. package/dist/discord/monitor/thread-bindings.js +4 -0
  316. package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
  317. package/dist/discord/monitor/thread-bindings.manager.js +423 -0
  318. package/dist/discord/monitor/thread-bindings.messages.js +55 -0
  319. package/dist/discord/monitor/thread-bindings.state.js +358 -0
  320. package/dist/discord/monitor/thread-bindings.types.js +6 -0
  321. package/dist/discord/resolve-users.js +33 -21
  322. package/dist/discord/send.channels.js +15 -0
  323. package/dist/discord/send.js +3 -2
  324. package/dist/discord/send.outbound.js +82 -26
  325. package/dist/discord/send.permissions.js +83 -30
  326. package/dist/discord/send.reactions.js +8 -4
  327. package/dist/discord/token.js +10 -5
  328. package/dist/discord/voice/command.js +263 -0
  329. package/dist/discord/voice/manager.js +531 -0
  330. package/dist/gateway/auth.js +34 -10
  331. package/dist/gateway/call.js +4 -16
  332. package/dist/gateway/client.js +28 -4
  333. package/dist/gateway/config-reload.js +3 -4
  334. package/dist/gateway/control-ui.js +219 -96
  335. package/dist/gateway/hooks-mapping.js +88 -38
  336. package/dist/gateway/http-auth-helpers.js +3 -2
  337. package/dist/gateway/http-endpoint-helpers.js +1 -0
  338. package/dist/gateway/net.js +54 -12
  339. package/dist/gateway/node-invoke-system-run-approval.js +14 -35
  340. package/dist/gateway/node-registry.js +10 -5
  341. package/dist/gateway/openai-http.js +1 -0
  342. package/dist/gateway/openresponses-http.js +1 -0
  343. package/dist/gateway/origin-check.js +1 -18
  344. package/dist/gateway/protocol/index.js +4 -3
  345. package/dist/gateway/protocol/schema/cron.js +1 -0
  346. package/dist/gateway/protocol/schema/devices.js +1 -0
  347. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -1
  348. package/dist/gateway/protocol/schema/sessions.js +6 -0
  349. package/dist/gateway/role-policy.js +17 -0
  350. package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
  351. package/dist/gateway/server/ws-connection/message-handler.js +175 -148
  352. package/dist/gateway/server-chat.js +83 -25
  353. package/dist/gateway/server-constants.js +10 -9
  354. package/dist/gateway/server-cron.js +1 -0
  355. package/dist/gateway/server-http.js +16 -7
  356. package/dist/gateway/server-maintenance.js +20 -5
  357. package/dist/gateway/server-methods/chat.js +10 -6
  358. package/dist/gateway/server-methods/config.js +12 -14
  359. package/dist/gateway/server-methods/devices.js +17 -3
  360. package/dist/gateway/server-methods/models.js +11 -1
  361. package/dist/gateway/server-methods/sessions.js +64 -8
  362. package/dist/gateway/server-methods/usage.js +162 -75
  363. package/dist/gateway/server-node-events.js +29 -0
  364. package/dist/gateway/server-runtime-config.js +34 -13
  365. package/dist/gateway/server-startup-memory.js +17 -11
  366. package/dist/gateway/session-utils.fs.js +32 -34
  367. package/dist/gateway/sessions-resolve.js +17 -5
  368. package/dist/gateway/test-helpers.openai-mock.js +14 -7
  369. package/dist/gateway/tools-invoke-http.js +21 -10
  370. package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
  371. package/dist/hooks/bundled/command-logger/handler.js +7 -2
  372. package/dist/hooks/bundled/session-memory/handler.js +6 -5
  373. package/dist/hooks/frontmatter.js +6 -6
  374. package/dist/hooks/gmail-watcher.js +11 -6
  375. package/dist/hooks/internal-hooks.js +11 -1
  376. package/dist/hooks/llm-slug-generator.js +4 -1
  377. package/dist/hooks/workspace.js +47 -17
  378. package/dist/imessage/accounts.js +9 -20
  379. package/dist/imessage/monitor/inbound-processing.js +2 -1
  380. package/dist/infra/archive.js +174 -73
  381. package/dist/infra/control-ui-assets.js +14 -6
  382. package/dist/infra/device-pairing.js +108 -29
  383. package/dist/infra/env.js +10 -5
  384. package/dist/infra/exec-approvals-allowlist.js +122 -0
  385. package/dist/infra/exec-approvals-analysis.js +34 -3
  386. package/dist/infra/exec-approvals.js +5 -17
  387. package/dist/infra/exec-safe-bin-policy.js +53 -45
  388. package/dist/infra/fs-safe.js +71 -39
  389. package/dist/infra/gateway-lock.js +6 -2
  390. package/dist/infra/heartbeat-wake.js +6 -12
  391. package/dist/infra/host-env-security-policy.json +19 -0
  392. package/dist/infra/host-env-security.js +66 -0
  393. package/dist/infra/net/ssrf.js +131 -38
  394. package/dist/infra/outbound/bound-delivery-router.js +88 -0
  395. package/dist/infra/outbound/channel-selection.js +12 -6
  396. package/dist/infra/outbound/envelope.js +1 -1
  397. package/dist/infra/outbound/format.js +12 -6
  398. package/dist/infra/outbound/payloads.js +14 -7
  399. package/dist/infra/outbound/session-binding-service.js +123 -0
  400. package/dist/infra/path-guards.js +25 -0
  401. package/dist/infra/provider-usage.fetch.codex.js +7 -15
  402. package/dist/infra/provider-usage.fetch.gemini.js +14 -11
  403. package/dist/infra/provider-usage.fetch.shared.js +30 -1
  404. package/dist/infra/provider-usage.fetch.zai.js +10 -9
  405. package/dist/infra/retry-policy.js +4 -2
  406. package/dist/infra/retry.js +9 -5
  407. package/dist/infra/session-cost-usage.js +107 -59
  408. package/dist/infra/session-maintenance-warning.js +3 -1
  409. package/dist/infra/shell-env.js +98 -34
  410. package/dist/infra/ssh-config.js +12 -6
  411. package/dist/infra/system-run-command.js +49 -4
  412. package/dist/infra/update-channels.js +10 -5
  413. package/dist/line/accounts.js +5 -7
  414. package/dist/line/bot-access.js +8 -20
  415. package/dist/line/bot-handlers.js +3 -1
  416. package/dist/link-understanding/detect.js +15 -7
  417. package/dist/media/constants.js +15 -6
  418. package/dist/media/image-ops.js +7 -0
  419. package/dist/media/local-roots.js +3 -2
  420. package/dist/media-understanding/apply.js +4 -1
  421. package/dist/media-understanding/concurrency.js +8 -20
  422. package/dist/memory/backend-config.js +45 -6
  423. package/dist/memory/embeddings.js +10 -4
  424. package/dist/memory/fs-utils.js +23 -0
  425. package/dist/memory/manager-search.js +12 -6
  426. package/dist/memory/manager-sync-ops.js +12 -2
  427. package/dist/memory/qmd-manager.js +466 -53
  428. package/dist/memory/query-expansion.js +167 -3
  429. package/dist/memory/status-format.js +10 -5
  430. package/dist/memory/sync-memory-files.js +1 -1
  431. package/dist/node-host/invoke-system-run.js +281 -0
  432. package/dist/node-host/invoke.js +55 -337
  433. package/dist/pairing/pairing-store.js +22 -0
  434. package/dist/plugin-sdk/allow-from.js +1 -1
  435. package/dist/plugin-sdk/command-auth.js +3 -1
  436. package/dist/plugin-sdk/index.js +6 -3
  437. package/dist/plugin-sdk/webhook-targets.js +32 -0
  438. package/dist/plugins/bundled-dir.js +9 -6
  439. package/dist/plugins/hooks.js +50 -0
  440. package/dist/plugins/install.js +28 -16
  441. package/dist/plugins/runtime.js +3 -17
  442. package/dist/plugins/update.js +78 -12
  443. package/dist/process/spawn-utils.js +14 -7
  444. package/dist/providers/github-copilot-token.js +11 -6
  445. package/dist/providers/qwen-portal-oauth.js +14 -6
  446. package/dist/routing/account-id.js +30 -0
  447. package/dist/routing/resolve-route.js +3 -7
  448. package/dist/routing/session-key.js +2 -16
  449. package/dist/security/audit-channel.js +93 -2
  450. package/dist/security/audit-extra.async.js +159 -5
  451. package/dist/security/audit-extra.js +1 -1
  452. package/dist/security/audit-extra.sync.js +85 -6
  453. package/dist/security/audit.js +40 -4
  454. package/dist/security/dm-policy-shared.js +44 -0
  455. package/dist/security/external-content.js +26 -6
  456. package/dist/shared/entry-status.js +6 -0
  457. package/dist/shared/frontmatter.js +5 -5
  458. package/dist/shared/node-match.js +11 -4
  459. package/dist/shared/operator-scope-compat.js +8 -3
  460. package/dist/signal/accounts.js +7 -20
  461. package/dist/signal/monitor/event-handler.js +3 -1
  462. package/dist/slack/accounts.js +6 -19
  463. package/dist/slack/actions.js +11 -3
  464. package/dist/slack/monitor/auth.js +1 -1
  465. package/dist/slack/monitor/message-handler/dispatch.js +50 -29
  466. package/dist/slack/monitor/replies.js +15 -7
  467. package/dist/slack/monitor/slash.js +22 -13
  468. package/dist/slack/resolve-channels.js +10 -5
  469. package/dist/slack/send.js +102 -12
  470. package/dist/slack/stream-mode.js +10 -0
  471. package/dist/slack/streaming.js +4 -2
  472. package/dist/telegram/accounts.js +19 -14
  473. package/dist/telegram/bot/helpers.js +3 -5
  474. package/dist/telegram/bot-access.js +35 -36
  475. package/dist/telegram/bot-handlers.js +120 -148
  476. package/dist/telegram/bot-message-context.js +68 -9
  477. package/dist/telegram/bot-message-dispatch.js +155 -90
  478. package/dist/telegram/bot-native-commands.js +16 -0
  479. package/dist/telegram/draft-stream.js +14 -1
  480. package/dist/telegram/inline-buttons.js +5 -15
  481. package/dist/telegram/monitor.js +11 -7
  482. package/dist/telegram/network-config.js +19 -7
  483. package/dist/telegram/send.js +3 -2
  484. package/dist/telegram/sent-message-cache.js +5 -6
  485. package/dist/telegram/status-reaction-variants.js +208 -0
  486. package/dist/telegram/sticker-cache.js +11 -9
  487. package/dist/terminal/theme.js +12 -12
  488. package/dist/tts/tts.js +80 -567
  489. package/dist/tui/components/chat-log.js +41 -8
  490. package/dist/tui/theme/theme.js +10 -12
  491. package/dist/tui/tui-local-shell.js +16 -6
  492. package/dist/tui/tui.js +58 -6
  493. package/dist/utils/account-id.js +2 -4
  494. package/dist/utils/boolean.js +10 -5
  495. package/dist/utils/directive-tags.js +11 -0
  496. package/dist/utils/queue-helpers.js +67 -12
  497. package/dist/web/auto-reply/deliver-reply.js +8 -4
  498. package/dist/web/auto-reply/mentions.js +10 -5
  499. package/dist/web/auto-reply/monitor/group-members.js +14 -7
  500. package/dist/web/auto-reply/monitor/process-message.js +45 -24
  501. package/dist/web/inbound/access-control.js +5 -2
  502. package/dist/web/login-qr.js +12 -6
  503. package/dist/web/media.js +123 -16
  504. package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
  505. package/extensions/bluebubbles/src/monitor.ts +208 -1950
  506. package/package.json +1 -1
@@ -1,7 +1,9 @@
1
1
  import crypto from "node:crypto";
2
2
  import { formatThinkingLevels, normalizeThinkLevel } from "../auto-reply/thinking.js";
3
+ import { DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH } from "../config/agent-limits.js";
3
4
  import { loadConfig } from "../config/config.js";
4
5
  import { callGateway } from "../gateway/call.js";
6
+ import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
5
7
  import { normalizeAgentId, parseAgentSessionKey } from "../routing/session-key.js";
6
8
  import { normalizeDeliveryContext } from "../utils/delivery-context.js";
7
9
  import { resolveAgentConfig } from "./agent-scope.js";
@@ -12,7 +14,9 @@ import { getSubagentDepthFromSessionStore } from "./subagent-depth.js";
12
14
  import { countActiveRunsForSession, registerSubagentRun } from "./subagent-registry.js";
13
15
  import { readStringParam } from "./tools/common.js";
14
16
  import { resolveDisplaySessionKey, resolveInternalSessionKey, resolveMainSessionAlias, } from "./tools/sessions-helpers.js";
15
- export const SUBAGENT_SPAWN_ACCEPTED_NOTE = "auto-announces on completion, do not poll/sleep. The response will be sent back as an agent message.";
17
+ export const SUBAGENT_SPAWN_MODES = ["run", "session"];
18
+ export const SUBAGENT_SPAWN_ACCEPTED_NOTE = "auto-announces on completion, do not poll/sleep. The response will be sent back as an user message.";
19
+ export const SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE = "thread-bound session stays active after this task; continue in-thread for follow-ups.";
16
20
  export function splitModelRef(ref) {
17
21
  if (!ref) {
18
22
  return { provider: undefined, model: undefined };
@@ -27,23 +31,99 @@ export function splitModelRef(ref) {
27
31
  }
28
32
  return { provider: undefined, model: trimmed };
29
33
  }
34
+ function resolveSpawnMode(params) {
35
+ if (params.requestedMode === "run" || params.requestedMode === "session") {
36
+ return params.requestedMode;
37
+ }
38
+ // Thread-bound spawns should default to persistent sessions.
39
+ return params.threadRequested ? "session" : "run";
40
+ }
41
+ function summarizeError(err) {
42
+ if (err instanceof Error) {
43
+ return err.message;
44
+ }
45
+ if (typeof err === "string") {
46
+ return err;
47
+ }
48
+ return "error";
49
+ }
50
+ async function ensureThreadBindingForSubagentSpawn(params) {
51
+ const hookRunner = params.hookRunner;
52
+ if (!hookRunner?.hasHooks("subagent_spawning")) {
53
+ return {
54
+ status: "error",
55
+ error: "thread=true is unavailable because no channel plugin registered subagent_spawning hooks.",
56
+ };
57
+ }
58
+ try {
59
+ const result = await hookRunner.runSubagentSpawning({
60
+ childSessionKey: params.childSessionKey,
61
+ agentId: params.agentId,
62
+ label: params.label,
63
+ mode: params.mode,
64
+ requester: params.requester,
65
+ threadRequested: true,
66
+ }, {
67
+ childSessionKey: params.childSessionKey,
68
+ requesterSessionKey: params.requesterSessionKey,
69
+ });
70
+ if (result?.status === "error") {
71
+ const error = result.error.trim();
72
+ return {
73
+ status: "error",
74
+ error: error || "Failed to prepare thread binding for this subagent session.",
75
+ };
76
+ }
77
+ if (result?.status !== "ok" || !result.threadBindingReady) {
78
+ return {
79
+ status: "error",
80
+ error: "Unable to create or bind a thread for this subagent session. Session mode is unavailable for this target.",
81
+ };
82
+ }
83
+ return { status: "ok" };
84
+ }
85
+ catch (err) {
86
+ return {
87
+ status: "error",
88
+ error: `Thread bind failed: ${summarizeError(err)}`,
89
+ };
90
+ }
91
+ }
30
92
  export async function spawnSubagentDirect(params, ctx) {
31
93
  const task = params.task;
32
94
  const label = params.label?.trim() || "";
33
95
  const requestedAgentId = params.agentId;
34
96
  const modelOverride = params.model;
35
97
  const thinkingOverrideRaw = params.thinking;
36
- const cleanup = params.cleanup === "keep" || params.cleanup === "delete" ? params.cleanup : "keep";
98
+ const requestThreadBinding = params.thread === true;
99
+ const spawnMode = resolveSpawnMode({
100
+ requestedMode: params.mode,
101
+ threadRequested: requestThreadBinding,
102
+ });
103
+ if (spawnMode === "session" && !requestThreadBinding) {
104
+ return {
105
+ status: "error",
106
+ error: 'mode="session" requires thread=true so the subagent can stay bound to a thread.',
107
+ };
108
+ }
109
+ const cleanup = spawnMode === "session"
110
+ ? "keep"
111
+ : params.cleanup === "keep" || params.cleanup === "delete"
112
+ ? params.cleanup
113
+ : "keep";
114
+ const expectsCompletionMessage = params.expectsCompletionMessage !== false;
37
115
  const requesterOrigin = normalizeDeliveryContext({
38
116
  channel: ctx.agentChannel,
39
117
  accountId: ctx.agentAccountId,
40
118
  to: ctx.agentTo,
41
119
  threadId: ctx.agentThreadId,
42
120
  });
121
+ const hookRunner = getGlobalHookRunner();
43
122
  const runTimeoutSeconds = typeof params.runTimeoutSeconds === "number" && Number.isFinite(params.runTimeoutSeconds)
44
123
  ? Math.max(0, Math.floor(params.runTimeoutSeconds))
45
124
  : 0;
46
125
  let modelApplied = false;
126
+ let threadBindingReady = false;
47
127
  const cfg = loadConfig();
48
128
  const { mainKey, alias } = resolveMainSessionAlias(cfg);
49
129
  const requesterSessionKey = ctx.agentSessionKey;
@@ -60,7 +140,7 @@ export async function spawnSubagentDirect(params, ctx) {
60
140
  mainKey,
61
141
  });
62
142
  const callerDepth = getSubagentDepthFromSessionStore(requesterInternalKey, { cfg });
63
- const maxSpawnDepth = cfg.agents?.defaults?.subagents?.maxSpawnDepth ?? 1;
143
+ const maxSpawnDepth = cfg.agents?.defaults?.subagents?.maxSpawnDepth ?? DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH;
64
144
  if (callerDepth >= maxSpawnDepth) {
65
145
  return {
66
146
  status: "forbidden",
@@ -170,6 +250,40 @@ export async function spawnSubagentDirect(params, ctx) {
170
250
  };
171
251
  }
172
252
  }
253
+ if (requestThreadBinding) {
254
+ const bindResult = await ensureThreadBindingForSubagentSpawn({
255
+ hookRunner,
256
+ childSessionKey,
257
+ agentId: targetAgentId,
258
+ label: label || undefined,
259
+ mode: spawnMode,
260
+ requesterSessionKey: requesterInternalKey,
261
+ requester: {
262
+ channel: requesterOrigin?.channel,
263
+ accountId: requesterOrigin?.accountId,
264
+ to: requesterOrigin?.to,
265
+ threadId: requesterOrigin?.threadId,
266
+ },
267
+ });
268
+ if (bindResult.status === "error") {
269
+ try {
270
+ await callGateway({
271
+ method: "sessions.delete",
272
+ params: { key: childSessionKey, emitLifecycleHooks: false },
273
+ timeoutMs: 10_000,
274
+ });
275
+ }
276
+ catch {
277
+ // Best-effort cleanup only.
278
+ }
279
+ return {
280
+ status: "error",
281
+ error: bindResult.error,
282
+ childSessionKey,
283
+ };
284
+ }
285
+ threadBindingReady = true;
286
+ }
173
287
  const childSystemPrompt = buildSubagentSystemPrompt({
174
288
  requesterSessionKey,
175
289
  requesterOrigin,
@@ -181,8 +295,13 @@ export async function spawnSubagentDirect(params, ctx) {
181
295
  });
182
296
  const childTaskMessage = [
183
297
  `[Subagent Context] You are running as a subagent (depth ${childDepth}/${maxSpawnDepth}). Results auto-announce to your requester; do not busy-poll for status.`,
298
+ spawnMode === "session"
299
+ ? "[Subagent Context] This subagent session is persistent and remains available for thread follow-up messages."
300
+ : undefined,
184
301
  `[Subagent Task]: ${task}`,
185
- ].join("\n\n");
302
+ ]
303
+ .filter((line) => Boolean(line))
304
+ .join("\n\n");
186
305
  const childIdem = crypto.randomUUID();
187
306
  let childRunId = childIdem;
188
307
  try {
@@ -214,7 +333,49 @@ export async function spawnSubagentDirect(params, ctx) {
214
333
  }
215
334
  }
216
335
  catch (err) {
217
- const messageText = err instanceof Error ? err.message : typeof err === "string" ? err : "error";
336
+ if (threadBindingReady) {
337
+ const hasEndedHook = hookRunner?.hasHooks("subagent_ended") === true;
338
+ let endedHookEmitted = false;
339
+ if (hasEndedHook) {
340
+ try {
341
+ await hookRunner?.runSubagentEnded({
342
+ targetSessionKey: childSessionKey,
343
+ targetKind: "subagent",
344
+ reason: "spawn-failed",
345
+ sendFarewell: true,
346
+ accountId: requesterOrigin?.accountId,
347
+ runId: childRunId,
348
+ outcome: "error",
349
+ error: "Session failed to start",
350
+ }, {
351
+ runId: childRunId,
352
+ childSessionKey,
353
+ requesterSessionKey: requesterInternalKey,
354
+ });
355
+ endedHookEmitted = true;
356
+ }
357
+ catch {
358
+ // Spawn should still return an actionable error even if cleanup hooks fail.
359
+ }
360
+ }
361
+ // Always delete the provisional child session after a failed spawn attempt.
362
+ // If we already emitted subagent_ended above, suppress a duplicate lifecycle hook.
363
+ try {
364
+ await callGateway({
365
+ method: "sessions.delete",
366
+ params: {
367
+ key: childSessionKey,
368
+ deleteTranscript: true,
369
+ emitLifecycleHooks: !endedHookEmitted,
370
+ },
371
+ timeoutMs: 10_000,
372
+ });
373
+ }
374
+ catch {
375
+ // Best-effort only.
376
+ }
377
+ }
378
+ const messageText = summarizeError(err);
218
379
  return {
219
380
  status: "error",
220
381
  error: messageText,
@@ -233,13 +394,40 @@ export async function spawnSubagentDirect(params, ctx) {
233
394
  label: label || undefined,
234
395
  model: resolvedModel,
235
396
  runTimeoutSeconds,
236
- expectsCompletionMessage: params.expectsCompletionMessage === true,
397
+ expectsCompletionMessage,
398
+ spawnMode,
237
399
  });
400
+ if (hookRunner?.hasHooks("subagent_spawned")) {
401
+ try {
402
+ await hookRunner.runSubagentSpawned({
403
+ runId: childRunId,
404
+ childSessionKey,
405
+ agentId: targetAgentId,
406
+ label: label || undefined,
407
+ requester: {
408
+ channel: requesterOrigin?.channel,
409
+ accountId: requesterOrigin?.accountId,
410
+ to: requesterOrigin?.to,
411
+ threadId: requesterOrigin?.threadId,
412
+ },
413
+ threadRequested: requestThreadBinding,
414
+ mode: spawnMode,
415
+ }, {
416
+ runId: childRunId,
417
+ childSessionKey,
418
+ requesterSessionKey: requesterInternalKey,
419
+ });
420
+ }
421
+ catch {
422
+ // Spawn should still return accepted if spawn lifecycle hooks fail.
423
+ }
424
+ }
238
425
  return {
239
426
  status: "accepted",
240
427
  childSessionKey,
241
428
  runId: childRunId,
242
- note: SUBAGENT_SPAWN_ACCEPTED_NOTE,
429
+ mode: spawnMode,
430
+ note: spawnMode === "session" ? SUBAGENT_SPAWN_SESSION_ACCEPTED_NOTE : SUBAGENT_SPAWN_ACCEPTED_NOTE,
243
431
  modelApplied: resolvedModel ? modelApplied : undefined,
244
432
  };
245
433
  }
@@ -1,3 +1,4 @@
1
+ import { createHmac, createHash } from "node:crypto";
1
2
  import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
2
3
  import { listDeliverableMessageChannels } from "../utils/message-channel.js";
3
4
  import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js";
@@ -44,7 +45,24 @@ function buildUserIdentitySection(ownerLine, isMinimal) {
44
45
  if (!ownerLine || isMinimal) {
45
46
  return [];
46
47
  }
47
- return ["## User Identity", ownerLine, ""];
48
+ return ["## Authorized Senders", ownerLine, ""];
49
+ }
50
+ function formatOwnerDisplayId(ownerId, ownerDisplaySecret) {
51
+ const hasSecret = ownerDisplaySecret?.trim();
52
+ const digest = hasSecret
53
+ ? createHmac("sha256", hasSecret).update(ownerId).digest("hex")
54
+ : createHash("sha256").update(ownerId).digest("hex");
55
+ return digest.slice(0, 12);
56
+ }
57
+ function buildOwnerIdentityLine(ownerNumbers, ownerDisplay, ownerDisplaySecret) {
58
+ const normalized = ownerNumbers.map((value) => value.trim()).filter(Boolean);
59
+ if (normalized.length === 0) {
60
+ return undefined;
61
+ }
62
+ const displayOwnerNumbers = ownerDisplay === "hash"
63
+ ? normalized.map((ownerId) => formatOwnerDisplayId(ownerId, ownerDisplaySecret))
64
+ : normalized;
65
+ return `Authorized senders: ${displayOwnerNumbers.join(", ")}. These senders are allowlisted; do not assume they are the owner.`;
48
66
  }
49
67
  function buildTimeSection(params) {
50
68
  if (!params.userTimezone) {
@@ -118,7 +136,7 @@ function buildDocsSection(params) {
118
136
  return [
119
137
  "## Documentation",
120
138
  `Pool Bot docs: ${docsPath}`,
121
- "Mirror: https://docs.poolbot.dev",
139
+ "Mirror: https://docs.molt.bot",
122
140
  "Source: https://github.com/poolbot/poolbot",
123
141
  "Community: https://discord.com/invite/clawd",
124
142
  "Find new skills: https://clawhub.com",
@@ -220,10 +238,8 @@ export function buildAgentSystemPrompt(params) {
220
238
  const execToolName = resolveToolName("exec");
221
239
  const processToolName = resolveToolName("process");
222
240
  const extraSystemPrompt = params.extraSystemPrompt?.trim();
223
- const ownerNumbers = (params.ownerNumbers ?? []).map((value) => value.trim()).filter(Boolean);
224
- const ownerLine = ownerNumbers.length > 0
225
- ? `Owner numbers: ${ownerNumbers.join(", ")}. Treat messages from these numbers as the user.`
226
- : undefined;
241
+ const ownerDisplay = params.ownerDisplay === "hash" ? "hash" : "raw";
242
+ const ownerLine = buildOwnerIdentityLine(params.ownerNumbers ?? [], ownerDisplay, params.ownerDisplaySecret);
227
243
  const reasoningHint = params.reasoningTagHint
228
244
  ? [
229
245
  "ALL internal reasoning MUST be inside <think>...</think>.",
@@ -1,18 +1 @@
1
- import { vi } from "vitest";
2
- const stubTool = (name) => ({
3
- name,
4
- description: `${name} stub`,
5
- parameters: { type: "object", properties: {} },
6
- execute: vi.fn(),
7
- });
8
- vi.mock("../tools/image-tool.js", () => ({
9
- createImageTool: () => stubTool("image"),
10
- }));
11
- vi.mock("../tools/web-tools.js", () => ({
12
- createWebSearchTool: () => null,
13
- createWebFetchTool: () => null,
14
- }));
15
- vi.mock("../../plugins/tools.js", () => ({
16
- resolvePluginTools: () => [],
17
- getPluginToolMeta: () => undefined,
18
- }));
1
+ import "./fast-tool-stubs.js";
@@ -1,24 +1,8 @@
1
1
  import { vi } from "vitest";
2
- const stubTool = (name) => ({
3
- name,
4
- description: `${name} stub`,
5
- parameters: { type: "object", properties: {} },
6
- execute: vi.fn(),
7
- });
2
+ import { stubTool } from "./fast-tool-stubs.js";
8
3
  vi.mock("../tools/browser-tool.js", () => ({
9
4
  createBrowserTool: () => stubTool("browser"),
10
5
  }));
11
6
  vi.mock("../tools/canvas-tool.js", () => ({
12
7
  createCanvasTool: () => stubTool("canvas"),
13
8
  }));
14
- vi.mock("../tools/image-tool.js", () => ({
15
- createImageTool: () => stubTool("image"),
16
- }));
17
- vi.mock("../tools/web-tools.js", () => ({
18
- createWebSearchTool: () => null,
19
- createWebFetchTool: () => null,
20
- }));
21
- vi.mock("../../plugins/tools.js", () => ({
22
- resolvePluginTools: () => [],
23
- getPluginToolMeta: () => undefined,
24
- }));
@@ -1,4 +1,5 @@
1
1
  const DEFAULT_AGENT_TIMEOUT_SECONDS = 600;
2
+ const MAX_SAFE_TIMEOUT_MS = 2_147_000_000;
2
3
  const normalizeNumber = (value) => typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : undefined;
3
4
  export function resolveAgentTimeoutSeconds(cfg) {
4
5
  const raw = normalizeNumber(cfg?.agents?.defaults?.timeoutSeconds);
@@ -7,18 +8,29 @@ export function resolveAgentTimeoutSeconds(cfg) {
7
8
  }
8
9
  export function resolveAgentTimeoutMs(opts) {
9
10
  const minMs = Math.max(normalizeNumber(opts.minMs) ?? 1, 1);
10
- const defaultMs = resolveAgentTimeoutSeconds(opts.cfg) * 1000;
11
+ const clampTimeoutMs = (valueMs) => Math.min(Math.max(valueMs, minMs), MAX_SAFE_TIMEOUT_MS);
12
+ const defaultMs = clampTimeoutMs(resolveAgentTimeoutSeconds(opts.cfg) * 1000);
13
+ // Use the maximum timer-safe timeout to represent "no timeout" when explicitly set to 0.
14
+ const NO_TIMEOUT_MS = MAX_SAFE_TIMEOUT_MS;
11
15
  const overrideMs = normalizeNumber(opts.overrideMs);
12
16
  if (overrideMs !== undefined) {
13
- if (overrideMs <= 0)
17
+ if (overrideMs === 0) {
18
+ return NO_TIMEOUT_MS;
19
+ }
20
+ if (overrideMs < 0) {
14
21
  return defaultMs;
15
- return Math.max(overrideMs, minMs);
22
+ }
23
+ return clampTimeoutMs(overrideMs);
16
24
  }
17
25
  const overrideSeconds = normalizeNumber(opts.overrideSeconds);
18
26
  if (overrideSeconds !== undefined) {
19
- if (overrideSeconds <= 0)
27
+ if (overrideSeconds === 0) {
28
+ return NO_TIMEOUT_MS;
29
+ }
30
+ if (overrideSeconds < 0) {
20
31
  return defaultMs;
21
- return Math.max(overrideSeconds * 1000, minMs);
32
+ }
33
+ return clampTimeoutMs(overrideSeconds * 1000);
22
34
  }
23
- return Math.max(defaultMs, minMs);
35
+ return defaultMs;
24
36
  }
@@ -73,7 +73,7 @@ export function isValidCloudCodeAssistToolId(id, mode = "strict") {
73
73
  return /^[a-zA-Z0-9]+$/.test(id);
74
74
  }
75
75
  function shortHash(text, length = 8) {
76
- return createHash("sha1").update(text).digest("hex").slice(0, length);
76
+ return createHash("sha256").update(text).digest("hex").slice(0, length);
77
77
  }
78
78
  function makeUniqueToolId(params) {
79
79
  if (params.mode === "strict9") {
@@ -411,20 +411,24 @@ function scanTopLevelChars(command, visit) {
411
411
  }
412
412
  }
413
413
  }
414
- function firstTopLevelStage(command) {
415
- let splitIndex = -1;
414
+ function splitTopLevelStages(command) {
415
+ const parts = [];
416
+ let start = 0;
416
417
  scanTopLevelChars(command, (char, index) => {
417
418
  if (char === ";") {
418
- splitIndex = index;
419
- return false;
419
+ parts.push(command.slice(start, index));
420
+ start = index + 1;
421
+ return true;
420
422
  }
421
423
  if ((char === "&" || char === "|") && command[index + 1] === char) {
422
- splitIndex = index;
423
- return false;
424
+ parts.push(command.slice(start, index));
425
+ start = index + 2;
426
+ return true;
424
427
  }
425
428
  return true;
426
429
  });
427
- return splitIndex >= 0 ? command.slice(0, splitIndex) : command;
430
+ parts.push(command.slice(start));
431
+ return parts.map((part) => part.trim()).filter((part) => part.length > 0);
428
432
  }
429
433
  function splitTopLevelPipes(command) {
430
434
  const parts = [];
@@ -439,31 +443,66 @@ function splitTopLevelPipes(command) {
439
443
  parts.push(command.slice(start));
440
444
  return parts.map((part) => part.trim()).filter((part) => part.length > 0);
441
445
  }
446
+ function parseChdirTarget(head) {
447
+ const words = splitShellWords(head, 3);
448
+ const bin = binaryName(words[0]);
449
+ if (bin === "cd" || bin === "pushd") {
450
+ return words[1] || undefined;
451
+ }
452
+ return undefined;
453
+ }
454
+ function isChdirCommand(head) {
455
+ const bin = binaryName(splitShellWords(head, 2)[0]);
456
+ return bin === "cd" || bin === "pushd" || bin === "popd";
457
+ }
458
+ function isPopdCommand(head) {
459
+ return binaryName(splitShellWords(head, 2)[0]) === "popd";
460
+ }
442
461
  function stripShellPreamble(command) {
443
462
  let rest = command.trim();
463
+ let chdirPath;
444
464
  for (let i = 0; i < 4; i += 1) {
445
- const andIndex = rest.indexOf("&&");
446
- const semicolonIndex = rest.indexOf(";");
447
- const newlineIndex = rest.indexOf("\n");
448
- const candidates = [
449
- { index: andIndex, length: 2 },
450
- { index: semicolonIndex, length: 1 },
451
- { index: newlineIndex, length: 1 },
452
- ]
453
- .filter((candidate) => candidate.index >= 0)
454
- .toSorted((a, b) => a.index - b.index);
455
- const first = candidates[0];
465
+ // Find the first top-level separator (&&, ||, ;, \n) respecting quotes/escaping.
466
+ let first;
467
+ scanTopLevelChars(rest, (char, idx) => {
468
+ if (char === "&" && rest[idx + 1] === "&") {
469
+ first = { index: idx, length: 2 };
470
+ return false;
471
+ }
472
+ if (char === "|" && rest[idx + 1] === "|") {
473
+ first = { index: idx, length: 2, isOr: true };
474
+ return false;
475
+ }
476
+ if (char === ";" || char === "\n") {
477
+ first = { index: idx, length: 1 };
478
+ return false;
479
+ }
480
+ });
456
481
  const head = (first ? rest.slice(0, first.index) : rest).trim();
457
- const isPreamble = head.startsWith("set ") || head.startsWith("export ") || head.startsWith("unset ");
482
+ // cd/pushd/popd is preamble when followed by && / ; / \n, or when we already
483
+ // stripped at least one preamble segment (handles chained cd's like `cd /tmp && cd /app`).
484
+ // NOT for || — `cd /app || npm install` means npm runs when cd *fails*, so (in /app) is wrong.
485
+ const isChdir = (first ? !first.isOr : i > 0) && isChdirCommand(head);
486
+ const isPreamble = head.startsWith("set ") || head.startsWith("export ") || head.startsWith("unset ") || isChdir;
458
487
  if (!isPreamble) {
459
488
  break;
460
489
  }
490
+ if (isChdir) {
491
+ // popd returns to the previous directory, so inferred cwd from earlier
492
+ // preamble steps is no longer reliable.
493
+ if (isPopdCommand(head)) {
494
+ chdirPath = undefined;
495
+ }
496
+ else {
497
+ chdirPath = parseChdirTarget(head) ?? chdirPath;
498
+ }
499
+ }
461
500
  rest = first ? rest.slice(first.index + first.length).trimStart() : "";
462
501
  if (!rest) {
463
502
  break;
464
503
  }
465
504
  }
466
- return rest.trim();
505
+ return { command: rest.trim(), chdirPath };
467
506
  }
468
507
  function summarizeKnownExec(words) {
469
508
  if (words.length === 0) {
@@ -696,12 +735,7 @@ function summarizeKnownExec(words) {
696
735
  }
697
736
  return /^[A-Za-z0-9._/-]+$/.test(arg) ? `run ${bin} ${arg}` : `run ${bin}`;
698
737
  }
699
- function summarizeExecCommand(command) {
700
- const cleaned = stripShellPreamble(command);
701
- const stage = firstTopLevelStage(cleaned).trim();
702
- if (!stage) {
703
- return cleaned ? summarizeKnownExec(trimLeadingEnv(splitShellWords(cleaned))) : undefined;
704
- }
738
+ function summarizePipeline(stage) {
705
739
  const pipeline = splitTopLevelPipes(stage);
706
740
  if (pipeline.length > 1) {
707
741
  const first = summarizeKnownExec(trimLeadingEnv(splitShellWords(pipeline[0])));
@@ -711,6 +745,92 @@ function summarizeExecCommand(command) {
711
745
  }
712
746
  return summarizeKnownExec(trimLeadingEnv(splitShellWords(stage)));
713
747
  }
748
+ function summarizeExecCommand(command) {
749
+ const { command: cleaned, chdirPath } = stripShellPreamble(command);
750
+ if (!cleaned) {
751
+ // All segments were preamble (e.g. `cd /tmp && cd /app`) — preserve chdirPath for context.
752
+ return chdirPath ? { text: "", chdirPath } : undefined;
753
+ }
754
+ const stages = splitTopLevelStages(cleaned);
755
+ if (stages.length === 0) {
756
+ return undefined;
757
+ }
758
+ const summaries = stages.map((stage) => summarizePipeline(stage));
759
+ const text = summaries.length === 1 ? summaries[0] : summaries.join(" → ");
760
+ const allGeneric = summaries.every((s) => isGenericSummary(s));
761
+ return { text, chdirPath, allGeneric };
762
+ }
763
+ /** Known summarizer prefixes that indicate a recognized command with useful context. */
764
+ const KNOWN_SUMMARY_PREFIXES = [
765
+ "check git",
766
+ "view git",
767
+ "show git",
768
+ "list git",
769
+ "switch git",
770
+ "create git",
771
+ "pull git",
772
+ "push git",
773
+ "fetch git",
774
+ "merge git",
775
+ "rebase git",
776
+ "stage git",
777
+ "restore git",
778
+ "reset git",
779
+ "stash git",
780
+ "search ",
781
+ "find files",
782
+ "list files",
783
+ "show first",
784
+ "show last",
785
+ "print line",
786
+ "print text",
787
+ "copy ",
788
+ "move ",
789
+ "remove ",
790
+ "create folder",
791
+ "create file",
792
+ "fetch http",
793
+ "install dependencies",
794
+ "run tests",
795
+ "run build",
796
+ "start app",
797
+ "run lint",
798
+ "run poolbot",
799
+ "run node script",
800
+ "run node ",
801
+ "run python",
802
+ "run ruby",
803
+ "run php",
804
+ "run sed",
805
+ "run git ",
806
+ "run npm ",
807
+ "run pnpm ",
808
+ "run yarn ",
809
+ "run bun ",
810
+ "check js syntax",
811
+ ];
812
+ /** True when the summary is generic and the raw command would be more informative. */
813
+ function isGenericSummary(summary) {
814
+ if (summary === "run command") {
815
+ return true;
816
+ }
817
+ // "run <binary>" or "run <binary> <arg>" without useful context
818
+ if (summary.startsWith("run ")) {
819
+ return !KNOWN_SUMMARY_PREFIXES.some((prefix) => summary.startsWith(prefix));
820
+ }
821
+ return false;
822
+ }
823
+ /** Compact the raw command for display: collapse whitespace, trim long strings. */
824
+ function compactRawCommand(raw, maxLength = 120) {
825
+ const oneLine = raw
826
+ .replace(/\s*\n\s*/g, " ")
827
+ .replace(/\s{2,}/g, " ")
828
+ .trim();
829
+ if (oneLine.length <= maxLength) {
830
+ return oneLine;
831
+ }
832
+ return `${oneLine.slice(0, Math.max(0, maxLength - 1))}…`;
833
+ }
714
834
  export function resolveExecDetail(args) {
715
835
  const record = asRecord(args);
716
836
  if (!record) {
@@ -721,14 +841,27 @@ export function resolveExecDetail(args) {
721
841
  return undefined;
722
842
  }
723
843
  const unwrapped = unwrapShellWrapper(raw);
724
- const summary = summarizeExecCommand(unwrapped) ?? summarizeExecCommand(raw) ?? "run command";
844
+ const result = summarizeExecCommand(unwrapped) ?? summarizeExecCommand(raw);
845
+ const summary = result?.text || "run command";
725
846
  const cwdRaw = typeof record.workdir === "string"
726
847
  ? record.workdir
727
848
  : typeof record.cwd === "string"
728
849
  ? record.cwd
729
850
  : undefined;
730
- const cwd = cwdRaw?.trim();
731
- return cwd ? `${summary} (in ${cwd})` : summary;
851
+ // Explicit workdir takes priority; fall back to cd path extracted from the command.
852
+ const cwd = cwdRaw?.trim() || result?.chdirPath || undefined;
853
+ const compact = compactRawCommand(unwrapped);
854
+ // When ALL stages are generic (e.g. "run jj"), use the compact raw command instead.
855
+ // For mixed stages like "run cargo build → run tests", keep the summary since some parts are useful.
856
+ if (result?.allGeneric !== false && isGenericSummary(summary)) {
857
+ return cwd ? `${compact} (in ${cwd})` : compact;
858
+ }
859
+ const displaySummary = cwd ? `${summary} (in ${cwd})` : summary;
860
+ // Append the raw command when the summary differs meaningfully from the command itself.
861
+ if (compact && compact !== displaySummary && compact !== summary) {
862
+ return `${displaySummary}\n\n\`${compact}\``;
863
+ }
864
+ return displaySummary;
732
865
  }
733
866
  export function resolveActionSpec(spec, action) {
734
867
  if (!spec || !action) {