@poolzin/pool-bot 2026.3.25 → 2026.3.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 (271) hide show
  1. package/dist/agents/model-fallback.js +5 -4
  2. package/dist/agents/tools/common.js +16 -201
  3. package/dist/auto-reply/auto-reply/reply/agent-runner-execution.js +502 -0
  4. package/dist/auto-reply/auto-reply/reply/agent-runner-helpers.js +65 -0
  5. package/dist/auto-reply/auto-reply/reply/agent-runner-memory.js +160 -0
  6. package/dist/auto-reply/auto-reply/reply/agent-runner-payloads.js +85 -0
  7. package/dist/auto-reply/auto-reply/reply/agent-runner-utils.js +101 -0
  8. package/dist/auto-reply/auto-reply/reply/bash-command.js +338 -0
  9. package/dist/auto-reply/auto-reply/reply/block-streaming.js +91 -0
  10. package/dist/auto-reply/auto-reply/reply/commands-approve.js +88 -0
  11. package/dist/auto-reply/auto-reply/reply/commands-bash.js +26 -0
  12. package/dist/auto-reply/auto-reply/reply/commands-compact.js +107 -0
  13. package/dist/auto-reply/auto-reply/reply/commands-config.js +241 -0
  14. package/dist/auto-reply/auto-reply/reply/commands-context-report.js +295 -0
  15. package/dist/auto-reply/auto-reply/reply/commands-context.js +30 -0
  16. package/dist/auto-reply/auto-reply/reply/commands-core.js +151 -0
  17. package/dist/auto-reply/auto-reply/reply/commands-export-session.js +163 -0
  18. package/dist/auto-reply/auto-reply/reply/commands-info.js +184 -0
  19. package/dist/auto-reply/auto-reply/reply/commands-models.js +299 -0
  20. package/dist/auto-reply/auto-reply/reply/commands-plugin.js +35 -0
  21. package/dist/auto-reply/auto-reply/reply/commands-ptt.js +171 -0
  22. package/dist/auto-reply/auto-reply/reply/commands-setunset-standard.js +13 -0
  23. package/dist/auto-reply/auto-reply/reply/commands-setunset.js +73 -0
  24. package/dist/auto-reply/auto-reply/reply/commands-slash-parse.js +31 -0
  25. package/dist/auto-reply/auto-reply/reply/commands-status.js +178 -0
  26. package/dist/auto-reply/auto-reply/reply/commands-subagents.js +73 -0
  27. package/dist/auto-reply/auto-reply/reply/commands-system-prompt.js +117 -0
  28. package/dist/auto-reply/auto-reply/reply/commands-tts.js +231 -0
  29. package/dist/auto-reply/auto-reply/reply/directive-handling.impl.js +380 -0
  30. package/dist/auto-reply/auto-reply/reply/followup-runner.js +227 -0
  31. package/dist/auto-reply/auto-reply/reply/get-reply-directives-apply.js +201 -0
  32. package/dist/auto-reply/auto-reply/reply/get-reply-directives-utils.js +54 -0
  33. package/dist/auto-reply/auto-reply/reply/get-reply-directives.js +332 -0
  34. package/dist/auto-reply/auto-reply/reply/get-reply-inline-actions.js +258 -0
  35. package/dist/auto-reply/auto-reply/reply/get-reply-run.js +297 -0
  36. package/dist/auto-reply/auto-reply/reply/groups.js +102 -0
  37. package/dist/auto-reply/auto-reply/reply/mentions.js +129 -0
  38. package/dist/auto-reply/auto-reply/reply/reply-delivery.js +92 -0
  39. package/dist/auto-reply/auto-reply/reply/reply-directives.js +30 -0
  40. package/dist/auto-reply/auto-reply/reply/reply-dispatcher.js +152 -0
  41. package/dist/auto-reply/auto-reply/reply/reply-elevated.js +166 -0
  42. package/dist/auto-reply/auto-reply/reply/reply-inline.js +28 -0
  43. package/dist/auto-reply/auto-reply/reply/reply-payloads.js +114 -0
  44. package/dist/auto-reply/auto-reply/reply/reply-reference.js +36 -0
  45. package/dist/auto-reply/auto-reply/reply/reply-tags.js +13 -0
  46. package/dist/auto-reply/auto-reply/reply/reply-threading.js +41 -0
  47. package/dist/auto-reply/auto-reply/reply/session-updates.js +233 -0
  48. package/dist/auto-reply/auto-reply/reply/stage-sandbox-media.js +146 -0
  49. package/dist/build-info.json +3 -3
  50. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  51. package/dist/canvas-host/a2ui/a2ui.bundle.js +2 -17772
  52. package/dist/canvas-host/a2ui/index.html +1 -307
  53. package/dist/channels/channels/directory-config.js +185 -0
  54. package/dist/channels/channels/discord/handle-action.guild-admin.js +332 -0
  55. package/dist/channels/channels/discord/handle-action.js +165 -0
  56. package/dist/channels/channels/discord.js +413 -0
  57. package/dist/channels/channels/dock.js +436 -0
  58. package/dist/channels/channels/index.js +51 -0
  59. package/dist/channels/channels/plugins/outbound/discord.js +101 -0
  60. package/dist/channels/channels/whatsapp.js +17 -0
  61. package/dist/channels/plugins/types.js +1 -1
  62. package/dist/channels/run-state-machine.js +7 -0
  63. package/dist/commands/models/auth.js +47 -1
  64. package/dist/commands-subagents/action-agents.js +44 -0
  65. package/dist/commands-subagents/action-focus.js +64 -0
  66. package/dist/commands-subagents/action-help.js +4 -0
  67. package/dist/commands-subagents/action-info.js +45 -0
  68. package/dist/commands-subagents/action-kill.js +60 -0
  69. package/dist/commands-subagents/action-list.js +44 -0
  70. package/dist/commands-subagents/action-log.js +29 -0
  71. package/dist/commands-subagents/action-send.js +119 -0
  72. package/dist/commands-subagents/action-spawn.js +52 -0
  73. package/dist/commands-subagents/action-unfocus.js +30 -0
  74. package/dist/commands-subagents/shared.js +303 -0
  75. package/dist/config/config.js +1 -8
  76. package/dist/config/types.secrets.js +61 -0
  77. package/dist/control-ui/assets/{index-D7shnQwQ.js → index-umCsvrWy.js} +884 -741
  78. package/dist/control-ui/assets/index-umCsvrWy.js.map +1 -0
  79. package/dist/control-ui/assets/pt-BR-DedEVAvY.js +2 -0
  80. package/dist/control-ui/assets/pt-BR-DedEVAvY.js.map +1 -0
  81. package/dist/control-ui/assets/zh-CN-CDzeklK-.js +2 -0
  82. package/dist/control-ui/assets/zh-CN-CDzeklK-.js.map +1 -0
  83. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js +2 -0
  84. package/dist/control-ui/assets/zh-TW-BJCRYNWH.js.map +1 -0
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/gateway/method-scopes.js +9 -1
  87. package/dist/gateway/node-pending-work.js +142 -0
  88. package/dist/gateway/protocol/index.js +5 -1
  89. package/dist/gateway/protocol/schema/nodes.js +18 -0
  90. package/dist/gateway/server-methods/nodes-pending.js +96 -0
  91. package/dist/gateway/server-methods-list.js +4 -0
  92. package/dist/gateway/server-methods.js +2 -0
  93. package/dist/imessage/channel.js +253 -0
  94. package/dist/imessage/monitor/echo-cache.js +70 -0
  95. package/dist/imessage/monitor/loop-rate-limiter.js +51 -0
  96. package/dist/imessage/monitor/reflection-guard.js +50 -0
  97. package/dist/imessage/monitor/sanitize-outbound.js +25 -0
  98. package/dist/imessage/monitor/self-chat-cache.js +75 -0
  99. package/dist/imessage/runtime.js +3 -0
  100. package/dist/infra/exec-approval-reply.js +7 -0
  101. package/dist/infra/tmp-openclaw-dir.js +84 -0
  102. package/dist/pairing/pairing-challenge.js +15 -0
  103. package/dist/plugin-sdk/account-id.d.ts +1 -0
  104. package/dist/plugin-sdk/agent-media-payload.d.ts +12 -0
  105. package/dist/plugin-sdk/allow-from.d.ts +27 -0
  106. package/dist/plugin-sdk/command-auth.d.ts +25 -0
  107. package/dist/plugin-sdk/command-auth.js +3 -1
  108. package/dist/plugin-sdk/config-paths.d.ts +6 -0
  109. package/dist/plugin-sdk/file-lock.d.ts +16 -0
  110. package/dist/plugin-sdk/index.d.ts +428 -0
  111. package/dist/plugin-sdk/index.js +237 -103
  112. package/dist/plugin-sdk/json-store.d.ts +5 -0
  113. package/dist/plugin-sdk/keyed-async-queue.d.ts +12 -0
  114. package/dist/plugin-sdk/onboarding.d.ts +11 -0
  115. package/dist/plugin-sdk/provider-auth-result.d.ts +14 -0
  116. package/dist/plugin-sdk/slack-message-actions.d.ts +11 -0
  117. package/dist/plugin-sdk/status-helpers.d.ts +25 -0
  118. package/dist/plugin-sdk/temp-path.d.ts +12 -0
  119. package/dist/plugin-sdk/text-chunking.d.ts +1 -0
  120. package/dist/plugin-sdk/tool-send.d.ts +4 -0
  121. package/dist/plugin-sdk/webhook-path.d.ts +6 -0
  122. package/dist/plugin-sdk/webhook-targets.d.ts +23 -0
  123. package/dist/plugin-sdk/windows-spawn.d.ts +39 -0
  124. package/dist/plugin-sdk-internal/accounts.js +6 -0
  125. package/dist/plugin-sdk-internal/discord.js +23 -0
  126. package/dist/plugin-sdk-internal/imessage.js +13 -0
  127. package/dist/plugin-sdk-internal/setup.js +9 -0
  128. package/dist/plugin-sdk-internal/signal.js +13 -0
  129. package/dist/plugin-sdk-internal/slack.js +22 -0
  130. package/dist/plugin-sdk-internal/telegram.js +32 -0
  131. package/dist/plugin-sdk-internal/whatsapp.js +29 -0
  132. package/dist/routing/session-key.js +4 -185
  133. package/dist/shared/pid-alive.js +2 -61
  134. package/dist/shared/process-scoped-map.js +5 -7
  135. package/dist/signal/channel.js +264 -0
  136. package/dist/signal/monitor/access-policy.js +60 -0
  137. package/dist/signal/runtime.js +3 -0
  138. package/dist/slack/account-inspect.js +135 -0
  139. package/dist/slack/blocks-input.js +7 -38
  140. package/dist/slack/channel.js +394 -0
  141. package/dist/slack/interactive-replies.js +28 -0
  142. package/dist/slack/monitor/channel-type.js +31 -0
  143. package/dist/slack/monitor/dm-auth.js +49 -0
  144. package/dist/slack/monitor/events/interactions.modal.js +137 -0
  145. package/dist/slack/monitor/events/message-subtype-handlers.js +68 -0
  146. package/dist/slack/monitor/events/system-event-context.js +29 -0
  147. package/dist/slack/monitor/events/system-event-test-harness.js +41 -0
  148. package/dist/slack/monitor/external-arg-menu-store.js +46 -0
  149. package/dist/slack/monitor/message-handler/prepare-content.js +69 -0
  150. package/dist/slack/monitor/message-handler/prepare-thread-context.js +91 -0
  151. package/dist/slack/monitor/message-handler/prepare.test-helpers.js +55 -0
  152. package/dist/slack/monitor/reconnect-policy.js +78 -0
  153. package/dist/slack/monitor/slash-commands.runtime.js +1 -0
  154. package/dist/slack/monitor/slash-dispatch.runtime.js +9 -0
  155. package/dist/slack/monitor/slash-skill-commands.runtime.js +1 -0
  156. package/dist/slack/resolve-allowlist-common.js +36 -0
  157. package/dist/slack/runtime.js +3 -0
  158. package/dist/slack/sent-thread-cache.js +61 -0
  159. package/dist/slack/truncate.js +10 -0
  160. package/dist/telegram/account-inspect.js +175 -0
  161. package/dist/telegram/allow-from.js +10 -0
  162. package/dist/telegram/api-fetch.js +18 -0
  163. package/dist/telegram/approval-buttons.js +30 -0
  164. package/dist/telegram/audit-membership-runtime.js +61 -0
  165. package/dist/telegram/bot/delivery.replies.js +508 -0
  166. package/dist/telegram/bot/delivery.resolve-media.js +227 -0
  167. package/dist/telegram/bot/delivery.send.js +132 -0
  168. package/dist/telegram/bot/reply-threading.js +46 -0
  169. package/dist/telegram/bot-message-context.body.js +186 -0
  170. package/dist/telegram/bot-message-context.session.js +207 -0
  171. package/dist/telegram/bot-message-context.types.js +1 -0
  172. package/dist/telegram/bot-native-commands.test-helpers.js +117 -0
  173. package/dist/telegram/bot.media.e2e-harness.js +81 -0
  174. package/dist/telegram/bot.media.test-utils.js +81 -0
  175. package/dist/telegram/channel-actions.js +225 -0
  176. package/dist/telegram/channel.js +515 -0
  177. package/dist/telegram/conversation-route.js +107 -0
  178. package/dist/telegram/delivery.js +2 -0
  179. package/dist/telegram/delivery.replies.js +508 -0
  180. package/dist/telegram/dm-access.js +86 -0
  181. package/dist/telegram/draft-stream.test-helpers.js +62 -0
  182. package/dist/telegram/exec-approvals-handler.js +281 -0
  183. package/dist/telegram/exec-approvals.js +62 -0
  184. package/dist/telegram/forum-service-message.js +22 -0
  185. package/dist/telegram/group-config-helpers.js +10 -0
  186. package/dist/telegram/lane-delivery-state.js +19 -0
  187. package/dist/telegram/lane-delivery-text-deliverer.js +357 -0
  188. package/dist/telegram/lane-delivery.js +2 -0
  189. package/dist/telegram/normalize.js +37 -0
  190. package/dist/telegram/onboarding.js +192 -0
  191. package/dist/telegram/outbound-adapter.js +100 -0
  192. package/dist/telegram/polling-session.js +275 -0
  193. package/dist/telegram/runtime.js +3 -0
  194. package/dist/telegram/sendchataction-401-backoff.js +71 -0
  195. package/dist/telegram/sequential-key.js +46 -0
  196. package/dist/telegram/status-issues.js +105 -0
  197. package/dist/telegram/target-writeback.js +165 -0
  198. package/dist/telegram/thread-bindings.js +560 -0
  199. package/dist/utils.js +10 -276
  200. package/dist/wizard/prompts.js +5 -5
  201. package/extensions/feishu/src/policy.ts +1 -1
  202. package/extensions/firecrawl/index.test.ts +82 -0
  203. package/extensions/firecrawl/index.ts +20 -0
  204. package/extensions/firecrawl/openclaw.plugin.json +8 -0
  205. package/extensions/firecrawl/package.json +12 -0
  206. package/extensions/firecrawl/src/config.ts +159 -0
  207. package/extensions/firecrawl/src/firecrawl-client.ts +446 -0
  208. package/extensions/firecrawl/src/firecrawl-scrape-tool.ts +89 -0
  209. package/extensions/firecrawl/src/firecrawl-search-provider.ts +63 -0
  210. package/extensions/firecrawl/src/firecrawl-search-tool.ts +76 -0
  211. package/package.json +1 -1
  212. package/dist/.buildstamp +0 -1
  213. package/dist/acp/bindings-store.js +0 -209
  214. package/dist/acp/control-plane/runtime-cache.js +0 -54
  215. package/dist/acp/control-plane/runtime-options.js +0 -215
  216. package/dist/acp/control-plane/session-actor-queue.js +0 -36
  217. package/dist/acp/index.js +0 -2
  218. package/dist/acp/runtime/errors.js +0 -47
  219. package/dist/acp/runtime/registry.js +0 -86
  220. package/dist/acp/secret-file.js +0 -22
  221. package/dist/agents/auth-profiles.resolve-auth-profile-order.fixtures.js +0 -23
  222. package/dist/agents/bash-process-registry.test-helpers.js +0 -29
  223. package/dist/agents/bash-tools.exec-approval-request.js +0 -20
  224. package/dist/agents/bash-tools.exec-host-gateway.js +0 -240
  225. package/dist/agents/bash-tools.exec-host-node.js +0 -235
  226. package/dist/agents/checkpoint-manager.js +0 -290
  227. package/dist/agents/claude-cli-runner.js +0 -3
  228. package/dist/agents/error-classifier.js +0 -251
  229. package/dist/agents/live-model-filter.js +0 -84
  230. package/dist/agents/nvidia-models.js +0 -228
  231. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +0 -34
  232. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +0 -156
  233. package/dist/agents/pi-embedded-subscribe.handlers.tools.media.test-helpers.js +0 -30
  234. package/dist/agents/provider/config-loader.js +0 -76
  235. package/dist/agents/provider/index.js +0 -15
  236. package/dist/agents/provider/models-dev.js +0 -129
  237. package/dist/agents/provider/session-binding.js +0 -376
  238. package/dist/agents/queued-file-writer.js +0 -22
  239. package/dist/agents/skills/bundled-context.js +0 -23
  240. package/dist/agents/skills/security.js +0 -211
  241. package/dist/agents/skills/tools-dir.js +0 -9
  242. package/dist/agents/skills-install-download.js +0 -290
  243. package/dist/agents/skills-install-output.js +0 -30
  244. package/dist/agents/skills-install.download-test-utils.js +0 -36
  245. package/dist/agents/skills.test-helpers.js +0 -13
  246. package/dist/agents/subagent-announce-reliability.js +0 -160
  247. package/dist/agents/subagent-registry.mocks.shared.js +0 -12
  248. package/dist/agents/test-helpers/assistant-message-fixtures.js +0 -29
  249. package/dist/agents/test-helpers/fast-coding-tools.js +0 -1
  250. package/dist/agents/test-helpers/fast-core-tools.js +0 -8
  251. package/dist/agents/test-helpers/fast-tool-stubs.js +0 -18
  252. package/dist/agents/test-helpers/host-sandbox-fs-bridge.js +0 -74
  253. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +0 -27
  254. package/dist/agents/tool-display-common.js +0 -915
  255. package/dist/agents/tool-policy-shared.js +0 -108
  256. package/dist/agents/tool-policy.conformance.js +0 -14
  257. package/dist/agents/tool-result-truncation.js +0 -299
  258. package/dist/agents/tools/cron-tool.test-helpers.js +0 -12
  259. package/dist/agents/tools/discord-actions-moderation-shared.js +0 -27
  260. package/dist/agents/tools/discord-actions-presence.js +0 -78
  261. package/dist/control-ui/assets/index-D7shnQwQ.js.map +0 -1
  262. package/dist/discord/discord-improvements.js +0 -167
  263. package/dist/discord/index.js +0 -2
  264. package/dist/hooks/bundled/boot-md/HOOK.md +0 -19
  265. package/dist/hooks/bundled/command-logger/HOOK.md +0 -122
  266. package/dist/hooks/bundled/session-memory/HOOK.md +0 -86
  267. package/dist/hooks/bundled/soul-evil/HOOK.md +0 -71
  268. package/dist/whatsapp/normalize.js +0 -66
  269. package/dist/whatsapp/resolve-outbound-target.js +0 -42
  270. /package/dist/{acp/runtime/types.js → auto-reply/auto-reply/reply/commands-types.js} +0 -0
  271. /package/dist/{agents/pi-embedded-payloads.js → slack/account-surface-fields.js} +0 -0
@@ -0,0 +1,233 @@
1
+ import crypto from "node:crypto";
2
+ import { resolveUserTimezone } from "../../agents/date-time.js";
3
+ import { buildWorkspaceSkillSnapshot } from "../../agents/skills.js";
4
+ import { ensureSkillsWatcher, getSkillsSnapshotVersion } from "../../agents/skills/refresh.js";
5
+ import { updateSessionStore } from "../../config/sessions.js";
6
+ import { buildChannelSummary } from "../../infra/channel-summary.js";
7
+ import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
8
+ import { drainSystemEventEntries } from "../../infra/system-events.js";
9
+ export async function prependSystemEvents(params) {
10
+ const compactSystemEvent = (line) => {
11
+ const trimmed = line.trim();
12
+ if (!trimmed)
13
+ return null;
14
+ const lower = trimmed.toLowerCase();
15
+ if (lower.includes("reason periodic"))
16
+ return null;
17
+ // Filter out the actual heartbeat prompt, but not cron jobs that mention "heartbeat"
18
+ // The heartbeat prompt starts with "Read HEARTBEAT.md" - cron payloads won't match this
19
+ if (lower.startsWith("read heartbeat.md"))
20
+ return null;
21
+ // Also filter heartbeat poll/wake noise
22
+ if (lower.includes("heartbeat poll") || lower.includes("heartbeat wake"))
23
+ return null;
24
+ if (trimmed.startsWith("Node:")) {
25
+ return trimmed.replace(/ · last input [^·]+/i, "").trim();
26
+ }
27
+ return trimmed;
28
+ };
29
+ const resolveExplicitTimezone = (value) => {
30
+ try {
31
+ new Intl.DateTimeFormat("en-US", { timeZone: value }).format(new Date());
32
+ return value;
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ };
38
+ const resolveSystemEventTimezone = (cfg) => {
39
+ const raw = cfg.agents?.defaults?.envelopeTimezone?.trim();
40
+ if (!raw)
41
+ return { mode: "local" };
42
+ const lowered = raw.toLowerCase();
43
+ if (lowered === "utc" || lowered === "gmt")
44
+ return { mode: "utc" };
45
+ if (lowered === "local" || lowered === "host")
46
+ return { mode: "local" };
47
+ if (lowered === "user") {
48
+ return {
49
+ mode: "iana",
50
+ timeZone: resolveUserTimezone(cfg.agents?.defaults?.userTimezone),
51
+ };
52
+ }
53
+ const explicit = resolveExplicitTimezone(raw);
54
+ return explicit ? { mode: "iana", timeZone: explicit } : { mode: "local" };
55
+ };
56
+ const formatUtcTimestamp = (date) => {
57
+ const yyyy = String(date.getUTCFullYear()).padStart(4, "0");
58
+ const mm = String(date.getUTCMonth() + 1).padStart(2, "0");
59
+ const dd = String(date.getUTCDate()).padStart(2, "0");
60
+ const hh = String(date.getUTCHours()).padStart(2, "0");
61
+ const min = String(date.getUTCMinutes()).padStart(2, "0");
62
+ const sec = String(date.getUTCSeconds()).padStart(2, "0");
63
+ return `${yyyy}-${mm}-${dd}T${hh}:${min}:${sec}Z`;
64
+ };
65
+ const formatZonedTimestamp = (date, timeZone) => {
66
+ const parts = new Intl.DateTimeFormat("en-US", {
67
+ timeZone,
68
+ year: "numeric",
69
+ month: "2-digit",
70
+ day: "2-digit",
71
+ hour: "2-digit",
72
+ minute: "2-digit",
73
+ second: "2-digit",
74
+ hourCycle: "h23",
75
+ timeZoneName: "short",
76
+ }).formatToParts(date);
77
+ const pick = (type) => parts.find((part) => part.type === type)?.value;
78
+ const yyyy = pick("year");
79
+ const mm = pick("month");
80
+ const dd = pick("day");
81
+ const hh = pick("hour");
82
+ const min = pick("minute");
83
+ const sec = pick("second");
84
+ const tz = [...parts]
85
+ .reverse()
86
+ .find((part) => part.type === "timeZoneName")
87
+ ?.value?.trim();
88
+ if (!yyyy || !mm || !dd || !hh || !min || !sec)
89
+ return undefined;
90
+ return `${yyyy}-${mm}-${dd} ${hh}:${min}:${sec}${tz ? ` ${tz}` : ""}`;
91
+ };
92
+ const formatSystemEventTimestamp = (ts, cfg) => {
93
+ const date = new Date(ts);
94
+ if (Number.isNaN(date.getTime()))
95
+ return "unknown-time";
96
+ const zone = resolveSystemEventTimezone(cfg);
97
+ if (zone.mode === "utc")
98
+ return formatUtcTimestamp(date);
99
+ if (zone.mode === "local")
100
+ return formatZonedTimestamp(date) ?? "unknown-time";
101
+ return formatZonedTimestamp(date, zone.timeZone) ?? "unknown-time";
102
+ };
103
+ const systemLines = [];
104
+ const queued = drainSystemEventEntries(params.sessionKey);
105
+ systemLines.push(...queued
106
+ .map((event) => {
107
+ const compacted = compactSystemEvent(event.text);
108
+ if (!compacted)
109
+ return null;
110
+ return `[${formatSystemEventTimestamp(event.ts, params.cfg)}] ${compacted}`;
111
+ })
112
+ .filter((v) => Boolean(v)));
113
+ if (params.isMainSession && params.isNewSession) {
114
+ const summary = await buildChannelSummary(params.cfg);
115
+ if (summary.length > 0)
116
+ systemLines.unshift(...summary);
117
+ }
118
+ if (systemLines.length === 0)
119
+ return params.prefixedBodyBase;
120
+ const block = systemLines.map((l) => `System: ${l}`).join("\n");
121
+ return `${block}\n\n${params.prefixedBodyBase}`;
122
+ }
123
+ export async function ensureSkillSnapshot(params) {
124
+ const { sessionEntry, sessionStore, sessionKey, storePath, sessionId, isFirstTurnInSession, workspaceDir, cfg, skillFilter, } = params;
125
+ let nextEntry = sessionEntry;
126
+ let systemSent = sessionEntry?.systemSent ?? false;
127
+ const remoteEligibility = getRemoteSkillEligibility();
128
+ const snapshotVersion = getSkillsSnapshotVersion(workspaceDir);
129
+ ensureSkillsWatcher({ workspaceDir, config: cfg });
130
+ const shouldRefreshSnapshot = snapshotVersion > 0 && (nextEntry?.skillsSnapshot?.version ?? 0) < snapshotVersion;
131
+ if (isFirstTurnInSession && sessionStore && sessionKey) {
132
+ const current = nextEntry ??
133
+ sessionStore[sessionKey] ?? {
134
+ sessionId: sessionId ?? crypto.randomUUID(),
135
+ updatedAt: Date.now(),
136
+ };
137
+ const skillSnapshot = isFirstTurnInSession || !current.skillsSnapshot || shouldRefreshSnapshot
138
+ ? buildWorkspaceSkillSnapshot(workspaceDir, {
139
+ config: cfg,
140
+ skillFilter,
141
+ eligibility: { remote: remoteEligibility },
142
+ snapshotVersion,
143
+ })
144
+ : current.skillsSnapshot;
145
+ nextEntry = {
146
+ ...current,
147
+ sessionId: sessionId ?? current.sessionId ?? crypto.randomUUID(),
148
+ updatedAt: Date.now(),
149
+ systemSent: true,
150
+ skillsSnapshot: skillSnapshot,
151
+ };
152
+ sessionStore[sessionKey] = { ...sessionStore[sessionKey], ...nextEntry };
153
+ if (storePath) {
154
+ await updateSessionStore(storePath, (store) => {
155
+ store[sessionKey] = { ...store[sessionKey], ...nextEntry };
156
+ });
157
+ }
158
+ systemSent = true;
159
+ }
160
+ const skillsSnapshot = shouldRefreshSnapshot
161
+ ? buildWorkspaceSkillSnapshot(workspaceDir, {
162
+ config: cfg,
163
+ skillFilter,
164
+ eligibility: { remote: remoteEligibility },
165
+ snapshotVersion,
166
+ })
167
+ : (nextEntry?.skillsSnapshot ??
168
+ (isFirstTurnInSession
169
+ ? undefined
170
+ : buildWorkspaceSkillSnapshot(workspaceDir, {
171
+ config: cfg,
172
+ skillFilter,
173
+ eligibility: { remote: remoteEligibility },
174
+ snapshotVersion,
175
+ })));
176
+ if (skillsSnapshot &&
177
+ sessionStore &&
178
+ sessionKey &&
179
+ !isFirstTurnInSession &&
180
+ (!nextEntry?.skillsSnapshot || shouldRefreshSnapshot)) {
181
+ const current = nextEntry ?? {
182
+ sessionId: sessionId ?? crypto.randomUUID(),
183
+ updatedAt: Date.now(),
184
+ };
185
+ nextEntry = {
186
+ ...current,
187
+ sessionId: sessionId ?? current.sessionId ?? crypto.randomUUID(),
188
+ updatedAt: Date.now(),
189
+ skillsSnapshot,
190
+ };
191
+ sessionStore[sessionKey] = { ...sessionStore[sessionKey], ...nextEntry };
192
+ if (storePath) {
193
+ await updateSessionStore(storePath, (store) => {
194
+ store[sessionKey] = { ...store[sessionKey], ...nextEntry };
195
+ });
196
+ }
197
+ }
198
+ return { sessionEntry: nextEntry, skillsSnapshot, systemSent };
199
+ }
200
+ export async function incrementCompactionCount(params) {
201
+ const { sessionEntry, sessionStore, sessionKey, storePath, now = Date.now(), tokensAfter, } = params;
202
+ if (!sessionStore || !sessionKey)
203
+ return undefined;
204
+ const entry = sessionStore[sessionKey] ?? sessionEntry;
205
+ if (!entry)
206
+ return undefined;
207
+ const nextCount = (entry.compactionCount ?? 0) + 1;
208
+ // Build update payload with compaction count and optionally updated token counts
209
+ const updates = {
210
+ compactionCount: nextCount,
211
+ updatedAt: now,
212
+ };
213
+ // If tokensAfter is provided, update the cached token counts to reflect post-compaction state
214
+ if (tokensAfter != null && tokensAfter > 0) {
215
+ updates.totalTokens = tokensAfter;
216
+ // Clear input/output breakdown since we only have the total estimate after compaction
217
+ updates.inputTokens = undefined;
218
+ updates.outputTokens = undefined;
219
+ }
220
+ sessionStore[sessionKey] = {
221
+ ...entry,
222
+ ...updates,
223
+ };
224
+ if (storePath) {
225
+ await updateSessionStore(storePath, (store) => {
226
+ store[sessionKey] = {
227
+ ...store[sessionKey],
228
+ ...updates,
229
+ };
230
+ });
231
+ }
232
+ return nextCount;
233
+ }
@@ -0,0 +1,146 @@
1
+ import { spawn } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { ensureSandboxWorkspaceForSession } from "../../agents/sandbox.js";
6
+ import { logVerbose } from "../../globals.js";
7
+ import { CONFIG_DIR } from "../../utils.js";
8
+ export async function stageSandboxMedia(params) {
9
+ const { ctx, sessionCtx, cfg, sessionKey, workspaceDir } = params;
10
+ const hasPathsArray = Array.isArray(ctx.MediaPaths) && ctx.MediaPaths.length > 0;
11
+ const pathsFromArray = Array.isArray(ctx.MediaPaths) ? ctx.MediaPaths : undefined;
12
+ const rawPaths = pathsFromArray && pathsFromArray.length > 0
13
+ ? pathsFromArray
14
+ : ctx.MediaPath?.trim()
15
+ ? [ctx.MediaPath.trim()]
16
+ : [];
17
+ if (rawPaths.length === 0 || !sessionKey)
18
+ return;
19
+ const sandbox = await ensureSandboxWorkspaceForSession({
20
+ config: cfg,
21
+ sessionKey,
22
+ workspaceDir,
23
+ });
24
+ // For remote attachments without sandbox, use ~/.poolbot/media (not agent workspace for privacy)
25
+ const remoteMediaCacheDir = ctx.MediaRemoteHost
26
+ ? path.join(CONFIG_DIR, "media", "remote-cache", sessionKey)
27
+ : null;
28
+ const effectiveWorkspaceDir = sandbox?.workspaceDir ?? remoteMediaCacheDir;
29
+ if (!effectiveWorkspaceDir)
30
+ return;
31
+ const resolveAbsolutePath = (value) => {
32
+ let resolved = value.trim();
33
+ if (!resolved)
34
+ return null;
35
+ if (resolved.startsWith("file://")) {
36
+ try {
37
+ resolved = fileURLToPath(resolved);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ if (!path.isAbsolute(resolved))
44
+ return null;
45
+ return resolved;
46
+ };
47
+ try {
48
+ // For sandbox: <workspace>/media/inbound, for remote cache: use dir directly
49
+ const destDir = sandbox
50
+ ? path.join(effectiveWorkspaceDir, "media", "inbound")
51
+ : effectiveWorkspaceDir;
52
+ await fs.mkdir(destDir, { recursive: true });
53
+ const usedNames = new Set();
54
+ const staged = new Map(); // absolute source -> relative sandbox path
55
+ for (const raw of rawPaths) {
56
+ const source = resolveAbsolutePath(raw);
57
+ if (!source)
58
+ continue;
59
+ if (staged.has(source))
60
+ continue;
61
+ const baseName = path.basename(source);
62
+ if (!baseName)
63
+ continue;
64
+ const parsed = path.parse(baseName);
65
+ let fileName = baseName;
66
+ let suffix = 1;
67
+ while (usedNames.has(fileName)) {
68
+ fileName = `${parsed.name}-${suffix}${parsed.ext}`;
69
+ suffix += 1;
70
+ }
71
+ usedNames.add(fileName);
72
+ const dest = path.join(destDir, fileName);
73
+ if (ctx.MediaRemoteHost) {
74
+ // Always use SCP when remote host is configured - local paths refer to remote machine
75
+ await scpFile(ctx.MediaRemoteHost, source, dest);
76
+ }
77
+ else {
78
+ await fs.copyFile(source, dest);
79
+ }
80
+ // For sandbox use relative path, for remote cache use absolute path
81
+ const stagedPath = sandbox ? path.posix.join("media", "inbound", fileName) : dest;
82
+ staged.set(source, stagedPath);
83
+ }
84
+ const rewriteIfStaged = (value) => {
85
+ const raw = value?.trim();
86
+ if (!raw)
87
+ return value;
88
+ const abs = resolveAbsolutePath(raw);
89
+ if (!abs)
90
+ return value;
91
+ const mapped = staged.get(abs);
92
+ return mapped ?? value;
93
+ };
94
+ const nextMediaPaths = hasPathsArray ? rawPaths.map((p) => rewriteIfStaged(p) ?? p) : undefined;
95
+ if (nextMediaPaths) {
96
+ ctx.MediaPaths = nextMediaPaths;
97
+ sessionCtx.MediaPaths = nextMediaPaths;
98
+ ctx.MediaPath = nextMediaPaths[0];
99
+ sessionCtx.MediaPath = nextMediaPaths[0];
100
+ }
101
+ else {
102
+ const rewritten = rewriteIfStaged(ctx.MediaPath);
103
+ if (rewritten && rewritten !== ctx.MediaPath) {
104
+ ctx.MediaPath = rewritten;
105
+ sessionCtx.MediaPath = rewritten;
106
+ }
107
+ }
108
+ if (Array.isArray(ctx.MediaUrls) && ctx.MediaUrls.length > 0) {
109
+ const nextUrls = ctx.MediaUrls.map((u) => rewriteIfStaged(u) ?? u);
110
+ ctx.MediaUrls = nextUrls;
111
+ sessionCtx.MediaUrls = nextUrls;
112
+ }
113
+ const rewrittenUrl = rewriteIfStaged(ctx.MediaUrl);
114
+ if (rewrittenUrl && rewrittenUrl !== ctx.MediaUrl) {
115
+ ctx.MediaUrl = rewrittenUrl;
116
+ sessionCtx.MediaUrl = rewrittenUrl;
117
+ }
118
+ }
119
+ catch (err) {
120
+ logVerbose(`Failed to stage inbound media for sandbox: ${String(err)}`);
121
+ }
122
+ }
123
+ async function scpFile(remoteHost, remotePath, localPath) {
124
+ return new Promise((resolve, reject) => {
125
+ const child = spawn("/usr/bin/scp", [
126
+ "-o",
127
+ "BatchMode=yes",
128
+ "-o",
129
+ "StrictHostKeyChecking=accept-new",
130
+ `${remoteHost}:${remotePath}`,
131
+ localPath,
132
+ ], { stdio: ["ignore", "ignore", "pipe"] });
133
+ let stderr = "";
134
+ child.stderr?.setEncoding("utf8");
135
+ child.stderr?.on("data", (chunk) => {
136
+ stderr += chunk;
137
+ });
138
+ child.once("error", reject);
139
+ child.once("exit", (code) => {
140
+ if (code === 0)
141
+ resolve();
142
+ else
143
+ reject(new Error(`scp failed (${code}): ${stderr.trim()}`));
144
+ });
145
+ });
146
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.3.25",
3
- "commit": "c9d04aa2bcb820ac58ff49c59285704e2ed6ed75",
4
- "builtAt": "2026-03-16T21:28:12.661Z"
2
+ "version": "2026.3.26",
3
+ "commit": "eee66000dac39be6214625d1cf9dc6e254077e7c",
4
+ "builtAt": "2026-03-18T11:37:07.663Z"
5
5
  }
@@ -1 +1 @@
1
- 6b0df478e4e17402a1fa00508f807742d68a3f83cd0ed0a2fa35847745519125
1
+ stub