@poolzin/pool-bot 2026.3.6 → 2026.3.9

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 (68) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/.buildstamp +1 -1
  3. package/dist/agents/error-classifier.js +302 -0
  4. package/dist/agents/pi-tools.js +32 -2
  5. package/dist/agents/skills/security.js +217 -0
  6. package/dist/auto-reply/reply/get-reply.js +6 -0
  7. package/dist/auto-reply/reply/message-preprocess-hooks.js +17 -0
  8. package/dist/build-info.json +3 -3
  9. package/dist/cli/banner.js +20 -1
  10. package/dist/cli/lazy-commands.example.js +113 -0
  11. package/dist/cli/lazy-commands.js +329 -0
  12. package/dist/cli/program/command-registry.js +13 -0
  13. package/dist/cli/program/register.skills.js +4 -0
  14. package/dist/cli/security-cli.js +211 -2
  15. package/dist/cli/tagline.js +7 -0
  16. package/dist/config/config.js +1 -0
  17. package/dist/config/secrets-integration.js +88 -0
  18. package/dist/config/types.cli.js +1 -0
  19. package/dist/config/types.security.js +33 -0
  20. package/dist/config/zod-schema.js +15 -0
  21. package/dist/config/zod-schema.providers-core.js +1 -0
  22. package/dist/config/zod-schema.security.js +113 -0
  23. package/dist/context-engine/index.js +33 -0
  24. package/dist/context-engine/legacy.js +181 -0
  25. package/dist/context-engine/registry.js +86 -0
  26. package/dist/context-engine/summarizing.js +293 -0
  27. package/dist/context-engine/types.js +7 -0
  28. package/dist/discord/monitor/message-handler.preflight.js +11 -2
  29. package/dist/gateway/http-common.js +6 -1
  30. package/dist/hooks/fire-and-forget.js +6 -0
  31. package/dist/hooks/internal-hooks.js +64 -19
  32. package/dist/hooks/message-hook-mappers.js +179 -0
  33. package/dist/infra/abort-pattern.js +106 -0
  34. package/dist/infra/retry.js +94 -0
  35. package/dist/secrets/index.js +28 -0
  36. package/dist/secrets/resolver.js +185 -0
  37. package/dist/secrets/runtime.js +142 -0
  38. package/dist/secrets/types.js +11 -0
  39. package/dist/security/capability-guards.js +89 -0
  40. package/dist/security/capability-manager.js +76 -0
  41. package/dist/security/capability.js +147 -0
  42. package/dist/security/dangerous-tools.js +80 -0
  43. package/dist/security/index.js +7 -0
  44. package/dist/security/middleware.js +105 -0
  45. package/dist/security/types.js +12 -0
  46. package/dist/skills/commands.js +351 -0
  47. package/dist/skills/index.js +167 -0
  48. package/dist/skills/loader.js +282 -0
  49. package/dist/skills/parser.js +461 -0
  50. package/dist/skills/registry.js +397 -0
  51. package/dist/skills/security.js +318 -0
  52. package/dist/skills/types.js +21 -0
  53. package/dist/slack/monitor/context.js +1 -0
  54. package/dist/slack/monitor/message-handler/dispatch.js +14 -1
  55. package/dist/slack/monitor/provider.js +2 -0
  56. package/dist/test-utils/index.js +219 -0
  57. package/dist/tui/index.js +595 -0
  58. package/docs/INTEGRATION_PLAN.md +475 -0
  59. package/docs/INTEGRATION_SUMMARY.md +215 -0
  60. package/docs/integrations/HEXSTRIKE_PLAN.md +796 -0
  61. package/docs/integrations/INTEGRATION_PLAN.md +424 -0
  62. package/docs/integrations/PAGE_AGENT_PLAN.md +370 -0
  63. package/docs/integrations/XYOPS_PLAN.md +978 -0
  64. package/docs/skills/IMPLEMENTATION_SUMMARY.md +145 -0
  65. package/docs/skills/SKILL.md +524 -0
  66. package/docs/skills.md +405 -0
  67. package/package.json +1 -1
  68. package/skills/example-skill/SKILL.md +195 -0
@@ -0,0 +1,76 @@
1
+ import { capabilityMatches, CapabilityResult } from "./capability.js";
2
+ /**
3
+ * Manages capability grants for all agents.
4
+ * Uses a Map for O(1) lookups. Thread-safe for single-threaded Node.js.
5
+ */
6
+ export class CapabilityManager {
7
+ grants = new Map();
8
+ /** Grant capabilities to an agent. Replaces any existing grants. */
9
+ grant(agentId, capabilities) {
10
+ this.grants.set(agentId, capabilities);
11
+ }
12
+ /** Add capabilities to an agent's existing grants. */
13
+ add(agentId, capabilities) {
14
+ const existing = this.grants.get(agentId) ?? [];
15
+ this.grants.set(agentId, [...existing, ...capabilities]);
16
+ }
17
+ /** Check whether an agent has a specific capability. */
18
+ check(agentId, required) {
19
+ const grants = this.grants.get(agentId);
20
+ if (!grants) {
21
+ return CapabilityResult.denied(`No capabilities registered for agent ${agentId}`);
22
+ }
23
+ for (const granted of grants) {
24
+ if (capabilityMatches(granted, required)) {
25
+ return CapabilityResult.granted();
26
+ }
27
+ }
28
+ return CapabilityResult.denied(`Agent ${agentId} does not have capability: ${JSON.stringify(required)}`);
29
+ }
30
+ /** Check multiple capabilities at once. Returns first denial or grants all. */
31
+ checkAll(agentId, required) {
32
+ for (const req of required) {
33
+ const result = this.check(agentId, req);
34
+ if (!result.granted)
35
+ return result;
36
+ }
37
+ return CapabilityResult.granted();
38
+ }
39
+ /** List all capabilities for an agent. */
40
+ list(agentId) {
41
+ return this.grants.get(agentId) ?? [];
42
+ }
43
+ /** Remove all capabilities for an agent. */
44
+ revokeAll(agentId) {
45
+ this.grants.delete(agentId);
46
+ }
47
+ /** Check if an agent has any capabilities registered. */
48
+ has(agentId) {
49
+ return this.grants.has(agentId);
50
+ }
51
+ /** Get all registered agent IDs. */
52
+ agents() {
53
+ return Array.from(this.grants.keys());
54
+ }
55
+ /** Clear all grants. */
56
+ clear() {
57
+ this.grants.clear();
58
+ }
59
+ }
60
+ /** Global singleton instance. */
61
+ let globalManager;
62
+ /** Get or create the global capability manager. */
63
+ export function getCapabilityManager() {
64
+ if (!globalManager) {
65
+ globalManager = new CapabilityManager();
66
+ }
67
+ return globalManager;
68
+ }
69
+ /** Reset the global manager (useful for testing). */
70
+ export function resetCapabilityManager() {
71
+ globalManager = undefined;
72
+ }
73
+ /** Set a custom global manager (useful for testing). */
74
+ export function setCapabilityManager(manager) {
75
+ globalManager = manager;
76
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Capability-based security system for Pool Bot.
3
+ *
4
+ * Inspired by OpenFang's capability system, adapted for TypeScript.
5
+ * Agents can only perform actions they've been explicitly granted permission for.
6
+ * Capabilities are immutable after agent creation and enforced at runtime.
7
+ */
8
+ /** All available capability types for CLI and validation. */
9
+ export const CAPABILITY_TYPES = [
10
+ // File system
11
+ "file:read",
12
+ "file:write",
13
+ // Network
14
+ "net:connect",
15
+ "net:listen",
16
+ // Tools
17
+ "tool:invoke",
18
+ "tool:all",
19
+ // LLM
20
+ "llm:query",
21
+ "llm:maxTokens",
22
+ // Agent interaction
23
+ "agent:spawn",
24
+ "agent:message",
25
+ "agent:kill",
26
+ // Memory
27
+ "memory:read",
28
+ "memory:write",
29
+ // Shell
30
+ "shell:exec",
31
+ "env:read",
32
+ // Gateway
33
+ "gateway:admin",
34
+ "gateway:channels:read",
35
+ "gateway:channels:write",
36
+ // Economic
37
+ "econ:spend",
38
+ "econ:earn",
39
+ "econ:transfer",
40
+ ];
41
+ /** Helper to create capability check results. */
42
+ export const CapabilityResult = {
43
+ granted() {
44
+ return { granted: true };
45
+ },
46
+ denied(reason) {
47
+ return { granted: false, reason };
48
+ },
49
+ };
50
+ /** Simple glob pattern matching supporting '*' as wildcard. */
51
+ export function globMatches(pattern, value) {
52
+ if (pattern === "*")
53
+ return true;
54
+ if (pattern === value)
55
+ return true;
56
+ // Prefix wildcard: "*.example.com"
57
+ if (pattern.startsWith("*")) {
58
+ const suffix = pattern.slice(1);
59
+ return value.endsWith(suffix);
60
+ }
61
+ // Suffix wildcard: "api.*"
62
+ if (pattern.endsWith("*")) {
63
+ const prefix = pattern.slice(0, -1);
64
+ return value.startsWith(prefix);
65
+ }
66
+ // Middle wildcard: "api.*.com"
67
+ const starPos = pattern.indexOf("*");
68
+ if (starPos !== -1) {
69
+ const prefix = pattern.slice(0, starPos);
70
+ const suffix = pattern.slice(starPos + 1);
71
+ return (value.startsWith(prefix) &&
72
+ value.endsWith(suffix) &&
73
+ value.length >= prefix.length + suffix.length);
74
+ }
75
+ return false;
76
+ }
77
+ /**
78
+ * Check whether a required capability matches any granted capability.
79
+ */
80
+ export function capabilityMatches(granted, required) {
81
+ // Tool:all grants any specific tool
82
+ if (granted.type === "tool:all" && required.type === "tool:invoke") {
83
+ return true;
84
+ }
85
+ // Same variant type matching
86
+ if (granted.type !== required.type)
87
+ return false;
88
+ switch (granted.type) {
89
+ case "file:read":
90
+ case "file:write":
91
+ return globMatches(granted.pattern, required.pattern);
92
+ case "net:connect":
93
+ return globMatches(granted.pattern, required.pattern);
94
+ case "net:listen":
95
+ return granted.port === required.port;
96
+ case "tool:invoke":
97
+ return granted.toolId === required.toolId || granted.toolId === "*";
98
+ case "llm:query":
99
+ return globMatches(granted.pattern, required.pattern);
100
+ case "llm:maxTokens":
101
+ return granted.limit >= required.limit;
102
+ case "agent:spawn":
103
+ return true;
104
+ case "agent:message":
105
+ case "agent:kill":
106
+ return globMatches(granted.pattern, required.pattern);
107
+ case "memory:read":
108
+ case "memory:write":
109
+ return globMatches(granted.scope, required.scope);
110
+ case "shell:exec":
111
+ return globMatches(granted.pattern, required.pattern);
112
+ case "env:read":
113
+ return globMatches(granted.pattern, required.pattern);
114
+ case "gateway:admin":
115
+ case "gateway:channels:read":
116
+ return true;
117
+ case "gateway:channels:write":
118
+ return globMatches(granted.pattern, required.pattern);
119
+ case "econ:spend":
120
+ return granted.limit >= required.limit;
121
+ case "econ:earn":
122
+ return true;
123
+ case "econ:transfer":
124
+ return globMatches(granted.pattern, required.pattern);
125
+ case "tool:all":
126
+ // tool:all only matches tool:all (already handled above for tool:invoke)
127
+ return false;
128
+ default:
129
+ return false;
130
+ }
131
+ }
132
+ /**
133
+ * Validate that child capabilities are a subset of parent capabilities.
134
+ * Prevents privilege escalation.
135
+ */
136
+ export function validateCapabilityInheritance(parentCaps, childCaps) {
137
+ for (const childCap of childCaps) {
138
+ const isCovered = parentCaps.some((parentCap) => capabilityMatches(parentCap, childCap));
139
+ if (!isCovered) {
140
+ return {
141
+ valid: false,
142
+ reason: `Privilege escalation denied: child requests ${JSON.stringify(childCap)} but parent does not have a matching grant`,
143
+ };
144
+ }
145
+ }
146
+ return { valid: true };
147
+ }
@@ -14,6 +14,20 @@ export const DEFAULT_GATEWAY_HTTP_TOOL_DENY = [
14
14
  "gateway",
15
15
  // Interactive setup — requires terminal QR scan, hangs on HTTP
16
16
  "whatsapp_login",
17
+ // Cron automation — scheduling can be used for persistence
18
+ "cron",
19
+ // Exec tools — remote code execution risk
20
+ "exec",
21
+ "shell",
22
+ "spawn",
23
+ // File system mutations
24
+ "fs_write",
25
+ "fs_delete",
26
+ "fs_move",
27
+ "apply_patch",
28
+ // Device pairing
29
+ "device_pair",
30
+ "pair_device",
17
31
  ];
18
32
  /**
19
33
  * ACP tools that should always require explicit user approval.
@@ -30,5 +44,71 @@ export const DANGEROUS_ACP_TOOL_NAMES = [
30
44
  "fs_delete",
31
45
  "fs_move",
32
46
  "apply_patch",
47
+ "cron",
48
+ "exec_approved",
49
+ "elevated_exec",
33
50
  ];
34
51
  export const DANGEROUS_ACP_TOOLS = new Set(DANGEROUS_ACP_TOOL_NAMES);
52
+ /**
53
+ * Tool categories by risk level
54
+ */
55
+ export const TOOL_CATEGORIES = {
56
+ /** Execution tools - can run arbitrary code */
57
+ EXECUTION: ["exec", "spawn", "shell", "exec_approved", "elevated_exec"],
58
+ /** File system mutators - can modify files */
59
+ FILE_MUTATORS: ["fs_write", "fs_delete", "fs_move", "apply_patch", "fs_mkdir", "fs_rename"],
60
+ /** Session orchestrators - can spawn/control sessions */
61
+ SESSION_ORCHESTRATORS: ["sessions_spawn", "sessions_send", "sessions_kill", "sessions_reset"],
62
+ /** Gateway control - can reconfigure gateway */
63
+ GATEWAY_CONTROL: ["gateway", "config_set", "config_reload"],
64
+ /** Automation - can schedule/automate */
65
+ AUTOMATION: ["cron", "hook_register", "automation_create"],
66
+ /** External integrations - can interact with external services */
67
+ EXTERNAL: ["whatsapp_login", "device_pair", "pair_device", "oauth_flow"],
68
+ };
69
+ /**
70
+ * Check if a tool is in a specific category
71
+ */
72
+ export function isToolInCategory(toolName, category) {
73
+ return TOOL_CATEGORIES[category].includes(toolName);
74
+ }
75
+ /**
76
+ * Check if a tool is considered dangerous
77
+ */
78
+ export function isDangerousTool(toolName) {
79
+ return DANGEROUS_ACP_TOOLS.has(toolName.toLowerCase().trim());
80
+ }
81
+ /**
82
+ * Check if a tool is denied over HTTP gateway
83
+ */
84
+ export function isGatewayHttpDenied(toolName) {
85
+ return DEFAULT_GATEWAY_HTTP_TOOL_DENY.includes(toolName.toLowerCase().trim());
86
+ }
87
+ /**
88
+ * Get risk level for a tool
89
+ */
90
+ export function getToolRiskLevel(toolName) {
91
+ if (["exec", "spawn", "shell", "sessions_spawn"].includes(toolName)) {
92
+ return "critical";
93
+ }
94
+ if (["fs_write", "fs_delete", "apply_patch", "gateway"].includes(toolName)) {
95
+ return "high";
96
+ }
97
+ if (["fs_move", "cron", "sessions_send"].includes(toolName)) {
98
+ return "medium";
99
+ }
100
+ return "low";
101
+ }
102
+ /**
103
+ * Get tools that require explicit approval
104
+ */
105
+ export function getToolsRequiringApproval(riskLevel = "high") {
106
+ const allDangerous = Array.from(DANGEROUS_ACP_TOOLS);
107
+ if (riskLevel === "critical") {
108
+ return allDangerous.filter((t) => getToolRiskLevel(t) === "critical");
109
+ }
110
+ if (riskLevel === "high") {
111
+ return allDangerous.filter((t) => ["critical", "high"].includes(getToolRiskLevel(t)));
112
+ }
113
+ return allDangerous;
114
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Security module index exports.
3
+ */
4
+ export * from "./capability.js";
5
+ export * from "./capability-manager.js";
6
+ export * from "./capability-guards.js";
7
+ export * from "./middleware.js";
@@ -0,0 +1,105 @@
1
+ import { getCapabilityManager } from "./capability-manager.js";
2
+ import { CapabilityError } from "./capability-guards.js";
3
+ import { logVerbose } from "../globals.js";
4
+ /**
5
+ * Creates a middleware that checks tool invocation capabilities.
6
+ */
7
+ export function createCapabilityMiddleware() {
8
+ return async (ctx, toolId, _args, next) => {
9
+ const manager = getCapabilityManager();
10
+ // Check for tool:all first (grants any tool)
11
+ const allCheck = manager.check(ctx.agentId, { type: "tool:all" });
12
+ if (allCheck.granted) {
13
+ logVerbose(`[capability] ${ctx.agentId} granted tool:all for ${toolId}`);
14
+ return await next();
15
+ }
16
+ // Check for specific tool invocation
17
+ const toolCheck = manager.check(ctx.agentId, {
18
+ type: "tool:invoke",
19
+ toolId,
20
+ });
21
+ if (!toolCheck.granted) {
22
+ logVerbose(`[capability] ${ctx.agentId} denied access to tool ${toolId}: ${toolCheck.reason}`);
23
+ throw new CapabilityError(`Tool '${toolId}' access denied: ${toolCheck.reason}`, ctx.agentId, { type: "tool:invoke", toolId });
24
+ }
25
+ logVerbose(`[capability] ${ctx.agentId} granted access to ${toolId}`);
26
+ return await next();
27
+ };
28
+ }
29
+ /**
30
+ * Creates a middleware that checks file access capabilities.
31
+ */
32
+ export function createFileAccessMiddleware() {
33
+ return async (ctx, toolId, args, next) => {
34
+ // Tools that read files
35
+ if (toolId === "file_read" || toolId === "read_file") {
36
+ const path = args.path || args.file_path || args.filePath;
37
+ if (typeof path === "string") {
38
+ const manager = getCapabilityManager();
39
+ const check = manager.check(ctx.agentId, {
40
+ type: "file:read",
41
+ pattern: path,
42
+ });
43
+ if (!check.granted) {
44
+ throw new CapabilityError(`File read denied for '${path}': ${check.reason}`, ctx.agentId, { type: "file:read", pattern: path });
45
+ }
46
+ }
47
+ }
48
+ // Tools that write files
49
+ if (toolId === "file_write" || toolId === "write_file") {
50
+ const path = args.path || args.file_path || args.filePath;
51
+ if (typeof path === "string") {
52
+ const manager = getCapabilityManager();
53
+ const check = manager.check(ctx.agentId, {
54
+ type: "file:write",
55
+ pattern: path,
56
+ });
57
+ if (!check.granted) {
58
+ throw new CapabilityError(`File write denied for '${path}': ${check.reason}`, ctx.agentId, { type: "file:write", pattern: path });
59
+ }
60
+ }
61
+ }
62
+ return await next();
63
+ };
64
+ }
65
+ /**
66
+ * Creates a middleware that checks shell execution capabilities.
67
+ */
68
+ export function createShellExecutionMiddleware() {
69
+ return async (ctx, toolId, args, next) => {
70
+ if (toolId === "shell" || toolId === "bash" || toolId === "exec") {
71
+ const command = args.command || args.cmd || args.shell;
72
+ if (typeof command === "string") {
73
+ const manager = getCapabilityManager();
74
+ const check = manager.check(ctx.agentId, {
75
+ type: "shell:exec",
76
+ pattern: command,
77
+ });
78
+ if (!check.granted) {
79
+ throw new CapabilityError(`Shell execution denied for '${command}': ${check.reason}`, ctx.agentId, { type: "shell:exec", pattern: command });
80
+ }
81
+ }
82
+ }
83
+ return await next();
84
+ };
85
+ }
86
+ /**
87
+ * Composes multiple middlewares into a single middleware.
88
+ */
89
+ export function composeMiddlewares(...middlewares) {
90
+ return async (ctx, toolId, args, finalNext) => {
91
+ let index = 0;
92
+ const dispatch = async () => {
93
+ if (index >= middlewares.length) {
94
+ return await finalNext();
95
+ }
96
+ const middleware = middlewares[index++];
97
+ return await middleware(ctx, toolId, args, dispatch);
98
+ };
99
+ return await dispatch();
100
+ };
101
+ }
102
+ /** Default security middleware stack. */
103
+ export function createDefaultSecurityMiddleware() {
104
+ return composeMiddlewares(createCapabilityMiddleware(), createFileAccessMiddleware(), createShellExecutionMiddleware());
105
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Security Module for PoolBot
3
+ *
4
+ * Provides enterprise-grade security controls:
5
+ * - Audit logging for security events
6
+ * - Dangerous tool detection
7
+ * - Safe regex validation
8
+ * - External content validation
9
+ *
10
+ * Based on OpenClaw patterns but adapted for PoolBot architecture.
11
+ */
12
+ export {};