@poolzin/pool-bot 2026.2.22 → 2026.2.23

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 (51) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/build-info.json +3 -3
  3. package/extensions/bluebubbles/package.json +1 -1
  4. package/extensions/copilot-proxy/package.json +1 -1
  5. package/extensions/device-pair/index.ts +2 -2
  6. package/extensions/diagnostics-otel/package.json +1 -1
  7. package/extensions/discord/package.json +1 -1
  8. package/extensions/feishu/package.json +1 -1
  9. package/extensions/google-antigravity-auth/package.json +1 -1
  10. package/extensions/google-gemini-cli-auth/package.json +1 -1
  11. package/extensions/googlechat/package.json +1 -1
  12. package/extensions/imessage/package.json +1 -1
  13. package/extensions/irc/package.json +1 -1
  14. package/extensions/irc/src/accounts.ts +1 -1
  15. package/extensions/irc/src/onboarding.ts +4 -4
  16. package/extensions/line/package.json +1 -1
  17. package/extensions/llm-task/package.json +1 -1
  18. package/extensions/lobster/package.json +1 -1
  19. package/extensions/matrix/CHANGELOG.md +5 -0
  20. package/extensions/matrix/package.json +1 -1
  21. package/extensions/mattermost/package.json +1 -1
  22. package/extensions/memory-core/package.json +1 -1
  23. package/extensions/memory-lancedb/package.json +1 -1
  24. package/extensions/minimax-portal-auth/package.json +1 -1
  25. package/extensions/msteams/CHANGELOG.md +5 -0
  26. package/extensions/msteams/package.json +1 -1
  27. package/extensions/nextcloud-talk/package.json +1 -1
  28. package/extensions/nostr/CHANGELOG.md +5 -0
  29. package/extensions/nostr/package.json +1 -1
  30. package/extensions/open-prose/package.json +1 -1
  31. package/extensions/openai-codex-auth/package.json +1 -1
  32. package/extensions/signal/package.json +1 -1
  33. package/extensions/slack/package.json +1 -1
  34. package/extensions/telegram/package.json +1 -1
  35. package/extensions/tlon/package.json +1 -1
  36. package/extensions/twitch/CHANGELOG.md +5 -0
  37. package/extensions/twitch/package.json +1 -1
  38. package/extensions/voice-call/CHANGELOG.md +5 -0
  39. package/extensions/voice-call/package.json +1 -1
  40. package/extensions/whatsapp/package.json +1 -1
  41. package/extensions/zalo/CHANGELOG.md +5 -0
  42. package/extensions/zalo/package.json +1 -1
  43. package/extensions/zalouser/CHANGELOG.md +5 -0
  44. package/extensions/zalouser/package.json +1 -1
  45. package/package.json +1 -1
  46. package/dist/agents/openclaw-tools.js +0 -151
  47. package/dist/agents/tool-security.js +0 -96
  48. package/dist/gateway/url-validation.js +0 -94
  49. package/dist/infra/openclaw-root.js +0 -109
  50. package/dist/infra/tmp-openclaw-dir.js +0 -81
  51. package/dist/media/path-sanitization.js +0 -78
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## v2026.2.23 (2026-02-18)
2
+
3
+ ### Fixes
4
+ - **Rebrand:** purge last 7 user-facing "OpenClaw" references from device-pair and IRC extensions — QR code pairing instructions, IRC realname default, onboarding placeholders, and CLI command references now all say "Pool Bot" / "poolbot"
5
+ - **Audit:** full codebase scan confirms zero "openclaw" references remain in production code (src/cli, src/commands, src/terminal, src/auto-reply, src/config, src/agents, src/infra, src/gateway, all channels, all extensions)
6
+
7
+ ---
8
+
1
9
  ## v2026.2.22 (2026-02-18)
2
10
 
3
11
  ### Features
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.2.22",
3
- "commit": "2f28abca3332ffa8582bc9169e87e707374b2c56",
4
- "builtAt": "2026-02-18T13:03:00.077Z"
2
+ "version": "2026.2.23",
3
+ "commit": "ef242fa9f8b367333f246a3777937c94c68f5847",
4
+ "builtAt": "2026-02-18T18:15:41.704Z"
5
5
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/bluebubbles",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot BlueBubbles channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/copilot-proxy",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Copilot Proxy provider plugin",
6
6
  "poolbot": {
@@ -457,7 +457,7 @@ export default function register(api: PoolBotPluginApi) {
457
457
  if (send) {
458
458
  await send(
459
459
  target,
460
- ["Scan this QR code with the OpenClaw iOS app:", "", "```", qrAscii, "```"].join(
460
+ ["Scan this QR code with the Pool Bot iOS app:", "", "```", qrAscii, "```"].join(
461
461
  "\n",
462
462
  ),
463
463
  {
@@ -495,7 +495,7 @@ export default function register(api: PoolBotPluginApi) {
495
495
  // WebUI + CLI/TUI: ASCII QR
496
496
  return {
497
497
  text: [
498
- "Scan this QR code with the OpenClaw iOS app:",
498
+ "Scan this QR code with the Pool Bot iOS app:",
499
499
  "",
500
500
  "```",
501
501
  qrAscii,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/diagnostics-otel",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot diagnostics OpenTelemetry exporter",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/discord",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Discord channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/feishu",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "description": "Pool Bot Feishu/Lark channel plugin (community maintained by @m1heng)",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/google-antigravity-auth",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Google Antigravity OAuth provider plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/google-gemini-cli-auth",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Gemini CLI OAuth provider plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/googlechat",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Google Chat channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/imessage",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot iMessage channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/irc",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "description": "Pool Bot IRC channel plugin",
5
5
  "type": "module",
6
6
  "devDependencies": {
@@ -206,7 +206,7 @@ export function resolveIrcAccount(params: {
206
206
  const realname = (
207
207
  merged.realname?.trim() ||
208
208
  (accountId === DEFAULT_ACCOUNT_ID ? process.env.IRC_REALNAME?.trim() : "") ||
209
- "OpenClaw"
209
+ "Pool Bot"
210
210
  ).trim();
211
211
 
212
212
  const passwordResolution = resolvePassword(accountId, merged);
@@ -387,14 +387,14 @@ export const ircOnboardingAdapter: ChannelOnboardingAdapter = {
387
387
  const realname = String(
388
388
  await prompter.text({
389
389
  message: "IRC real name",
390
- initialValue: resolved.config.realname || "OpenClaw",
390
+ initialValue: resolved.config.realname || "Pool Bot",
391
391
  validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
392
392
  }),
393
393
  ).trim();
394
394
 
395
395
  const channelsRaw = await prompter.text({
396
396
  message: "Auto-join IRC channels (optional, comma-separated)",
397
- placeholder: "#openclaw, #ops",
397
+ placeholder: "#poolbot, #ops",
398
398
  initialValue: (resolved.config.channels ?? []).join(", "),
399
399
  });
400
400
  const channels = [
@@ -424,7 +424,7 @@ export const ircOnboardingAdapter: ChannelOnboardingAdapter = {
424
424
  label: "IRC channels",
425
425
  currentPolicy: afterConfig.config.groupPolicy ?? "allowlist",
426
426
  currentEntries: Object.keys(afterConfig.config.groups ?? {}),
427
- placeholder: "#openclaw, #ops, *",
427
+ placeholder: "#poolbot, #ops, *",
428
428
  updatePrompt: Boolean(afterConfig.config.groups),
429
429
  });
430
430
  if (accessConfig) {
@@ -457,7 +457,7 @@ export const ircOnboardingAdapter: ChannelOnboardingAdapter = {
457
457
  await prompter.note(
458
458
  [
459
459
  "Next: restart gateway and verify status.",
460
- "Command: openclaw channels status --probe",
460
+ "Command: poolbot channels status --probe",
461
461
  `Docs: ${formatDocsLink("/channels/irc", "channels/irc")}`,
462
462
  ].join("\n"),
463
463
  "IRC next steps",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/line",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot LINE channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/llm-task",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot JSON-only LLM task plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/lobster",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
6
6
  "poolbot": {
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/matrix",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Matrix channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/mattermost",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Mattermost channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/memory-core",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot core memory search plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/memory-lancedb",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot LanceDB-backed long-term memory plugin with auto-recall/capture",
6
6
  "dependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/minimax-portal-auth",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "private": true,
5
5
  "description": "Pool Bot MiniMax Portal OAuth provider plugin",
6
6
  "type": "module",
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/msteams",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Microsoft Teams channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/nextcloud-talk",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Nextcloud Talk channel plugin",
6
6
  "poolbot": {
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/nostr",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Nostr channel plugin for NIP-04 encrypted DMs",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/open-prose",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "OpenProse VM skill pack plugin (slash command + telemetry).",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/openai-codex-auth",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "private": true,
5
5
  "description": "OpenAI Codex CLI auth provider plugin - use ChatGPT Plus/Pro subscription for OpenAI models",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/signal",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Signal channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/slack",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Slack channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/telegram",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Telegram channel plugin",
6
6
  "poolbot": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/tlon",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Tlon/Urbit channel plugin",
6
6
  "poolbot": {
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/twitch",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "description": "Poolbot Twitch channel plugin",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/voice-call",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot voice-call plugin",
6
6
  "dependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/whatsapp",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot WhatsApp channel plugin",
6
6
  "poolbot": {
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/zalo",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Zalo channel plugin",
6
6
  "poolbot": {
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.2.23
4
+
5
+ ### Changes
6
+ - Version alignment with core Poolbot release numbers.
7
+
3
8
  ## 2026.2.22
4
9
 
5
10
  ### Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolbot/zalouser",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "type": "module",
5
5
  "description": "Poolbot Zalo Personal Account plugin via zca-cli",
6
6
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/pool-bot",
3
- "version": "2026.2.22",
3
+ "version": "2026.2.23",
4
4
  "description": "🎱 Pool Bot - AI assistant with PLCODE integrations",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -1,151 +0,0 @@
1
- import { resolvePluginTools } from "../plugins/tools.js";
2
- import { resolveSessionAgentId } from "./agent-scope.js";
3
- import { createAgentsListTool } from "./tools/agents-list-tool.js";
4
- import { createBrowserTool } from "./tools/browser-tool.js";
5
- import { createCanvasTool } from "./tools/canvas-tool.js";
6
- import { createCronTool } from "./tools/cron-tool.js";
7
- import { createGatewayTool } from "./tools/gateway-tool.js";
8
- import { createDeepResearchTool } from "./tools/deep-research-tool.js";
9
- import { createImageGenerateTool } from "./tools/image-generate-tool.js";
10
- import { createImageTool } from "./tools/image-tool.js";
11
- import { createMessageTool } from "./tools/message-tool.js";
12
- import { createNodesTool } from "./tools/nodes-tool.js";
13
- import { createSessionStatusTool } from "./tools/session-status-tool.js";
14
- import { createSessionsHistoryTool } from "./tools/sessions-history-tool.js";
15
- import { createSessionsListTool } from "./tools/sessions-list-tool.js";
16
- import { createSessionsSendTool } from "./tools/sessions-send-tool.js";
17
- import { createSessionsSpawnTool } from "./tools/sessions-spawn-tool.js";
18
- import { createSubagentsTool } from "./tools/subagents-tool.js";
19
- import { createTtsTool } from "./tools/tts-tool.js";
20
- import { createWebFetchTool, createWebSearchTool } from "./tools/web-tools.js";
21
- import { resolveWorkspaceRoot } from "./workspace-dir.js";
22
- export function createOpenClawTools(options) {
23
- const workspaceDir = resolveWorkspaceRoot(options?.workspaceDir);
24
- const imageTool = options?.agentDir?.trim()
25
- ? createImageTool({
26
- config: options?.config,
27
- agentDir: options.agentDir,
28
- workspaceDir,
29
- sandbox: options?.sandboxRoot && options?.sandboxFsBridge
30
- ? { root: options.sandboxRoot, bridge: options.sandboxFsBridge }
31
- : undefined,
32
- modelHasVision: options?.modelHasVision,
33
- })
34
- : null;
35
- const imageGenerateTool = createImageGenerateTool({
36
- config: options?.config,
37
- agentDir: options?.agentDir,
38
- sandboxRoot: options?.sandboxRoot,
39
- });
40
- const webSearchTool = createWebSearchTool({
41
- config: options?.config,
42
- sandboxed: options?.sandboxed,
43
- });
44
- const webFetchTool = createWebFetchTool({
45
- config: options?.config,
46
- sandboxed: options?.sandboxed,
47
- });
48
- const messageTool = options?.disableMessageTool
49
- ? null
50
- : createMessageTool({
51
- agentAccountId: options?.agentAccountId,
52
- agentSessionKey: options?.agentSessionKey,
53
- config: options?.config,
54
- currentChannelId: options?.currentChannelId,
55
- currentChannelProvider: options?.agentChannel,
56
- currentThreadTs: options?.currentThreadTs,
57
- replyToMode: options?.replyToMode,
58
- hasRepliedRef: options?.hasRepliedRef,
59
- sandboxRoot: options?.sandboxRoot,
60
- requireExplicitTarget: options?.requireExplicitMessageTarget,
61
- });
62
- const tools = [
63
- createBrowserTool({
64
- sandboxBridgeUrl: options?.sandboxBrowserBridgeUrl,
65
- allowHostControl: options?.allowHostBrowserControl,
66
- }),
67
- createCanvasTool(),
68
- createNodesTool({
69
- agentSessionKey: options?.agentSessionKey,
70
- config: options?.config,
71
- }),
72
- createCronTool({
73
- agentSessionKey: options?.agentSessionKey,
74
- }),
75
- ...(messageTool ? [messageTool] : []),
76
- createTtsTool({
77
- agentChannel: options?.agentChannel,
78
- config: options?.config,
79
- }),
80
- createGatewayTool({
81
- agentSessionKey: options?.agentSessionKey,
82
- config: options?.config,
83
- }),
84
- createAgentsListTool({
85
- agentSessionKey: options?.agentSessionKey,
86
- requesterAgentIdOverride: options?.requesterAgentIdOverride,
87
- }),
88
- createSessionsListTool({
89
- agentSessionKey: options?.agentSessionKey,
90
- sandboxed: options?.sandboxed,
91
- }),
92
- createSessionsHistoryTool({
93
- agentSessionKey: options?.agentSessionKey,
94
- sandboxed: options?.sandboxed,
95
- }),
96
- createSessionsSendTool({
97
- agentSessionKey: options?.agentSessionKey,
98
- agentChannel: options?.agentChannel,
99
- sandboxed: options?.sandboxed,
100
- }),
101
- createSessionsSpawnTool({
102
- agentSessionKey: options?.agentSessionKey,
103
- agentChannel: options?.agentChannel,
104
- agentAccountId: options?.agentAccountId,
105
- agentTo: options?.agentTo,
106
- agentThreadId: options?.agentThreadId,
107
- agentGroupId: options?.agentGroupId,
108
- agentGroupChannel: options?.agentGroupChannel,
109
- agentGroupSpace: options?.agentGroupSpace,
110
- sandboxed: options?.sandboxed,
111
- requesterAgentIdOverride: options?.requesterAgentIdOverride,
112
- }),
113
- createSubagentsTool({
114
- agentSessionKey: options?.agentSessionKey,
115
- }),
116
- createSessionStatusTool({
117
- agentSessionKey: options?.agentSessionKey,
118
- config: options?.config,
119
- }),
120
- ...(webSearchTool ? [webSearchTool] : []),
121
- ...(webFetchTool ? [webFetchTool] : []),
122
- ...(imageTool ? [imageTool] : []),
123
- ...(imageGenerateTool ? [imageGenerateTool] : []),
124
- ];
125
- // Z.AI-powered research tool (gracefully absent when no key configured)
126
- const deepResearchTool = createDeepResearchTool({
127
- config: options?.config,
128
- agentDir: options?.agentDir,
129
- sandboxRoot: options?.sandboxRoot,
130
- });
131
- if (deepResearchTool)
132
- tools.push(deepResearchTool);
133
- const pluginTools = resolvePluginTools({
134
- context: {
135
- config: options?.config,
136
- workspaceDir,
137
- agentDir: options?.agentDir,
138
- agentId: resolveSessionAgentId({
139
- sessionKey: options?.agentSessionKey,
140
- config: options?.config,
141
- }),
142
- sessionKey: options?.agentSessionKey,
143
- messageChannel: options?.agentChannel,
144
- agentAccountId: options?.agentAccountId,
145
- sandboxed: options?.sandboxed,
146
- },
147
- existingToolNames: new Set(tools.map((tool) => tool.name)),
148
- toolAllowlist: options?.pluginToolAllowlist,
149
- });
150
- return [...tools, ...pluginTools];
151
- }
@@ -1,96 +0,0 @@
1
- /**
2
- * Tool Security - Tool Gating and Access Control
3
- *
4
- * Based on OpenClaw 2026.2.4 security fixes:
5
- * - Gate sensitive tools to owner senders only
6
- * - Prevent tool hijacking by non-owners
7
- *
8
- * @version 2026.1.30
9
- */
10
- /**
11
- * List of sensitive tools that require owner permissions
12
- */
13
- export const SENSITIVE_TOOLS = [
14
- // WhatsApp
15
- "whatsapp_login",
16
- // Gateway management
17
- "gateway",
18
- "gateway:restart",
19
- "gateway:update",
20
- // Config management
21
- "gateway:config:apply",
22
- "gateway:config:patch",
23
- // Cron management
24
- "cron:add",
25
- "cron:remove",
26
- "cron:update",
27
- // Session management
28
- "sessions_spawn", // Pode criar sub-agentes
29
- ];
30
- /**
31
- * Check if a tool is sensitive (requires owner permission)
32
- */
33
- export function isSensitiveTool(toolName) {
34
- const normalized = toolName.trim().toLowerCase();
35
- return SENSITIVE_TOOLS.some((tool) => {
36
- const normalizedTool = tool.toLowerCase();
37
- // Exact match ou prefix match (ex: "gateway" match "gateway:restart")
38
- return normalized === normalizedTool || normalized.startsWith(`${normalizedTool}:`);
39
- });
40
- }
41
- /**
42
- * Check if a sender is an owner
43
- *
44
- * Owners are configured in poolbot.json:
45
- * {
46
- * "security": {
47
- * "owners": ["+554498569337", "5140768830"]
48
- * }
49
- * }
50
- */
51
- export function isOwner(sender, owners = []) {
52
- if (!sender)
53
- return false;
54
- const normalizedSender = sender.trim();
55
- if (!normalizedSender)
56
- return false;
57
- // Check if sender is in owners list
58
- return owners.some((owner) => {
59
- const normalizedOwner = owner.trim();
60
- return normalizedOwner === normalizedSender;
61
- });
62
- }
63
- /**
64
- * Check if a user can use a tool
65
- *
66
- * @param toolName - Tool name (ex: "whatsapp_login")
67
- * @param sender - Sender identifier (phone number, user ID, etc.)
68
- * @param owners - List of owner identifiers
69
- * @returns true if user can use the tool, false otherwise
70
- */
71
- export function canUseTool(toolName, sender, owners = []) {
72
- // Non-sensitive tools são permitidas para todos
73
- if (!isSensitiveTool(toolName)) {
74
- return true;
75
- }
76
- // Sensitive tools requerem owner permission
77
- return isOwner(sender, owners);
78
- }
79
- /**
80
- * Error message for denied tool access
81
- */
82
- export function toolAccessDeniedMessage(toolName) {
83
- return (`Tool "${toolName}" is restricted to owners only. ` +
84
- `This tool requires owner permissions for security reasons. ` +
85
- `Contact the bot owner for access.`);
86
- }
87
- /**
88
- * Validate tool access and throw if denied
89
- *
90
- * @throws Error if access is denied
91
- */
92
- export function validateToolAccess(toolName, sender, owners = []) {
93
- if (!canUseTool(toolName, sender, owners)) {
94
- throw new Error(toolAccessDeniedMessage(toolName));
95
- }
96
- }
@@ -1,94 +0,0 @@
1
- /**
2
- * Gateway URL Override Security
3
- * Prevents credential leakage via gateway URL redirects
4
- *
5
- * Based on OpenClaw 2026.2.4 security fix:
6
- * - Require explicit credentials for gateway URL overrides
7
- *
8
- * @version 2026.1.30
9
- */
10
- /**
11
- * Default gateway URLs (considered safe)
12
- */
13
- export const DEFAULT_GATEWAY_URLS = [
14
- "http://127.0.0.1:18789",
15
- "http://localhost:18789",
16
- "http://[::1]:18789",
17
- ];
18
- /**
19
- * Minimum token length for security
20
- */
21
- export const MIN_TOKEN_LENGTH = 32;
22
- /**
23
- * Check if URL is a default/safe gateway URL
24
- */
25
- export function isDefaultGatewayUrl(url) {
26
- if (!url)
27
- return true; // No URL means use default
28
- const normalized = url.trim().toLowerCase();
29
- return DEFAULT_GATEWAY_URLS.some((defaultUrl) => normalized === defaultUrl.toLowerCase());
30
- }
31
- /**
32
- * Validate gateway URL override security
33
- *
34
- * @param config - Gateway configuration
35
- * @throws Error if security requirements are not met
36
- *
37
- * @example
38
- * ```typescript
39
- * // Safe: Using default URL
40
- * validateGatewayUrlSecurity({ url: "http://localhost:18789" });
41
- *
42
- * // Safe: Custom URL with explicit token
43
- * validateGatewayUrlSecurity({
44
- * url: "http://custom.gateway.com",
45
- * token: "very-long-secure-token-32chars+",
46
- * requireExplicitToken: true
47
- * });
48
- *
49
- * // Unsafe: Custom URL without explicit flag
50
- * validateGatewayUrlSecurity({
51
- * url: "http://malicious.com",
52
- * token: "token"
53
- * });
54
- * // Throws: "Gateway URL override requires explicit token flag"
55
- * ```
56
- */
57
- export function validateGatewayUrlSecurity(config) {
58
- // If URL is default/safe, no additional validation needed
59
- if (isDefaultGatewayUrl(config.url)) {
60
- return;
61
- }
62
- // Custom URL detected - require explicit confirmation
63
- if (!config.requireExplicitToken) {
64
- throw new Error("Gateway URL override requires explicit token flag. " +
65
- "Set 'requireExplicitToken: true' in your gateway config to confirm " +
66
- "you want to use a custom gateway URL. This prevents accidental " +
67
- "credential leakage to untrusted gateways.");
68
- }
69
- // Require token when using custom URL
70
- if (!config.token) {
71
- throw new Error("Gateway URL override requires a token. " +
72
- "Provide a secure token when using a custom gateway URL.");
73
- }
74
- // Require strong token (32+ characters)
75
- if (config.token.length < MIN_TOKEN_LENGTH) {
76
- throw new Error(`Gateway URL override requires a strong token (${MIN_TOKEN_LENGTH}+ characters). ` +
77
- `Current token length: ${config.token.length} characters.`);
78
- }
79
- }
80
- /**
81
- * Check if gateway config is safe without throwing
82
- *
83
- * @param config - Gateway configuration
84
- * @returns true if config is safe, false otherwise
85
- */
86
- export function isGatewayConfigSafe(config) {
87
- try {
88
- validateGatewayUrlSecurity(config);
89
- return true;
90
- }
91
- catch {
92
- return false;
93
- }
94
- }
@@ -1,109 +0,0 @@
1
- import fsSync from "node:fs";
2
- import fs from "node:fs/promises";
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- const CORE_PACKAGE_NAMES = new Set(["poolbot"]);
6
- async function readPackageName(dir) {
7
- try {
8
- const raw = await fs.readFile(path.join(dir, "package.json"), "utf-8");
9
- const parsed = JSON.parse(raw);
10
- return typeof parsed.name === "string" ? parsed.name : null;
11
- }
12
- catch {
13
- return null;
14
- }
15
- }
16
- function readPackageNameSync(dir) {
17
- try {
18
- const raw = fsSync.readFileSync(path.join(dir, "package.json"), "utf-8");
19
- const parsed = JSON.parse(raw);
20
- return typeof parsed.name === "string" ? parsed.name : null;
21
- }
22
- catch {
23
- return null;
24
- }
25
- }
26
- async function findPackageRoot(startDir, maxDepth = 12) {
27
- let current = path.resolve(startDir);
28
- for (let i = 0; i < maxDepth; i += 1) {
29
- const name = await readPackageName(current);
30
- if (name && CORE_PACKAGE_NAMES.has(name)) {
31
- return current;
32
- }
33
- const parent = path.dirname(current);
34
- if (parent === current) {
35
- break;
36
- }
37
- current = parent;
38
- }
39
- return null;
40
- }
41
- function findPackageRootSync(startDir, maxDepth = 12) {
42
- let current = path.resolve(startDir);
43
- for (let i = 0; i < maxDepth; i += 1) {
44
- const name = readPackageNameSync(current);
45
- if (name && CORE_PACKAGE_NAMES.has(name)) {
46
- return current;
47
- }
48
- const parent = path.dirname(current);
49
- if (parent === current) {
50
- break;
51
- }
52
- current = parent;
53
- }
54
- return null;
55
- }
56
- function candidateDirsFromArgv1(argv1) {
57
- const normalized = path.resolve(argv1);
58
- const candidates = [path.dirname(normalized)];
59
- // Resolve symlinks for version managers (nvm, fnm, n, Homebrew/Linuxbrew)
60
- // that create symlinks in bin/ pointing to the real package location.
61
- try {
62
- const resolved = fsSync.realpathSync(normalized);
63
- if (resolved !== normalized) {
64
- candidates.push(path.dirname(resolved));
65
- }
66
- }
67
- catch {
68
- // realpathSync throws if path doesn't exist; keep original candidates
69
- }
70
- const parts = normalized.split(path.sep);
71
- const binIndex = parts.lastIndexOf(".bin");
72
- if (binIndex > 0 && parts[binIndex - 1] === "node_modules") {
73
- const binName = path.basename(normalized);
74
- const nodeModulesDir = parts.slice(0, binIndex).join(path.sep);
75
- candidates.push(path.join(nodeModulesDir, binName));
76
- }
77
- return candidates;
78
- }
79
- export async function resolveOpenClawPackageRoot(opts) {
80
- for (const candidate of buildCandidates(opts)) {
81
- const found = await findPackageRoot(candidate);
82
- if (found) {
83
- return found;
84
- }
85
- }
86
- return null;
87
- }
88
- export function resolveOpenClawPackageRootSync(opts) {
89
- for (const candidate of buildCandidates(opts)) {
90
- const found = findPackageRootSync(candidate);
91
- if (found) {
92
- return found;
93
- }
94
- }
95
- return null;
96
- }
97
- function buildCandidates(opts) {
98
- const candidates = [];
99
- if (opts.moduleUrl) {
100
- candidates.push(path.dirname(fileURLToPath(opts.moduleUrl)));
101
- }
102
- if (opts.argv1) {
103
- candidates.push(...candidateDirsFromArgv1(opts.argv1));
104
- }
105
- if (opts.cwd) {
106
- candidates.push(opts.cwd);
107
- }
108
- return candidates;
109
- }
@@ -1,81 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- export const POSIX_POOLBOT_TMP_DIR = "/tmp/openclaw";
5
- function isNodeErrorWithCode(err, code) {
6
- return (typeof err === "object" &&
7
- err !== null &&
8
- "code" in err &&
9
- err.code === code);
10
- }
11
- export function resolvePreferredOpenClawTmpDir(options = {}) {
12
- const accessSync = options.accessSync ?? fs.accessSync;
13
- const lstatSync = options.lstatSync ?? fs.lstatSync;
14
- const mkdirSync = options.mkdirSync ?? fs.mkdirSync;
15
- const getuid = options.getuid ??
16
- (() => {
17
- try {
18
- return typeof process.getuid === "function" ? process.getuid() : undefined;
19
- }
20
- catch {
21
- return undefined;
22
- }
23
- });
24
- const tmpdir = options.tmpdir ?? os.tmpdir;
25
- const uid = getuid();
26
- const isSecureDirForUser = (st) => {
27
- if (uid === undefined) {
28
- return true;
29
- }
30
- if (typeof st.uid === "number" && st.uid !== uid) {
31
- return false;
32
- }
33
- // Avoid group/other writable dirs when running on multi-user hosts.
34
- if (typeof st.mode === "number" && (st.mode & 0o022) !== 0) {
35
- return false;
36
- }
37
- return true;
38
- };
39
- const fallback = () => {
40
- const base = tmpdir();
41
- const suffix = uid === undefined ? "poolbot" : `openclaw-${uid}`;
42
- return path.join(base, suffix);
43
- };
44
- try {
45
- const preferred = lstatSync(POSIX_POOLBOT_TMP_DIR);
46
- if (!preferred.isDirectory() || preferred.isSymbolicLink()) {
47
- return fallback();
48
- }
49
- accessSync(POSIX_POOLBOT_TMP_DIR, fs.constants.W_OK | fs.constants.X_OK);
50
- if (!isSecureDirForUser(preferred)) {
51
- return fallback();
52
- }
53
- return POSIX_POOLBOT_TMP_DIR;
54
- }
55
- catch (err) {
56
- if (!isNodeErrorWithCode(err, "ENOENT")) {
57
- return fallback();
58
- }
59
- }
60
- try {
61
- accessSync("/tmp", fs.constants.W_OK | fs.constants.X_OK);
62
- // Create with a safe default; subsequent callers expect it exists.
63
- mkdirSync(POSIX_POOLBOT_TMP_DIR, { recursive: true, mode: 0o700 });
64
- try {
65
- const preferred = lstatSync(POSIX_POOLBOT_TMP_DIR);
66
- if (!preferred.isDirectory() || preferred.isSymbolicLink()) {
67
- return fallback();
68
- }
69
- if (!isSecureDirForUser(preferred)) {
70
- return fallback();
71
- }
72
- }
73
- catch {
74
- return fallback();
75
- }
76
- return POSIX_POOLBOT_TMP_DIR;
77
- }
78
- catch {
79
- return fallback();
80
- }
81
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * Media Path Sanitization
3
- * Prevents path traversal attacks in media attachments
4
- *
5
- * Based on OpenClaw 2026.2.4 security fix:
6
- * - Enforce sandboxed media paths for message tool attachments
7
- *
8
- * @version 2026.1.30
9
- */
10
- import path from "node:path";
11
- import fs from "node:fs";
12
- /**
13
- * Sanitize media path to prevent path traversal
14
- *
15
- * @param inputPath - User-provided path (may contain ../ or absolute paths)
16
- * @param baseDir - Base directory for media files (sandbox root)
17
- * @returns Sanitized absolute path within baseDir
18
- * @throws Error if path is outside baseDir or file doesn't exist
19
- *
20
- * @example
21
- * ```typescript
22
- * // Safe usage:
23
- * const safe = sanitizeMediaPath("photo.jpg", "/root/.poolbot/media/");
24
- * // Returns: "/root/.poolbot/media/photo.jpg"
25
- *
26
- * // Blocked (path traversal):
27
- * sanitizeMediaPath("../../etc/passwd", "/root/.poolbot/media/");
28
- * // Throws: "Path traversal detected"
29
- * ```
30
- */
31
- export function sanitizeMediaPath(inputPath, baseDir) {
32
- // 1. Normalize base directory (ensure trailing slash)
33
- const normalizedBase = path.resolve(baseDir);
34
- // 2. Resolve absolute path (follows ../ and resolves relative paths)
35
- const resolved = path.resolve(normalizedBase, inputPath);
36
- // 3. Security check: must be within baseDir
37
- if (!resolved.startsWith(normalizedBase + path.sep) && resolved !== normalizedBase) {
38
- throw new Error(`Path traversal detected: "${inputPath}" resolves to "${resolved}" ` +
39
- `which is outside the allowed directory "${normalizedBase}"`);
40
- }
41
- // 4. Check if file exists
42
- if (!fs.existsSync(resolved)) {
43
- throw new Error(`File not found: ${inputPath}`);
44
- }
45
- // 5. Check if it's a file (not directory)
46
- const stats = fs.statSync(resolved);
47
- if (!stats.isFile()) {
48
- throw new Error(`Path is not a file: ${inputPath}`);
49
- }
50
- return resolved;
51
- }
52
- /**
53
- * Sanitize multiple media paths
54
- *
55
- * @param inputPaths - Array of user-provided paths
56
- * @param baseDir - Base directory for media files
57
- * @returns Array of sanitized paths
58
- * @throws Error if any path is invalid
59
- */
60
- export function sanitizeMediaPaths(inputPaths, baseDir) {
61
- return inputPaths.map((p) => sanitizeMediaPath(p, baseDir));
62
- }
63
- /**
64
- * Check if path is safe without throwing
65
- *
66
- * @param inputPath - User-provided path
67
- * @param baseDir - Base directory
68
- * @returns true if path is safe, false otherwise
69
- */
70
- export function isMediaPathSafe(inputPath, baseDir) {
71
- try {
72
- sanitizeMediaPath(inputPath, baseDir);
73
- return true;
74
- }
75
- catch {
76
- return false;
77
- }
78
- }