@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
package/dist/utils.js CHANGED
@@ -1,288 +1,22 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { resolveOAuthDir } from "./config/paths.js";
5
- import { logVerbose, shouldLogVerbose } from "./globals.js";
6
- import { expandHomePrefix, resolveEffectiveHomeDir, resolveRequiredHomeDir, } from "./infra/home-dir.js";
7
- export async function ensureDir(dir) {
8
- await fs.promises.mkdir(dir, { recursive: true });
9
- }
10
- /**
11
- * Check if a file or directory exists at the given path.
12
- */
13
- export async function pathExists(targetPath) {
14
- try {
15
- await fs.promises.access(targetPath);
16
- return true;
17
- }
18
- catch {
19
- return false;
20
- }
21
- }
22
- export function clampNumber(value, min, max) {
23
- return Math.max(min, Math.min(max, value));
24
- }
25
- export function clampInt(value, min, max) {
26
- return clampNumber(Math.floor(value), min, max);
27
- }
28
- /** Alias for clampNumber (shorter, more common name) */
29
- export const clamp = clampNumber;
30
- /**
31
- * Escapes special regex characters in a string so it can be used in a RegExp constructor.
32
- */
33
- export function escapeRegExp(value) {
34
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
35
- }
36
- /**
37
- * Safely parse JSON, returning null on error instead of throwing.
38
- */
39
- export function safeParseJson(raw) {
1
+ // Stub for utils.js
2
+ export function safeParseJson(str) {
40
3
  try {
41
- return JSON.parse(raw);
4
+ return JSON.parse(str);
42
5
  }
43
6
  catch {
44
7
  return null;
45
8
  }
46
9
  }
47
- /**
48
- * Type guard for Record<string, unknown> (less strict than isPlainObject).
49
- * Accepts any non-null object that isn't an array.
50
- */
51
- export function isRecord(value) {
52
- return typeof value === "object" && value !== null && !Array.isArray(value);
53
- }
54
- export function assertWebChannel(input) {
55
- if (input !== "web") {
56
- throw new Error("Web channel must be 'web'");
57
- }
58
- }
59
- export function normalizePath(p) {
60
- if (!p.startsWith("/"))
61
- return `/${p}`;
62
- return p;
63
- }
64
- export function withWhatsAppPrefix(number) {
65
- return number.startsWith("whatsapp:") ? number : `whatsapp:${number}`;
66
- }
67
- export function normalizeE164(number) {
68
- const withoutPrefix = number.replace(/^whatsapp:/, "").trim();
69
- const digits = withoutPrefix.replace(/[^\d+]/g, "");
70
- if (digits.startsWith("+"))
71
- return `+${digits.slice(1)}`;
72
- return `+${digits}`;
73
- }
74
- /**
75
- * "Self-chat mode" heuristic (single phone): the gateway is logged in as the owner's own WhatsApp account,
76
- * and `channels.whatsapp.allowFrom` includes that same number. Used to avoid side-effects that make no sense when the
77
- * "bot" and the human are the same WhatsApp identity (e.g. auto read receipts, @mention JID triggers).
78
- */
79
- export function isSelfChatMode(selfE164, allowFrom) {
80
- if (!selfE164)
81
- return false;
82
- if (!Array.isArray(allowFrom) || allowFrom.length === 0)
83
- return false;
84
- const normalizedSelf = normalizeE164(selfE164);
85
- return allowFrom.some((n) => {
86
- if (n === "*")
87
- return false;
88
- try {
89
- return normalizeE164(String(n)) === normalizedSelf;
90
- }
91
- catch {
92
- return false;
93
- }
94
- });
95
- }
96
- export function toWhatsappJid(number) {
97
- const withoutPrefix = number.replace(/^whatsapp:/, "").trim();
98
- if (withoutPrefix.includes("@"))
99
- return withoutPrefix;
100
- const e164 = normalizeE164(withoutPrefix);
101
- const digits = e164.replace(/\D/g, "");
102
- return `${digits}@s.whatsapp.net`;
103
- }
104
- function resolveLidMappingDirs(opts) {
105
- const dirs = new Set();
106
- const addDir = (dir) => {
107
- if (!dir)
108
- return;
109
- dirs.add(resolveUserPath(dir));
110
- };
111
- addDir(opts?.authDir);
112
- for (const dir of opts?.lidMappingDirs ?? [])
113
- addDir(dir);
114
- addDir(resolveOAuthDir());
115
- addDir(path.join(CONFIG_DIR, "credentials"));
116
- return [...dirs];
117
- }
118
- function readLidReverseMapping(lid, opts) {
119
- const mappingFilename = `lid-mapping-${lid}_reverse.json`;
120
- const mappingDirs = resolveLidMappingDirs(opts);
121
- for (const dir of mappingDirs) {
122
- const mappingPath = path.join(dir, mappingFilename);
123
- try {
124
- const data = fs.readFileSync(mappingPath, "utf8");
125
- const phone = JSON.parse(data);
126
- if (phone === null || phone === undefined)
127
- continue;
128
- return normalizeE164(String(phone));
129
- }
130
- catch {
131
- // Try the next location.
132
- }
133
- }
134
- return null;
135
- }
136
- export function jidToE164(jid, opts) {
137
- // Convert a WhatsApp JID (with optional device suffix, e.g. 1234:1@s.whatsapp.net) back to +1234.
138
- const match = jid.match(/^(\d+)(?::\d+)?@(s\.whatsapp\.net|hosted)$/);
139
- if (match) {
140
- const digits = match[1];
141
- return `+${digits}`;
142
- }
143
- // Support @lid format (WhatsApp Linked ID) - look up reverse mapping
144
- const lidMatch = jid.match(/^(\d+)(?::\d+)?@(lid|hosted\.lid)$/);
145
- if (lidMatch) {
146
- const lid = lidMatch[1];
147
- const phone = readLidReverseMapping(lid, opts);
148
- if (phone)
149
- return phone;
150
- const shouldLog = opts?.logMissing ?? shouldLogVerbose();
151
- if (shouldLog) {
152
- logVerbose(`LID mapping not found for ${lid}; skipping inbound message`);
153
- }
154
- }
155
- return null;
156
- }
157
- export async function resolveJidToE164(jid, opts) {
158
- if (!jid)
159
- return null;
160
- const direct = jidToE164(jid, opts);
161
- if (direct)
162
- return direct;
163
- if (!/(@lid|@hosted\.lid)$/.test(jid))
164
- return null;
165
- if (!opts?.lidLookup?.getPNForLID)
166
- return null;
167
- try {
168
- const pnJid = await opts.lidLookup.getPNForLID(jid);
169
- if (!pnJid)
170
- return null;
171
- return jidToE164(pnJid, opts);
172
- }
173
- catch (err) {
174
- if (shouldLogVerbose()) {
175
- logVerbose(`LID mapping lookup failed for ${jid}: ${String(err)}`);
176
- }
177
- return null;
178
- }
179
- }
180
10
  export function sleep(ms) {
181
11
  return new Promise((resolve) => setTimeout(resolve, ms));
182
12
  }
183
- function isHighSurrogate(codeUnit) {
184
- return codeUnit >= 0xd800 && codeUnit <= 0xdbff;
185
- }
186
- function isLowSurrogate(codeUnit) {
187
- return codeUnit >= 0xdc00 && codeUnit <= 0xdfff;
13
+ export function stripAnsi(str) {
14
+ // oxlint-disable-next-line no-control-regex
15
+ return str.replace(/\u001b\[[0-9;]*m/g, "");
188
16
  }
189
- export function sliceUtf16Safe(input, start, end) {
190
- const len = input.length;
191
- let from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
192
- let to = end === undefined ? len : end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
193
- if (to < from) {
194
- const tmp = from;
195
- from = to;
196
- to = tmp;
197
- }
198
- if (from > 0 && from < len) {
199
- const codeUnit = input.charCodeAt(from);
200
- if (isLowSurrogate(codeUnit) && isHighSurrogate(input.charCodeAt(from - 1))) {
201
- from += 1;
202
- }
203
- }
204
- if (to > 0 && to < len) {
205
- const codeUnit = input.charCodeAt(to - 1);
206
- if (isHighSurrogate(codeUnit) && isLowSurrogate(input.charCodeAt(to))) {
207
- to -= 1;
208
- }
209
- }
210
- return input.slice(from, to);
211
- }
212
- export function truncateUtf16Safe(input, maxLen) {
213
- const limit = Math.max(0, Math.floor(maxLen));
214
- if (input.length <= limit)
215
- return input;
216
- return sliceUtf16Safe(input, 0, limit);
217
- }
218
- export function resolveUserPath(input) {
219
- const trimmed = input.trim();
220
- if (!trimmed)
221
- return trimmed;
222
- if (trimmed.startsWith("~")) {
223
- const expanded = expandHomePrefix(trimmed, {
224
- home: resolveRequiredHomeDir(process.env, os.homedir),
225
- env: process.env,
226
- homedir: os.homedir,
227
- });
228
- return path.resolve(expanded);
229
- }
230
- return path.resolve(trimmed);
231
- }
232
- export function resolveConfigDir(env = process.env, homedir = os.homedir) {
233
- const override = env.POOLBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
234
- if (override)
235
- return resolveUserPath(override);
236
- return path.join(homedir(), ".poolbot");
237
- }
238
- export function resolveHomeDir() {
239
- return resolveEffectiveHomeDir(process.env, os.homedir);
240
- }
241
- export function shortenHomePath(input) {
242
- if (!input)
243
- return input;
244
- const home = resolveHomeDir();
245
- if (!home)
246
- return input;
247
- if (input === home)
248
- return "~";
249
- if (input.startsWith(`${home}/`))
250
- return `~${input.slice(home.length)}`;
251
- return input;
252
- }
253
- export function shortenHomeInString(input) {
254
- if (!input)
255
- return input;
256
- const home = resolveHomeDir();
257
- if (!home)
258
- return input;
259
- return input.split(home).join("~");
260
- }
261
- export function displayPath(input) {
262
- return shortenHomePath(input);
263
- }
264
- export function displayString(input) {
265
- return shortenHomeInString(input);
266
- }
267
- export function formatTerminalLink(label, url, opts) {
268
- const esc = "\u001b";
269
- const safeLabel = label.replaceAll(esc, "");
270
- const safeUrl = url.replaceAll(esc, "");
271
- const allow = opts?.force === true ? true : opts?.force === false ? false : Boolean(process.stdout.isTTY);
272
- if (!allow) {
273
- return opts?.fallback ?? `${safeLabel} (${safeUrl})`;
274
- }
275
- return `\u001b]8;;${safeUrl}\u0007${safeLabel}\u001b]8;;\u0007`;
17
+ export function escapeRegExp(str) {
18
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
276
19
  }
277
- /**
278
- * Strict plain-object check — returns true only for `Object.create(null)` or `{}` literals.
279
- * Arrays, Dates, RegExps, class instances, and null/undefined all return false.
280
- */
281
- export function isPlainObject(value) {
282
- if (typeof value !== "object" || value === null)
283
- return false;
284
- const proto = Object.getPrototypeOf(value);
285
- return proto === Object.prototype || proto === null;
20
+ export function clamp(val, min, max) {
21
+ return Math.min(max, Math.max(min, val));
286
22
  }
287
- // Configuration root; can be overridden via POOLBOT_STATE_DIR (or CLAWDBOT_STATE_DIR).
288
- export const CONFIG_DIR = resolveConfigDir();
@@ -1,6 +1,6 @@
1
- export class WizardCancelledError extends Error {
2
- constructor(message = "wizard cancelled") {
3
- super(message);
4
- this.name = "WizardCancelledError";
5
- }
1
+ export async function promptAccountId(_config, _channelKey) {
2
+ return "default";
3
+ }
4
+ export async function promptChannelAccessConfig(_config, _channelKey, _accountId) {
5
+ return {};
6
6
  }
@@ -38,7 +38,7 @@ export function resolveFeishuGroupConfig(params: {
38
38
 
39
39
  export function resolveFeishuGroupToolPolicy(
40
40
  params: ChannelGroupContext,
41
- ): GroupToolPolicyConfig | undefined {
41
+ ): GroupToolPolicyConfig? {
42
42
  const cfg = params.cfg.channels?.feishu as FeishuConfig | undefined;
43
43
  if (!cfg) {
44
44
  return undefined;
@@ -0,0 +1,82 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import plugin from "./index.js";
3
+ import { __testing as firecrawlClientTesting } from "./src/firecrawl-client.js";
4
+
5
+ describe("firecrawl plugin", () => {
6
+ it("parses scrape payloads into wrapped external-content results", () => {
7
+ const result = firecrawlClientTesting.parseFirecrawlScrapePayload({
8
+ payload: {
9
+ success: true,
10
+ data: {
11
+ markdown: "# Hello\n\nWorld",
12
+ metadata: {
13
+ title: "Example page",
14
+ sourceURL: "https://example.com/final",
15
+ statusCode: 200,
16
+ },
17
+ },
18
+ },
19
+ url: "https://example.com/start",
20
+ extractMode: "text",
21
+ maxChars: 1000,
22
+ });
23
+
24
+ expect(result.finalUrl).toBe("https://example.com/final");
25
+ expect(result.status).toBe(200);
26
+ expect(result.extractor).toBe("firecrawl");
27
+ expect(typeof result.text).toBe("string");
28
+ });
29
+
30
+ it("extracts search items from flexible Firecrawl payload shapes", () => {
31
+ const items = firecrawlClientTesting.resolveSearchItems({
32
+ success: true,
33
+ data: [
34
+ {
35
+ title: "Docs",
36
+ url: "https://docs.example.com/path",
37
+ description: "Reference docs",
38
+ markdown: "Body",
39
+ },
40
+ ],
41
+ });
42
+
43
+ expect(items).toEqual([
44
+ {
45
+ title: "Docs",
46
+ url: "https://docs.example.com/path",
47
+ description: "Reference docs",
48
+ content: "Body",
49
+ published: undefined,
50
+ siteName: "docs.example.com",
51
+ },
52
+ ]);
53
+ });
54
+
55
+ it("extracts search items from Firecrawl v2 data.web payloads", () => {
56
+ const items = firecrawlClientTesting.resolveSearchItems({
57
+ success: true,
58
+ data: {
59
+ web: [
60
+ {
61
+ title: "API Platform - OpenAI",
62
+ url: "https://openai.com/api/",
63
+ description: "Build on the OpenAI API platform.",
64
+ markdown: "# API Platform",
65
+ position: 1,
66
+ },
67
+ ],
68
+ },
69
+ });
70
+
71
+ expect(items).toEqual([
72
+ {
73
+ title: "API Platform - OpenAI",
74
+ url: "https://openai.com/api/",
75
+ description: "Build on the OpenAI API platform.",
76
+ content: "# API Platform",
77
+ published: undefined,
78
+ siteName: "openai.com",
79
+ },
80
+ ]);
81
+ });
82
+ });
@@ -0,0 +1,20 @@
1
+ import type { AnyAgentTool } from "../../src/agents/tools/common.js";
2
+ import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js";
3
+ import type { OpenClawPluginApi } from "../../src/plugins/types.js";
4
+ import { createFirecrawlScrapeTool } from "./src/firecrawl-scrape-tool.js";
5
+ import { createFirecrawlWebSearchProvider } from "./src/firecrawl-search-provider.js";
6
+ import { createFirecrawlSearchTool } from "./src/firecrawl-search-tool.js";
7
+
8
+ const firecrawlPlugin = {
9
+ id: "firecrawl",
10
+ name: "Firecrawl Plugin",
11
+ description: "Bundled Firecrawl search and scrape plugin",
12
+ configSchema: emptyPluginConfigSchema(),
13
+ register(api: OpenClawPluginApi) {
14
+ api.registerWebSearchProvider(createFirecrawlWebSearchProvider());
15
+ api.registerTool(createFirecrawlSearchTool(api) as AnyAgentTool);
16
+ api.registerTool(createFirecrawlScrapeTool(api) as AnyAgentTool);
17
+ },
18
+ };
19
+
20
+ export default firecrawlPlugin;
@@ -0,0 +1,8 @@
1
+ {
2
+ "id": "firecrawl",
3
+ "configSchema": {
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "properties": {}
7
+ }
8
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@openclaw/firecrawl-plugin",
3
+ "version": "2026.3.14",
4
+ "private": true,
5
+ "description": "OpenClaw Firecrawl plugin",
6
+ "type": "module",
7
+ "openclaw": {
8
+ "extensions": [
9
+ "./index.ts"
10
+ ]
11
+ }
12
+ }
@@ -0,0 +1,159 @@
1
+ import type { OpenClawConfig } from "../../../src/config/config.js";
2
+ import { normalizeResolvedSecretInputString } from "../../../src/config/types.secrets.js";
3
+ import { normalizeSecretInput } from "../../../src/utils/normalize-secret-input.js";
4
+
5
+ export const DEFAULT_FIRECRAWL_BASE_URL = "https://api.firecrawl.dev";
6
+ export const DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS = 30;
7
+ export const DEFAULT_FIRECRAWL_SCRAPE_TIMEOUT_SECONDS = 60;
8
+ export const DEFAULT_FIRECRAWL_MAX_AGE_MS = 172_800_000;
9
+
10
+ type WebSearchConfig = NonNullable<OpenClawConfig["tools"]>["web"] extends infer Web
11
+ ? Web extends { search?: infer Search }
12
+ ? Search
13
+ : undefined
14
+ : undefined;
15
+
16
+ type WebFetchConfig = NonNullable<OpenClawConfig["tools"]>["web"] extends infer Web
17
+ ? Web extends { fetch?: infer Fetch }
18
+ ? Fetch
19
+ : undefined
20
+ : undefined;
21
+
22
+ type FirecrawlSearchConfig =
23
+ | {
24
+ apiKey?: unknown;
25
+ baseUrl?: string;
26
+ }
27
+ | undefined;
28
+
29
+ type FirecrawlFetchConfig =
30
+ | {
31
+ apiKey?: unknown;
32
+ baseUrl?: string;
33
+ onlyMainContent?: boolean;
34
+ maxAgeMs?: number;
35
+ timeoutSeconds?: number;
36
+ }
37
+ | undefined;
38
+
39
+ function resolveSearchConfig(cfg?: OpenClawConfig): WebSearchConfig {
40
+ const search = cfg?.tools?.web?.search;
41
+ if (!search || typeof search !== "object") {
42
+ return undefined;
43
+ }
44
+ return search as WebSearchConfig;
45
+ }
46
+
47
+ function resolveFetchConfig(cfg?: OpenClawConfig): WebFetchConfig {
48
+ const fetch = cfg?.tools?.web?.fetch;
49
+ if (!fetch || typeof fetch !== "object") {
50
+ return undefined;
51
+ }
52
+ return fetch as WebFetchConfig;
53
+ }
54
+
55
+ export function resolveFirecrawlSearchConfig(cfg?: OpenClawConfig): FirecrawlSearchConfig {
56
+ const search = resolveSearchConfig(cfg);
57
+ if (!search || typeof search !== "object") {
58
+ return undefined;
59
+ }
60
+ const firecrawl = "firecrawl" in search ? search.firecrawl : undefined;
61
+ if (!firecrawl || typeof firecrawl !== "object") {
62
+ return undefined;
63
+ }
64
+ return firecrawl as FirecrawlSearchConfig;
65
+ }
66
+
67
+ export function resolveFirecrawlFetchConfig(cfg?: OpenClawConfig): FirecrawlFetchConfig {
68
+ const fetch = resolveFetchConfig(cfg);
69
+ if (!fetch || typeof fetch !== "object") {
70
+ return undefined;
71
+ }
72
+ const firecrawl = "firecrawl" in fetch ? fetch.firecrawl : undefined;
73
+ if (!firecrawl || typeof firecrawl !== "object") {
74
+ return undefined;
75
+ }
76
+ return firecrawl as FirecrawlFetchConfig;
77
+ }
78
+
79
+ function normalizeConfiguredSecret(value: unknown, path: string): string | undefined {
80
+ return normalizeSecretInput(
81
+ normalizeResolvedSecretInputString({
82
+ value,
83
+ path,
84
+ }),
85
+ );
86
+ }
87
+
88
+ export function resolveFirecrawlApiKey(cfg?: OpenClawConfig): string | undefined {
89
+ const search = resolveFirecrawlSearchConfig(cfg);
90
+ const fetch = resolveFirecrawlFetchConfig(cfg);
91
+ return (
92
+ normalizeConfiguredSecret(search?.apiKey, "tools.web.search.firecrawl.apiKey") ||
93
+ normalizeConfiguredSecret(fetch?.apiKey, "tools.web.fetch.firecrawl.apiKey") ||
94
+ normalizeSecretInput(process.env.FIRECRAWL_API_KEY) ||
95
+ undefined
96
+ );
97
+ }
98
+
99
+ export function resolveFirecrawlBaseUrl(cfg?: OpenClawConfig): string {
100
+ const search = resolveFirecrawlSearchConfig(cfg);
101
+ const fetch = resolveFirecrawlFetchConfig(cfg);
102
+ const configured =
103
+ (typeof search?.baseUrl === "string" ? search.baseUrl.trim() : "") ||
104
+ (typeof fetch?.baseUrl === "string" ? fetch.baseUrl.trim() : "") ||
105
+ normalizeSecretInput(process.env.FIRECRAWL_BASE_URL) ||
106
+ "";
107
+ return configured || DEFAULT_FIRECRAWL_BASE_URL;
108
+ }
109
+
110
+ export function resolveFirecrawlOnlyMainContent(cfg?: OpenClawConfig, override?: boolean): boolean {
111
+ if (typeof override === "boolean") {
112
+ return override;
113
+ }
114
+ const fetch = resolveFirecrawlFetchConfig(cfg);
115
+ if (typeof fetch?.onlyMainContent === "boolean") {
116
+ return fetch.onlyMainContent;
117
+ }
118
+ return true;
119
+ }
120
+
121
+ export function resolveFirecrawlMaxAgeMs(cfg?: OpenClawConfig, override?: number): number {
122
+ if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
123
+ return Math.floor(override);
124
+ }
125
+ const fetch = resolveFirecrawlFetchConfig(cfg);
126
+ if (
127
+ typeof fetch?.maxAgeMs === "number" &&
128
+ Number.isFinite(fetch.maxAgeMs) &&
129
+ fetch.maxAgeMs >= 0
130
+ ) {
131
+ return Math.floor(fetch.maxAgeMs);
132
+ }
133
+ return DEFAULT_FIRECRAWL_MAX_AGE_MS;
134
+ }
135
+
136
+ export function resolveFirecrawlScrapeTimeoutSeconds(
137
+ cfg?: OpenClawConfig,
138
+ override?: number,
139
+ ): number {
140
+ if (typeof override === "number" && Number.isFinite(override) && override > 0) {
141
+ return Math.floor(override);
142
+ }
143
+ const fetch = resolveFirecrawlFetchConfig(cfg);
144
+ if (
145
+ typeof fetch?.timeoutSeconds === "number" &&
146
+ Number.isFinite(fetch.timeoutSeconds) &&
147
+ fetch.timeoutSeconds > 0
148
+ ) {
149
+ return Math.floor(fetch.timeoutSeconds);
150
+ }
151
+ return DEFAULT_FIRECRAWL_SCRAPE_TIMEOUT_SECONDS;
152
+ }
153
+
154
+ export function resolveFirecrawlSearchTimeoutSeconds(override?: number): number {
155
+ if (typeof override === "number" && Number.isFinite(override) && override > 0) {
156
+ return Math.floor(override);
157
+ }
158
+ return DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS;
159
+ }