@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,106 @@
1
+ /**
2
+ * Abort Pattern Utilities
3
+ *
4
+ * Provides memory-leak-free abort signal handling.
5
+ *
6
+ * CRITICAL FIX: Uses `.bind()` instead of closures to prevent memory leaks.
7
+ * Issue #7174: Closure-based abort handlers capture scope and leak memory.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // BAD: Captures closure scope (leaks memory)
12
+ * signal.addEventListener('abort', () => controller.abort());
13
+ *
14
+ * // GOOD: No closure capture
15
+ * signal.addEventListener('abort', relayAbort.bind(controller));
16
+ * ```
17
+ */
18
+ /**
19
+ * Relay abort signal without closure capture
20
+ * Prevents memory leak by using bind instead of arrow function
21
+ */
22
+ export function relayAbort() {
23
+ this.abort();
24
+ }
25
+ /**
26
+ * Create an abort relay that doesn't capture closure scope
27
+ */
28
+ export function createAbortRelay(controller) {
29
+ return relayAbort.bind(controller);
30
+ }
31
+ /**
32
+ * Link an abort signal to a controller without memory leaks
33
+ */
34
+ export function linkAbortSignal(source, target) {
35
+ const handler = createAbortRelay(target);
36
+ source.addEventListener('abort', handler, { once: true });
37
+ // Return cleanup function
38
+ return () => {
39
+ source.removeEventListener('abort', handler);
40
+ };
41
+ }
42
+ /**
43
+ * Create a timeout-based abort controller
44
+ */
45
+ export function createTimeoutAbortController(timeoutMs) {
46
+ const controller = new AbortController();
47
+ if (timeoutMs > 0) {
48
+ const timeout = setTimeout(() => {
49
+ controller.abort();
50
+ }, timeoutMs);
51
+ return {
52
+ controller,
53
+ cleanup: () => clearTimeout(timeout),
54
+ };
55
+ }
56
+ return {
57
+ controller,
58
+ cleanup: () => { },
59
+ };
60
+ }
61
+ /**
62
+ * Race multiple abort signals
63
+ */
64
+ export function raceAbortSignals(signals, controller) {
65
+ const handlers = [];
66
+ let alreadyAborted = false;
67
+ for (const signal of signals) {
68
+ if (signal.aborted && !alreadyAborted) {
69
+ alreadyAborted = true;
70
+ controller.abort();
71
+ }
72
+ else if (!alreadyAborted) {
73
+ const handler = createAbortRelay(controller);
74
+ signal.addEventListener('abort', handler, { once: true });
75
+ handlers.push(() => signal.removeEventListener('abort', handler));
76
+ }
77
+ }
78
+ return () => {
79
+ for (const cleanup of handlers) {
80
+ cleanup();
81
+ }
82
+ };
83
+ }
84
+ /**
85
+ * Fetch with timeout and proper abort handling
86
+ */
87
+ export async function fetchWithTimeout(url, options = {}) {
88
+ const { timeoutMs = 30000, ...fetchOptions } = options;
89
+ const { controller, cleanup } = createTimeoutAbortController(timeoutMs);
90
+ // Link existing signal if provided
91
+ let unlink;
92
+ if (fetchOptions.signal) {
93
+ unlink = linkAbortSignal(fetchOptions.signal, controller);
94
+ }
95
+ try {
96
+ const response = await fetch(url, {
97
+ ...fetchOptions,
98
+ signal: controller.signal,
99
+ });
100
+ return response;
101
+ }
102
+ finally {
103
+ unlink?.();
104
+ cleanup();
105
+ }
106
+ }
@@ -85,5 +85,99 @@ export async function retryAsync(fn, attemptsOrOptions = 3, initialDelayMs = 300
85
85
  await sleep(delay);
86
86
  }
87
87
  }
88
+ options.onExhausted?.(lastErr, maxAttempts);
88
89
  throw lastErr ?? new Error("Retry failed");
89
90
  }
91
+ /**
92
+ * Execute a function with retry logic and return detailed result
93
+ */
94
+ export async function retryWithResult(fn, options = {}) {
95
+ const resolved = resolveRetryConfig(DEFAULT_RETRY_CONFIG, options);
96
+ const maxAttempts = resolved.attempts;
97
+ const minDelayMs = resolved.minDelayMs;
98
+ const maxDelayMs = Number.isFinite(resolved.maxDelayMs) ? resolved.maxDelayMs : Number.POSITIVE_INFINITY;
99
+ const jitter = resolved.jitter;
100
+ const shouldRetry = options.shouldRetry ?? (() => true);
101
+ let lastErr;
102
+ let totalDelayMs = 0;
103
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
104
+ try {
105
+ const result = await fn();
106
+ return { result, attempts: attempt, totalDelayMs };
107
+ }
108
+ catch (err) {
109
+ lastErr = err;
110
+ if (attempt >= maxAttempts || !shouldRetry(err, attempt)) {
111
+ break;
112
+ }
113
+ const retryAfterMs = options.retryAfterMs?.(err);
114
+ const hasRetryAfter = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs);
115
+ const baseDelay = hasRetryAfter
116
+ ? Math.max(retryAfterMs, minDelayMs)
117
+ : minDelayMs * 2 ** (attempt - 1);
118
+ let delay = Math.min(baseDelay, maxDelayMs);
119
+ delay = applyJitter(delay, jitter);
120
+ delay = Math.min(Math.max(delay, minDelayMs), maxDelayMs);
121
+ totalDelayMs += delay;
122
+ options.onRetry?.({
123
+ attempt,
124
+ maxAttempts,
125
+ delayMs: delay,
126
+ err,
127
+ label: options.label,
128
+ });
129
+ await sleep(delay);
130
+ }
131
+ }
132
+ options.onExhausted?.(lastErr, maxAttempts);
133
+ throw lastErr ?? new Error("Retry failed");
134
+ }
135
+ /**
136
+ * Check if error is retryable (network errors, rate limits, etc.)
137
+ */
138
+ export function isRetryableError(error) {
139
+ if (error instanceof Error) {
140
+ const message = error.message.toLowerCase();
141
+ // Network errors
142
+ if (message.includes("econnreset"))
143
+ return true;
144
+ if (message.includes("etimedout"))
145
+ return true;
146
+ if (message.includes("econnrefused"))
147
+ return true;
148
+ if (message.includes("enotfound"))
149
+ return true;
150
+ if (message.includes("network"))
151
+ return true;
152
+ if (message.includes("timeout"))
153
+ return true;
154
+ // HTTP status codes that are retryable
155
+ const statusMatch = error.message.match(/status\s+(\d+)/i);
156
+ if (statusMatch) {
157
+ const status = parseInt(statusMatch[1], 10);
158
+ // 429 = Too Many Requests, 502/503/504 = Gateway errors
159
+ if (status === 429 || status === 502 || status === 503 || status === 504) {
160
+ return true;
161
+ }
162
+ }
163
+ }
164
+ return false;
165
+ }
166
+ /**
167
+ * Default retry configuration for API calls
168
+ */
169
+ export const API_RETRY_CONFIG = {
170
+ attempts: 3,
171
+ minDelayMs: 1000,
172
+ maxDelayMs: 10000,
173
+ jitter: 0.1,
174
+ };
175
+ /**
176
+ * Default retry configuration for network calls
177
+ */
178
+ export const NETWORK_RETRY_CONFIG = {
179
+ attempts: 5,
180
+ minDelayMs: 500,
181
+ maxDelayMs: 30000,
182
+ jitter: 0.1,
183
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Secrets Management System
3
+ *
4
+ * Secure secret resolution with support for:
5
+ * - Environment variables (env:default:KEY)
6
+ * - JSON files (file:/path/to/secrets.json:key)
7
+ * - Direct values (backward compatible)
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { SecretsRuntime, resolveValue } from './secrets/index.js';
12
+ *
13
+ * // Create runtime
14
+ * const runtime = new SecretsRuntime({
15
+ * allowDirectValues: true,
16
+ * warnOnDirectValues: true
17
+ * });
18
+ *
19
+ * // Resolve API key
20
+ * runtime.resolve('openaiApiKey', 'env:default:OPENAI_API_KEY');
21
+ *
22
+ * // Get resolved value
23
+ * const apiKey = runtime.get('openaiApiKey');
24
+ * ```
25
+ */
26
+ export * from "./types.js";
27
+ export * from "./resolver.js";
28
+ export * from "./runtime.js";
@@ -0,0 +1,185 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve as resolvePath } from "node:path";
3
+ /**
4
+ * Parse a secret reference string
5
+ * Formats:
6
+ * - env:default:KEY - Environment variable
7
+ * - env:production:KEY - Environment variable from specific source
8
+ * - file:/path/to/secrets.json:KEY - JSON file
9
+ * - file:/path/to/secrets.json - Entire JSON file as secret
10
+ * - raw value - Direct value (backward compatibility)
11
+ */
12
+ export function parseSecretRef(value) {
13
+ // Check if it's a reference
14
+ const envMatch = value.match(/^env:([^:]+):(.+)$/);
15
+ if (envMatch) {
16
+ return {
17
+ isRef: true,
18
+ ref: {
19
+ provider: "env",
20
+ source: envMatch[1],
21
+ key: envMatch[2],
22
+ },
23
+ };
24
+ }
25
+ const fileMatch = value.match(/^file:([^:]+):(.+)$/);
26
+ if (fileMatch) {
27
+ return {
28
+ isRef: true,
29
+ ref: {
30
+ provider: "file",
31
+ source: fileMatch[1],
32
+ key: fileMatch[2],
33
+ },
34
+ };
35
+ }
36
+ const fileOnlyMatch = value.match(/^file:(.+)$/);
37
+ if (fileOnlyMatch) {
38
+ return {
39
+ isRef: true,
40
+ ref: {
41
+ provider: "file",
42
+ source: fileOnlyMatch[1],
43
+ key: "", // Entire file
44
+ },
45
+ };
46
+ }
47
+ // Not a reference - treat as direct value
48
+ return {
49
+ isRef: false,
50
+ rawValue: value,
51
+ };
52
+ }
53
+ /**
54
+ * Resolve a secret reference to its value
55
+ */
56
+ export function resolveSecret(ref, options = {}) {
57
+ const warnings = [];
58
+ switch (ref.provider) {
59
+ case "env":
60
+ return resolveEnvSecret(ref, options, warnings);
61
+ case "file":
62
+ return resolveFileSecret(ref, options, warnings);
63
+ case "exec":
64
+ return resolveExecSecret(ref, options, warnings);
65
+ default:
66
+ return {
67
+ value: undefined,
68
+ resolved: false,
69
+ warnings: [`Unknown provider: ${String(ref.provider)}`],
70
+ };
71
+ }
72
+ }
73
+ function resolveEnvSecret(ref, options, warnings) {
74
+ const value = process.env[ref.key];
75
+ if (value === undefined) {
76
+ if (!options.allowMissing) {
77
+ warnings.push(`Environment variable ${ref.key} is not set`);
78
+ }
79
+ return {
80
+ value: undefined,
81
+ resolved: false,
82
+ source: `env:${ref.source}:${ref.key}`,
83
+ warnings,
84
+ };
85
+ }
86
+ return {
87
+ value,
88
+ resolved: true,
89
+ source: `env:${ref.source}:${ref.key}`,
90
+ warnings,
91
+ };
92
+ }
93
+ function resolveFileSecret(ref, options, warnings) {
94
+ try {
95
+ const filePath = resolvePath(ref.source);
96
+ // Path traversal protection
97
+ if (options.basePath && !filePath.startsWith(resolvePath(options.basePath))) {
98
+ warnings.push(`Secret file path outside allowed directory: ${ref.source}`);
99
+ return {
100
+ value: undefined,
101
+ resolved: false,
102
+ source: `file:${ref.source}`,
103
+ warnings,
104
+ };
105
+ }
106
+ const content = readFileSync(filePath, "utf-8");
107
+ // If key is empty, return entire file content
108
+ if (!ref.key) {
109
+ return {
110
+ value: content.trim(),
111
+ resolved: true,
112
+ source: `file:${ref.source}`,
113
+ warnings,
114
+ };
115
+ }
116
+ // Try to parse as JSON
117
+ try {
118
+ const json = JSON.parse(content);
119
+ if (typeof json === "object" && json !== null) {
120
+ if (ref.key in json) {
121
+ const value = String(json[ref.key]);
122
+ return {
123
+ value,
124
+ resolved: true,
125
+ source: `file:${ref.source}:${ref.key}`,
126
+ warnings,
127
+ };
128
+ }
129
+ warnings.push(`Key "${ref.key}" not found in JSON file ${ref.source}`);
130
+ }
131
+ }
132
+ catch {
133
+ // Not valid JSON, treat as plain text
134
+ warnings.push(`File ${ref.source} is not valid JSON`);
135
+ }
136
+ if (!options.allowMissing) {
137
+ warnings.push(`Could not resolve secret from file: ${ref.source}:${ref.key}`);
138
+ }
139
+ return {
140
+ value: undefined,
141
+ resolved: false,
142
+ source: `file:${ref.source}:${ref.key}`,
143
+ warnings,
144
+ };
145
+ }
146
+ catch (error) {
147
+ const message = error instanceof Error ? error.message : String(error);
148
+ warnings.push(`Failed to read file ${ref.source}: ${message}`);
149
+ return {
150
+ value: undefined,
151
+ resolved: false,
152
+ source: `file:${ref.source}:${ref.key}`,
153
+ warnings,
154
+ };
155
+ }
156
+ }
157
+ function resolveExecSecret(ref, _options, warnings) {
158
+ // Exec provider not yet implemented
159
+ warnings.push("Exec provider is not yet implemented");
160
+ return {
161
+ value: undefined,
162
+ resolved: false,
163
+ source: `exec:${ref.source}:${ref.key}`,
164
+ warnings,
165
+ };
166
+ }
167
+ /**
168
+ * Resolve a value that may be a secret reference or direct value
169
+ */
170
+ export function resolveValue(value, options = {}) {
171
+ const parsed = parseSecretRef(value);
172
+ if (parsed.isRef && parsed.ref) {
173
+ return resolveSecret(parsed.ref, options);
174
+ }
175
+ // Direct value
176
+ const warnings = [];
177
+ if (options.warnOnDirectValues && parsed.rawValue !== undefined) {
178
+ warnings.push("Using direct secret value. Consider using env:default:KEY or file:/path:key format for better security");
179
+ }
180
+ return {
181
+ value: parsed.rawValue,
182
+ resolved: parsed.rawValue !== undefined,
183
+ warnings,
184
+ };
185
+ }
@@ -0,0 +1,142 @@
1
+ import { resolveValue } from "./resolver.js";
2
+ /**
3
+ * Runtime snapshot for resolved secrets
4
+ *
5
+ * This class manages a snapshot of resolved secrets that is created
6
+ * at startup and remains immutable during runtime for security.
7
+ */
8
+ export class SecretsRuntime {
9
+ snapshot;
10
+ config;
11
+ constructor(config = {}) {
12
+ this.config = {
13
+ allowDirectValues: true,
14
+ warnOnDirectValues: true,
15
+ failOnUnresolved: false,
16
+ ...config,
17
+ };
18
+ this.snapshot = {
19
+ secrets: new Map(),
20
+ unresolved: [],
21
+ warnings: [],
22
+ timestamp: new Date(),
23
+ };
24
+ }
25
+ /**
26
+ * Resolve a single secret and add to snapshot
27
+ */
28
+ resolve(key, value) {
29
+ const result = resolveValue(value, {
30
+ allowDirectValues: this.config.allowDirectValues,
31
+ warnOnDirectValues: this.config.warnOnDirectValues,
32
+ allowMissing: !this.config.failOnUnresolved,
33
+ });
34
+ if (result.resolved && result.value !== undefined) {
35
+ this.snapshot.secrets.set(key, {
36
+ value: result.value,
37
+ source: result.source || "direct",
38
+ warnings: result.warnings,
39
+ });
40
+ }
41
+ else {
42
+ this.snapshot.unresolved.push(key);
43
+ }
44
+ if (result.warnings.length > 0) {
45
+ this.snapshot.warnings.push(...result.warnings);
46
+ }
47
+ return result;
48
+ }
49
+ /**
50
+ * Resolve multiple secrets from an object
51
+ */
52
+ resolveObject(obj) {
53
+ const resolved = {};
54
+ for (const [key, value] of Object.entries(obj)) {
55
+ const result = this.resolve(key, value);
56
+ if (result.value !== undefined) {
57
+ resolved[key] = result.value;
58
+ }
59
+ }
60
+ return resolved;
61
+ }
62
+ /**
63
+ * Get a resolved secret value
64
+ */
65
+ get(key) {
66
+ return this.snapshot.secrets.get(key)?.value;
67
+ }
68
+ /**
69
+ * Check if a secret is resolved
70
+ */
71
+ has(key) {
72
+ return this.snapshot.secrets.has(key);
73
+ }
74
+ /**
75
+ * Get full snapshot info for a secret
76
+ */
77
+ getInfo(key) {
78
+ return this.snapshot.secrets.get(key);
79
+ }
80
+ /**
81
+ * Get all unresolved keys
82
+ */
83
+ getUnresolved() {
84
+ return [...this.snapshot.unresolved];
85
+ }
86
+ /**
87
+ * Get all warnings
88
+ */
89
+ getWarnings() {
90
+ return [...this.snapshot.warnings];
91
+ }
92
+ /**
93
+ * Get snapshot timestamp
94
+ */
95
+ getTimestamp() {
96
+ return this.snapshot.timestamp;
97
+ }
98
+ /**
99
+ * Create an immutable snapshot copy
100
+ */
101
+ createSnapshot() {
102
+ return {
103
+ secrets: new Map(this.snapshot.secrets),
104
+ unresolved: [...this.snapshot.unresolved],
105
+ warnings: [...this.snapshot.warnings],
106
+ timestamp: new Date(this.snapshot.timestamp),
107
+ };
108
+ }
109
+ /**
110
+ * Check if there are any unresolved required secrets
111
+ */
112
+ hasUnresolved() {
113
+ return this.snapshot.unresolved.length > 0;
114
+ }
115
+ /**
116
+ * Get summary of the runtime state
117
+ */
118
+ getSummary() {
119
+ return {
120
+ resolved: this.snapshot.secrets.size,
121
+ unresolved: this.snapshot.unresolved.length,
122
+ warnings: this.snapshot.warnings.length,
123
+ timestamp: this.snapshot.timestamp,
124
+ };
125
+ }
126
+ }
127
+ /**
128
+ * Global runtime instance (lazy initialized)
129
+ */
130
+ let globalRuntime = null;
131
+ export function getGlobalRuntime() {
132
+ if (!globalRuntime) {
133
+ globalRuntime = new SecretsRuntime();
134
+ }
135
+ return globalRuntime;
136
+ }
137
+ export function setGlobalRuntime(runtime) {
138
+ globalRuntime = runtime;
139
+ }
140
+ export function resetGlobalRuntime() {
141
+ globalRuntime = null;
142
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Secrets Management System for PoolBot
3
+ *
4
+ * Provides secure secret resolution with support for:
5
+ * - Environment variables (env:default:KEY)
6
+ * - JSON files (file:/path/to/secrets.json)
7
+ * - Direct values (for backward compatibility)
8
+ *
9
+ * Based on OpenClaw patterns but adapted for PoolBot architecture.
10
+ */
11
+ export {};
@@ -0,0 +1,89 @@
1
+ import { getCapabilityManager } from "./capability-manager.js";
2
+ /** Error thrown when a capability check fails. */
3
+ export class CapabilityError extends Error {
4
+ agentId;
5
+ required;
6
+ constructor(message, agentId, required) {
7
+ super(message);
8
+ this.agentId = agentId;
9
+ this.required = required;
10
+ this.name = "CapabilityError";
11
+ }
12
+ }
13
+ /** Guard function that throws if capability is denied. */
14
+ export function requireCapability(agentId, required) {
15
+ const manager = getCapabilityManager();
16
+ const check = manager.check(agentId, required);
17
+ if (!check.granted) {
18
+ throw new CapabilityError(check.reason, agentId, required);
19
+ }
20
+ }
21
+ /** Async guard that returns a promise rejection if denied. */
22
+ export async function withCapability(agentId, required, fn) {
23
+ requireCapability(agentId, required);
24
+ return await fn();
25
+ }
26
+ /** Helper to check file read capability. */
27
+ export function checkFileRead(agentId, path) {
28
+ return getCapabilityManager().check(agentId, {
29
+ type: "file:read",
30
+ pattern: path,
31
+ });
32
+ }
33
+ /** Helper to check file write capability. */
34
+ export function checkFileWrite(agentId, path) {
35
+ return getCapabilityManager().check(agentId, {
36
+ type: "file:write",
37
+ pattern: path,
38
+ });
39
+ }
40
+ /** Helper to check tool invocation capability. */
41
+ export function checkToolInvoke(agentId, toolId) {
42
+ return getCapabilityManager().check(agentId, {
43
+ type: "tool:invoke",
44
+ toolId,
45
+ });
46
+ }
47
+ /** Helper to check network connection capability. */
48
+ export function checkNetConnect(agentId, host) {
49
+ return getCapabilityManager().check(agentId, {
50
+ type: "net:connect",
51
+ pattern: host,
52
+ });
53
+ }
54
+ /** Helper to check shell execution capability. */
55
+ export function checkShellExec(agentId, command) {
56
+ return getCapabilityManager().check(agentId, {
57
+ type: "shell:exec",
58
+ pattern: command,
59
+ });
60
+ }
61
+ /** Helper to check LLM query capability. */
62
+ export function checkLlmQuery(agentId, model) {
63
+ return getCapabilityManager().check(agentId, {
64
+ type: "llm:query",
65
+ pattern: model,
66
+ });
67
+ }
68
+ /** Helper to check agent spawn capability. */
69
+ export function checkAgentSpawn(agentId) {
70
+ return getCapabilityManager().check(agentId, { type: "agent:spawn" });
71
+ }
72
+ /** Helper to check memory read capability. */
73
+ export function checkMemoryRead(agentId, scope) {
74
+ return getCapabilityManager().check(agentId, {
75
+ type: "memory:read",
76
+ scope,
77
+ });
78
+ }
79
+ /** Helper to check memory write capability. */
80
+ export function checkMemoryWrite(agentId, scope) {
81
+ return getCapabilityManager().check(agentId, {
82
+ type: "memory:write",
83
+ scope,
84
+ });
85
+ }
86
+ /** Helper to check gateway admin capability. */
87
+ export function checkGatewayAdmin(agentId) {
88
+ return getCapabilityManager().check(agentId, { type: "gateway:admin" });
89
+ }