@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
@@ -2,7 +2,9 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import readline from "node:readline";
4
4
  import { normalizeUsage } from "../agents/usage.js";
5
+ import { stripInboundMetadata } from "../auto-reply/reply/strip-inbound-meta.js";
5
6
  import { resolveSessionFilePath, resolveSessionTranscriptsDirForAgent, } from "../config/sessions/paths.js";
7
+ import { stripEnvelope, stripMessageIdHints } from "../shared/chat-envelope.js";
6
8
  import { countToolResults, extractToolCallNames } from "../utils/transcript-tools.js";
7
9
  import { estimateUsageCost, resolveModelCostConfig } from "../utils/usage-format.js";
8
10
  const emptyTotals = () => ({
@@ -105,7 +107,7 @@ const computeLatencyStats = (values) => {
105
107
  if (!values.length) {
106
108
  return undefined;
107
109
  }
108
- const sorted = [...values].sort((a, b) => a - b);
110
+ const sorted = values.toSorted((a, b) => a - b);
109
111
  const total = sorted.reduce((sum, v) => sum + v, 0);
110
112
  const count = sorted.length;
111
113
  const p95Index = Math.max(0, Math.ceil(count * 0.95) - 1);
@@ -144,33 +146,47 @@ const applyCostTotal = (totals, costTotal) => {
144
146
  }
145
147
  totals.totalCost += costTotal;
146
148
  };
147
- async function scanTranscriptFile(params) {
148
- const fileStream = fs.createReadStream(params.filePath, { encoding: "utf-8" });
149
+ async function* readJsonlRecords(filePath) {
150
+ const fileStream = fs.createReadStream(filePath, { encoding: "utf-8" });
149
151
  const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity });
150
- for await (const line of rl) {
151
- const trimmed = line.trim();
152
- if (!trimmed) {
153
- continue;
154
- }
155
- try {
156
- const parsed = JSON.parse(trimmed);
157
- const entry = parseTranscriptEntry(parsed);
158
- if (!entry) {
152
+ try {
153
+ for await (const line of rl) {
154
+ const trimmed = line.trim();
155
+ if (!trimmed) {
159
156
  continue;
160
157
  }
161
- if (entry.usage && entry.costTotal === undefined) {
162
- const cost = resolveModelCostConfig({
163
- provider: entry.provider,
164
- model: entry.model,
165
- config: params.config,
166
- });
167
- entry.costTotal = estimateUsageCost({ usage: entry.usage, cost });
158
+ try {
159
+ const parsed = JSON.parse(trimmed);
160
+ if (!parsed || typeof parsed !== "object") {
161
+ continue;
162
+ }
163
+ yield parsed;
164
+ }
165
+ catch {
166
+ // Ignore malformed lines
168
167
  }
169
- params.onEntry(entry);
170
168
  }
171
- catch {
172
- // Ignore malformed lines
169
+ }
170
+ finally {
171
+ rl.close();
172
+ fileStream.destroy();
173
+ }
174
+ }
175
+ async function scanTranscriptFile(params) {
176
+ for await (const parsed of readJsonlRecords(params.filePath)) {
177
+ const entry = parseTranscriptEntry(parsed);
178
+ if (!entry) {
179
+ continue;
173
180
  }
181
+ if (entry.usage && entry.costTotal === undefined) {
182
+ const cost = resolveModelCostConfig({
183
+ provider: entry.provider,
184
+ model: entry.model,
185
+ config: params.config,
186
+ });
187
+ entry.costTotal = estimateUsageCost({ usage: entry.usage, cost });
188
+ }
189
+ params.onEntry(entry);
174
190
  }
175
191
  }
176
192
  async function scanUsageFile(params) {
@@ -257,7 +273,7 @@ export async function loadCostUsageSummary(params) {
257
273
  }
258
274
  const daily = Array.from(dailyMap.entries())
259
275
  .map(([date, bucket]) => Object.assign({ date }, bucket))
260
- .sort((a, b) => a.date.localeCompare(b.date));
276
+ .toSorted((a, b) => a.date.localeCompare(b.date));
261
277
  // Calculate days for backwards compatibility in response
262
278
  const days = Math.ceil((untilTime - sinceTime) / (24 * 60 * 60 * 1000)) + 1;
263
279
  return {
@@ -294,15 +310,8 @@ export async function discoverAllSessions(params) {
294
310
  // Try to read first user message for label extraction
295
311
  let firstUserMessage;
296
312
  try {
297
- const fileStream = fs.createReadStream(filePath, { encoding: "utf-8" });
298
- const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity });
299
- for await (const line of rl) {
300
- const trimmed = line.trim();
301
- if (!trimmed) {
302
- continue;
303
- }
313
+ for await (const parsed of readJsonlRecords(filePath)) {
304
314
  try {
305
- const parsed = JSON.parse(trimmed);
306
315
  const message = parsed.message;
307
316
  if (message?.role === "user") {
308
317
  const content = message.content;
@@ -329,8 +338,6 @@ export async function discoverAllSessions(params) {
329
338
  // Skip malformed lines
330
339
  }
331
340
  }
332
- rl.close();
333
- fileStream.destroy();
334
341
  }
335
342
  catch {
336
343
  // Ignore read errors
@@ -343,11 +350,15 @@ export async function discoverAllSessions(params) {
343
350
  });
344
351
  }
345
352
  // Sort by mtime descending (most recent first)
346
- return discovered.sort((a, b) => b.mtime - a.mtime);
353
+ return discovered.toSorted((a, b) => b.mtime - a.mtime);
347
354
  }
348
355
  export async function loadSessionCostSummary(params) {
349
356
  const sessionFile = params.sessionFile ??
350
- (params.sessionId ? resolveSessionFilePath(params.sessionId, params.sessionEntry) : undefined);
357
+ (params.sessionId
358
+ ? resolveSessionFilePath(params.sessionId, params.sessionEntry, {
359
+ agentId: params.agentId,
360
+ })
361
+ : undefined);
351
362
  if (!sessionFile || !fs.existsSync(sessionFile)) {
352
363
  return null;
353
364
  }
@@ -527,8 +538,8 @@ export async function loadSessionCostSummary(params) {
527
538
  // Convert daily map to sorted array
528
539
  const dailyBreakdown = Array.from(dailyMap.entries())
529
540
  .map(([date, data]) => ({ date, tokens: data.tokens, cost: data.cost }))
530
- .sort((a, b) => a.date.localeCompare(b.date));
531
- const dailyMessageCounts = Array.from(dailyMessageMap.values()).sort((a, b) => a.date.localeCompare(b.date));
541
+ .toSorted((a, b) => a.date.localeCompare(b.date));
542
+ const dailyMessageCounts = Array.from(dailyMessageMap.values()).toSorted((a, b) => a.date.localeCompare(b.date));
532
543
  const dailyLatency = Array.from(dailyLatencyMap.entries())
533
544
  .map(([date, values]) => {
534
545
  const stats = computeLatencyStats(values);
@@ -538,19 +549,19 @@ export async function loadSessionCostSummary(params) {
538
549
  return { date, ...stats };
539
550
  })
540
551
  .filter((entry) => Boolean(entry))
541
- .sort((a, b) => a.date.localeCompare(b.date));
542
- const dailyModelUsage = Array.from(dailyModelUsageMap.values()).sort((a, b) => a.date.localeCompare(b.date) || b.cost - a.cost);
552
+ .toSorted((a, b) => a.date.localeCompare(b.date));
553
+ const dailyModelUsage = Array.from(dailyModelUsageMap.values()).toSorted((a, b) => a.date.localeCompare(b.date) || b.cost - a.cost);
543
554
  const toolUsage = toolUsageMap.size
544
555
  ? {
545
556
  totalCalls: Array.from(toolUsageMap.values()).reduce((sum, count) => sum + count, 0),
546
557
  uniqueTools: toolUsageMap.size,
547
558
  tools: Array.from(toolUsageMap.entries())
548
559
  .map(([name, count]) => ({ name, count }))
549
- .sort((a, b) => b.count - a.count),
560
+ .toSorted((a, b) => b.count - a.count),
550
561
  }
551
562
  : undefined;
552
563
  const modelUsage = modelUsageMap.size
553
- ? Array.from(modelUsageMap.values()).sort((a, b) => {
564
+ ? Array.from(modelUsageMap.values()).toSorted((a, b) => {
554
565
  const costDiff = b.totals.totalCost - a.totals.totalCost;
555
566
  if (costDiff !== 0) {
556
567
  return costDiff;
@@ -566,7 +577,7 @@ export async function loadSessionCostSummary(params) {
566
577
  durationMs: firstActivity !== undefined && lastActivity !== undefined
567
578
  ? Math.max(0, lastActivity - firstActivity)
568
579
  : undefined,
569
- activityDates: Array.from(activityDatesSet).sort(),
580
+ activityDates: Array.from(activityDatesSet).toSorted(),
570
581
  dailyBreakdown,
571
582
  dailyMessageCounts,
572
583
  dailyLatency: dailyLatency.length ? dailyLatency : undefined,
@@ -580,7 +591,11 @@ export async function loadSessionCostSummary(params) {
580
591
  }
581
592
  export async function loadSessionUsageTimeSeries(params) {
582
593
  const sessionFile = params.sessionFile ??
583
- (params.sessionId ? resolveSessionFilePath(params.sessionId, params.sessionEntry) : undefined);
594
+ (params.sessionId
595
+ ? resolveSessionFilePath(params.sessionId, params.sessionEntry, {
596
+ agentId: params.agentId,
597
+ })
598
+ : undefined);
584
599
  if (!sessionFile || !fs.existsSync(sessionFile)) {
585
600
  return null;
586
601
  }
@@ -617,18 +632,47 @@ export async function loadSessionUsageTimeSeries(params) {
617
632
  },
618
633
  });
619
634
  // Sort by timestamp
620
- const sortedPoints = points.sort((a, b) => a.timestamp - b.timestamp);
635
+ const sortedPoints = points.toSorted((a, b) => a.timestamp - b.timestamp);
621
636
  // Optionally downsample if too many points
622
637
  const maxPoints = params.maxPoints ?? 100;
623
638
  if (sortedPoints.length > maxPoints) {
624
639
  const step = Math.ceil(sortedPoints.length / maxPoints);
625
640
  const downsampled = [];
641
+ let downsampledCumulativeTokens = 0;
642
+ let downsampledCumulativeCost = 0;
626
643
  for (let i = 0; i < sortedPoints.length; i += step) {
627
- downsampled.push(sortedPoints[i]);
628
- }
629
- // Always include the last point
630
- if (downsampled[downsampled.length - 1] !== sortedPoints[sortedPoints.length - 1]) {
631
- downsampled.push(sortedPoints[sortedPoints.length - 1]);
644
+ const bucket = sortedPoints.slice(i, i + step);
645
+ const bucketLast = bucket[bucket.length - 1];
646
+ if (!bucketLast) {
647
+ continue;
648
+ }
649
+ let bucketInput = 0;
650
+ let bucketOutput = 0;
651
+ let bucketCacheRead = 0;
652
+ let bucketCacheWrite = 0;
653
+ let bucketTotalTokens = 0;
654
+ let bucketCost = 0;
655
+ for (const point of bucket) {
656
+ bucketInput += point.input;
657
+ bucketOutput += point.output;
658
+ bucketCacheRead += point.cacheRead;
659
+ bucketCacheWrite += point.cacheWrite;
660
+ bucketTotalTokens += point.totalTokens;
661
+ bucketCost += point.cost;
662
+ }
663
+ downsampledCumulativeTokens += bucketTotalTokens;
664
+ downsampledCumulativeCost += bucketCost;
665
+ downsampled.push({
666
+ timestamp: bucketLast.timestamp,
667
+ input: bucketInput,
668
+ output: bucketOutput,
669
+ cacheRead: bucketCacheRead,
670
+ cacheWrite: bucketCacheWrite,
671
+ totalTokens: bucketTotalTokens,
672
+ cost: bucketCost,
673
+ cumulativeTokens: downsampledCumulativeTokens,
674
+ cumulativeCost: downsampledCumulativeCost,
675
+ });
632
676
  }
633
677
  return { sessionId: params.sessionId, points: downsampled };
634
678
  }
@@ -636,21 +680,18 @@ export async function loadSessionUsageTimeSeries(params) {
636
680
  }
637
681
  export async function loadSessionLogs(params) {
638
682
  const sessionFile = params.sessionFile ??
639
- (params.sessionId ? resolveSessionFilePath(params.sessionId, params.sessionEntry) : undefined);
683
+ (params.sessionId
684
+ ? resolveSessionFilePath(params.sessionId, params.sessionEntry, {
685
+ agentId: params.agentId,
686
+ })
687
+ : undefined);
640
688
  if (!sessionFile || !fs.existsSync(sessionFile)) {
641
689
  return null;
642
690
  }
643
691
  const logs = [];
644
692
  const limit = params.limit ?? 50;
645
- const fileStream = fs.createReadStream(sessionFile, { encoding: "utf-8" });
646
- const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity });
647
- for await (const line of rl) {
648
- const trimmed = line.trim();
649
- if (!trimmed) {
650
- continue;
651
- }
693
+ for await (const parsed of readJsonlRecords(sessionFile)) {
652
694
  try {
653
- const parsed = JSON.parse(trimmed);
654
695
  const message = parsed.message;
655
696
  if (!message) {
656
697
  continue;
@@ -718,6 +759,13 @@ export async function loadSessionLogs(params) {
718
759
  if (!content) {
719
760
  continue;
720
761
  }
762
+ content = stripInboundMetadata(content);
763
+ if (role === "user") {
764
+ content = stripMessageIdHints(stripEnvelope(content)).trim();
765
+ }
766
+ if (!content) {
767
+ continue;
768
+ }
721
769
  // Truncate very long content
722
770
  const maxLen = 2000;
723
771
  if (content.length > maxLen) {
@@ -771,7 +819,7 @@ export async function loadSessionLogs(params) {
771
819
  }
772
820
  }
773
821
  // Sort by timestamp and limit
774
- const sortedLogs = logs.sort((a, b) => a.timestamp - b.timestamp);
822
+ const sortedLogs = logs.toSorted((a, b) => a.timestamp - b.timestamp);
775
823
  // Return most recent logs
776
824
  if (sortedLogs.length > limit) {
777
825
  return sortedLogs.slice(-limit);
@@ -1,7 +1,9 @@
1
1
  import { resolveSessionAgentId } from "../agents/agent-scope.js";
2
+ import { createSubsystemLogger } from "../logging/subsystem.js";
2
3
  import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
3
4
  import { resolveSessionDeliveryTarget } from "./outbound/targets.js";
4
5
  import { enqueueSystemEvent } from "./system-events.js";
6
+ const log = createSubsystemLogger("session-maintenance");
5
7
  const warnedContexts = new Map();
6
8
  function shouldSendWarning() {
7
9
  return !process.env.VITEST && process.env.NODE_ENV !== "test";
@@ -83,7 +85,7 @@ export async function deliverSessionMaintenanceWarning(params) {
83
85
  });
84
86
  }
85
87
  catch (err) {
86
- console.warn(`Failed to deliver session maintenance warning: ${String(err)}`);
88
+ log.warn(`Failed to deliver session maintenance warning: ${String(err)}`);
87
89
  enqueueSystemEvent(text, { sessionKey: params.sessionKey });
88
90
  }
89
91
  }
@@ -1,26 +1,100 @@
1
1
  import { execFileSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
2
4
  import { isTruthyEnvValue } from "./env.js";
3
5
  const DEFAULT_TIMEOUT_MS = 15_000;
4
6
  const DEFAULT_MAX_BUFFER_BYTES = 2 * 1024 * 1024;
7
+ const DEFAULT_SHELL = "/bin/sh";
8
+ const TRUSTED_SHELL_PREFIXES = [
9
+ "/bin/",
10
+ "/usr/bin/",
11
+ "/usr/local/bin/",
12
+ "/opt/homebrew/bin/",
13
+ "/run/current-system/sw/bin/",
14
+ ];
5
15
  let lastAppliedKeys = [];
6
16
  let cachedShellPath;
17
+ let cachedEtcShells;
18
+ function resolveTimeoutMs(timeoutMs) {
19
+ if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs)) {
20
+ return DEFAULT_TIMEOUT_MS;
21
+ }
22
+ return Math.max(0, timeoutMs);
23
+ }
24
+ function readEtcShells() {
25
+ if (cachedEtcShells !== undefined) {
26
+ return cachedEtcShells;
27
+ }
28
+ try {
29
+ const raw = fs.readFileSync("/etc/shells", "utf8");
30
+ const entries = raw
31
+ .split(/\r?\n/)
32
+ .map((line) => line.trim())
33
+ .filter((line) => line.length > 0 && !line.startsWith("#") && path.isAbsolute(line));
34
+ cachedEtcShells = new Set(entries);
35
+ }
36
+ catch {
37
+ cachedEtcShells = null;
38
+ }
39
+ return cachedEtcShells;
40
+ }
41
+ function isTrustedShellPath(shell) {
42
+ if (!path.isAbsolute(shell)) {
43
+ return false;
44
+ }
45
+ const normalized = path.normalize(shell);
46
+ if (normalized !== shell) {
47
+ return false;
48
+ }
49
+ // Primary trust anchor: shell registered in /etc/shells.
50
+ const registeredShells = readEtcShells();
51
+ if (registeredShells?.has(shell)) {
52
+ return true;
53
+ }
54
+ // Fallback for environments where /etc/shells is incomplete/unavailable.
55
+ if (!TRUSTED_SHELL_PREFIXES.some((prefix) => shell.startsWith(prefix))) {
56
+ return false;
57
+ }
58
+ try {
59
+ fs.accessSync(shell, fs.constants.X_OK);
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
7
66
  function resolveShell(env) {
8
67
  const shell = env.SHELL?.trim();
9
- return shell && shell.length > 0 ? shell : "/bin/sh";
68
+ if (shell && isTrustedShellPath(shell)) {
69
+ return shell;
70
+ }
71
+ return DEFAULT_SHELL;
72
+ }
73
+ function execLoginShellEnvZero(params) {
74
+ return params.exec(params.shell, ["-l", "-c", "env -0"], {
75
+ encoding: "buffer",
76
+ timeout: params.timeoutMs,
77
+ maxBuffer: DEFAULT_MAX_BUFFER_BYTES,
78
+ env: params.env,
79
+ stdio: ["ignore", "pipe", "pipe"],
80
+ });
10
81
  }
11
82
  function parseShellEnv(stdout) {
12
83
  const shellEnv = new Map();
13
84
  const parts = stdout.toString("utf8").split("\0");
14
85
  for (const part of parts) {
15
- if (!part)
86
+ if (!part) {
16
87
  continue;
88
+ }
17
89
  const eq = part.indexOf("=");
18
- if (eq <= 0)
90
+ if (eq <= 0) {
19
91
  continue;
92
+ }
20
93
  const key = part.slice(0, eq);
21
94
  const value = part.slice(eq + 1);
22
- if (!key)
95
+ if (!key) {
23
96
  continue;
97
+ }
24
98
  shellEnv.set(key, value);
25
99
  }
26
100
  return shellEnv;
@@ -37,19 +111,11 @@ export function loadShellEnvFallback(opts) {
37
111
  lastAppliedKeys = [];
38
112
  return { ok: true, applied: [], skippedReason: "already-has-keys" };
39
113
  }
40
- const timeoutMs = typeof opts.timeoutMs === "number" && Number.isFinite(opts.timeoutMs)
41
- ? Math.max(0, opts.timeoutMs)
42
- : DEFAULT_TIMEOUT_MS;
114
+ const timeoutMs = resolveTimeoutMs(opts.timeoutMs);
43
115
  const shell = resolveShell(opts.env);
44
116
  let stdout;
45
117
  try {
46
- stdout = exec(shell, ["-l", "-c", "env -0"], {
47
- encoding: "buffer",
48
- timeout: timeoutMs,
49
- maxBuffer: DEFAULT_MAX_BUFFER_BYTES,
50
- env: opts.env,
51
- stdio: ["ignore", "pipe", "pipe"],
52
- });
118
+ stdout = execLoginShellEnvZero({ shell, env: opts.env, exec, timeoutMs });
53
119
  }
54
120
  catch (err) {
55
121
  const msg = err instanceof Error ? err.message : String(err);
@@ -60,11 +126,13 @@ export function loadShellEnvFallback(opts) {
60
126
  const shellEnv = parseShellEnv(stdout);
61
127
  const applied = [];
62
128
  for (const key of opts.expectedKeys) {
63
- if (opts.env[key]?.trim())
129
+ if (opts.env[key]?.trim()) {
64
130
  continue;
131
+ }
65
132
  const value = shellEnv.get(key);
66
- if (!value?.trim())
133
+ if (!value?.trim()) {
67
134
  continue;
135
+ }
68
136
  opts.env[key] = value;
69
137
  applied.push(key);
70
138
  }
@@ -72,42 +140,37 @@ export function loadShellEnvFallback(opts) {
72
140
  return { ok: true, applied };
73
141
  }
74
142
  export function shouldEnableShellEnvFallback(env) {
75
- return (isTruthyEnvValue(env.POOLBOT_LOAD_SHELL_ENV) || isTruthyEnvValue(env.CLAWDBOT_LOAD_SHELL_ENV));
143
+ return isTruthyEnvValue(env.POOLBOT_LOAD_SHELL_ENV);
76
144
  }
77
145
  export function shouldDeferShellEnvFallback(env) {
78
- return (isTruthyEnvValue(env.POOLBOT_DEFER_SHELL_ENV_FALLBACK) ||
79
- isTruthyEnvValue(env.CLAWDBOT_DEFER_SHELL_ENV_FALLBACK));
146
+ return isTruthyEnvValue(env.POOLBOT_DEFER_SHELL_ENV_FALLBACK);
80
147
  }
81
148
  export function resolveShellEnvFallbackTimeoutMs(env) {
82
- const raw = env.POOLBOT_SHELL_ENV_TIMEOUT_MS?.trim() || env.CLAWDBOT_SHELL_ENV_TIMEOUT_MS?.trim();
83
- if (!raw)
149
+ const raw = env.POOLBOT_SHELL_ENV_TIMEOUT_MS?.trim();
150
+ if (!raw) {
84
151
  return DEFAULT_TIMEOUT_MS;
152
+ }
85
153
  const parsed = Number.parseInt(raw, 10);
86
- if (!Number.isFinite(parsed))
154
+ if (!Number.isFinite(parsed)) {
87
155
  return DEFAULT_TIMEOUT_MS;
156
+ }
88
157
  return Math.max(0, parsed);
89
158
  }
90
159
  export function getShellPathFromLoginShell(opts) {
91
- if (cachedShellPath !== undefined)
160
+ if (cachedShellPath !== undefined) {
92
161
  return cachedShellPath;
93
- if (process.platform === "win32") {
162
+ }
163
+ const platform = opts.platform ?? process.platform;
164
+ if (platform === "win32") {
94
165
  cachedShellPath = null;
95
166
  return cachedShellPath;
96
167
  }
97
168
  const exec = opts.exec ?? execFileSync;
98
- const timeoutMs = typeof opts.timeoutMs === "number" && Number.isFinite(opts.timeoutMs)
99
- ? Math.max(0, opts.timeoutMs)
100
- : DEFAULT_TIMEOUT_MS;
169
+ const timeoutMs = resolveTimeoutMs(opts.timeoutMs);
101
170
  const shell = resolveShell(opts.env);
102
171
  let stdout;
103
172
  try {
104
- stdout = exec(shell, ["-l", "-c", "env -0"], {
105
- encoding: "buffer",
106
- timeout: timeoutMs,
107
- maxBuffer: DEFAULT_MAX_BUFFER_BYTES,
108
- env: opts.env,
109
- stdio: ["ignore", "pipe", "pipe"],
110
- });
173
+ stdout = execLoginShellEnvZero({ shell, env: opts.env, exec, timeoutMs });
111
174
  }
112
175
  catch {
113
176
  cachedShellPath = null;
@@ -120,6 +183,7 @@ export function getShellPathFromLoginShell(opts) {
120
183
  }
121
184
  export function resetShellPathCacheForTests() {
122
185
  cachedShellPath = undefined;
186
+ cachedEtcShells = undefined;
123
187
  }
124
188
  export function getShellEnvAppliedKeys() {
125
189
  return [...lastAppliedKeys];
@@ -1,10 +1,12 @@
1
1
  import { spawn } from "node:child_process";
2
2
  function parsePort(value) {
3
- if (!value)
3
+ if (!value) {
4
4
  return undefined;
5
+ }
5
6
  const parsed = Number.parseInt(value, 10);
6
- if (!Number.isFinite(parsed) || parsed <= 0)
7
+ if (!Number.isFinite(parsed) || parsed <= 0) {
7
8
  return undefined;
9
+ }
8
10
  return parsed;
9
11
  }
10
12
  export function parseSshConfigOutput(output) {
@@ -12,12 +14,14 @@ export function parseSshConfigOutput(output) {
12
14
  const lines = output.split("\n");
13
15
  for (const raw of lines) {
14
16
  const line = raw.trim();
15
- if (!line)
17
+ if (!line) {
16
18
  continue;
19
+ }
17
20
  const [key, ...rest] = line.split(/\s+/);
18
21
  const value = rest.join(" ").trim();
19
- if (!key || !value)
22
+ if (!key || !value) {
20
23
  continue;
24
+ }
21
25
  switch (key) {
22
26
  case "user":
23
27
  result.user = value;
@@ -29,8 +33,9 @@ export function parseSshConfigOutput(output) {
29
33
  result.port = parsePort(value);
30
34
  break;
31
35
  case "identityfile":
32
- if (value !== "none")
36
+ if (value !== "none") {
33
37
  result.identityFiles.push(value);
38
+ }
34
39
  break;
35
40
  default:
36
41
  break;
@@ -48,7 +53,8 @@ export async function resolveSshConfig(target, opts = {}) {
48
53
  args.push("-i", opts.identity.trim());
49
54
  }
50
55
  const userHost = target.user ? `${target.user}@${target.host}` : target.host;
51
- args.push(userHost);
56
+ // Use "--" so userHost can't be parsed as an ssh option.
57
+ args.push("--", userHost);
52
58
  return await new Promise((resolve) => {
53
59
  const child = spawn(sshPath, args, {
54
60
  stdio: ["ignore", "pipe", "ignore"],
@@ -45,8 +45,12 @@ export function extractShellCommandFromArgv(argv) {
45
45
  if (idx === -1) {
46
46
  return null;
47
47
  }
48
- const cmd = argv[idx + 1];
49
- return typeof cmd === "string" ? cmd : null;
48
+ const tail = argv.slice(idx + 1).map((item) => String(item));
49
+ if (tail.length === 0) {
50
+ return null;
51
+ }
52
+ const cmd = tail.join(" ").trim();
53
+ return cmd.length > 0 ? cmd : null;
50
54
  }
51
55
  return null;
52
56
  }
@@ -55,7 +59,7 @@ export function validateSystemRunCommandConsistency(params) {
55
59
  ? params.rawCommand.trim()
56
60
  : null;
57
61
  const shellCommand = extractShellCommandFromArgv(params.argv);
58
- const inferred = shellCommand ? shellCommand.trim() : formatExecCommand(params.argv);
62
+ const inferred = shellCommand !== null ? shellCommand.trim() : formatExecCommand(params.argv);
59
63
  if (raw && raw !== inferred) {
60
64
  return {
61
65
  ok: false,
@@ -72,7 +76,48 @@ export function validateSystemRunCommandConsistency(params) {
72
76
  // Only treat this as a shell command when argv is a recognized shell wrapper.
73
77
  // For direct argv execution, rawCommand is purely display/approval text and
74
78
  // must match the formatted argv.
75
- shellCommand: shellCommand ? (raw ?? shellCommand) : null,
79
+ shellCommand: shellCommand !== null ? (raw ?? shellCommand) : null,
76
80
  cmdText: raw ?? shellCommand ?? inferred,
77
81
  };
78
82
  }
83
+ export function resolveSystemRunCommand(params) {
84
+ const raw = typeof params.rawCommand === "string" && params.rawCommand.trim().length > 0
85
+ ? params.rawCommand.trim()
86
+ : null;
87
+ const command = Array.isArray(params.command) ? params.command : [];
88
+ if (command.length === 0) {
89
+ if (raw) {
90
+ return {
91
+ ok: false,
92
+ message: "rawCommand requires params.command",
93
+ details: { code: "MISSING_COMMAND" },
94
+ };
95
+ }
96
+ return {
97
+ ok: true,
98
+ argv: [],
99
+ rawCommand: null,
100
+ shellCommand: null,
101
+ cmdText: "",
102
+ };
103
+ }
104
+ const argv = command.map((v) => String(v));
105
+ const validation = validateSystemRunCommandConsistency({
106
+ argv,
107
+ rawCommand: raw,
108
+ });
109
+ if (!validation.ok) {
110
+ return {
111
+ ok: false,
112
+ message: validation.message,
113
+ details: validation.details ?? { code: "RAW_COMMAND_MISMATCH" },
114
+ };
115
+ }
116
+ return {
117
+ ok: true,
118
+ argv,
119
+ rawCommand: raw,
120
+ shellCommand: validation.shellCommand,
121
+ cmdText: validation.cmdText,
122
+ };
123
+ }