@poolzin/pool-bot 2026.3.7 → 2026.3.10

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 (150) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +147 -69
  3. package/dist/.buildstamp +1 -1
  4. package/dist/agents/error-classifier.js +251 -0
  5. package/dist/agents/skills/security.js +211 -0
  6. package/dist/build-info.json +3 -3
  7. package/dist/cli/cron-cli/register.cron-dashboard.js +339 -0
  8. package/dist/cli/cron-cli/register.js +2 -0
  9. package/dist/cli/errors.js +187 -0
  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 +26 -0
  13. package/dist/cli/program/register.maintenance.js +21 -0
  14. package/dist/cli/program/register.skills.js +4 -0
  15. package/dist/cli/program/register.subclis.js +9 -0
  16. package/dist/cli/swarm-cli/register.js +8 -0
  17. package/dist/cli/swarm-cli/register.swarm-status.js +488 -0
  18. package/dist/cli/telemetry-cli/register.js +10 -0
  19. package/dist/cli/telemetry-cli/register.telemetry-alerts.js +176 -0
  20. package/dist/cli/telemetry-cli/register.telemetry-metrics.js +323 -0
  21. package/dist/cli/telemetry-cli/register.telemetry-status.js +179 -0
  22. package/dist/commands/doctor-checks.js +498 -0
  23. package/dist/config/config.js +1 -0
  24. package/dist/config/secrets-integration.js +88 -0
  25. package/dist/context-engine/index.js +33 -0
  26. package/dist/context-engine/legacy.js +179 -0
  27. package/dist/context-engine/registry.js +86 -0
  28. package/dist/context-engine/summarizing.js +290 -0
  29. package/dist/context-engine/types.js +7 -0
  30. package/dist/cron/service/timer.js +18 -0
  31. package/dist/gateway/protocol/index.js +5 -2
  32. package/dist/gateway/protocol/schema/error-codes.js +1 -0
  33. package/dist/gateway/protocol/schema/swarm.js +80 -0
  34. package/dist/gateway/protocol/schema.js +1 -0
  35. package/dist/gateway/server-close.js +4 -0
  36. package/dist/gateway/server-constants.js +1 -0
  37. package/dist/gateway/server-cron.js +29 -0
  38. package/dist/gateway/server-maintenance.js +35 -2
  39. package/dist/gateway/server-methods/swarm.js +58 -0
  40. package/dist/gateway/server-methods/telemetry.js +71 -0
  41. package/dist/gateway/server-methods-list.js +8 -0
  42. package/dist/gateway/server-methods.js +9 -2
  43. package/dist/gateway/server.impl.js +33 -16
  44. package/dist/infra/abort-pattern.js +106 -0
  45. package/dist/infra/retry.js +96 -0
  46. package/dist/secrets/index.js +28 -0
  47. package/dist/secrets/resolver.js +185 -0
  48. package/dist/secrets/runtime.js +142 -0
  49. package/dist/secrets/types.js +11 -0
  50. package/dist/security/dangerous-tools.js +80 -0
  51. package/dist/security/types.js +12 -0
  52. package/dist/skills/commands.js +333 -0
  53. package/dist/skills/index.js +164 -0
  54. package/dist/skills/loader.js +282 -0
  55. package/dist/skills/parser.js +446 -0
  56. package/dist/skills/registry.js +394 -0
  57. package/dist/skills/security.js +312 -0
  58. package/dist/skills/types.js +21 -0
  59. package/dist/swarm/service.js +247 -0
  60. package/dist/telemetry/alert-engine.js +258 -0
  61. package/dist/telemetry/cron-instrumentation.js +49 -0
  62. package/dist/telemetry/gateway-instrumentation.js +80 -0
  63. package/dist/telemetry/instrumentation.js +66 -0
  64. package/dist/telemetry/service.js +345 -0
  65. package/dist/test-utils/index.js +219 -0
  66. package/dist/tui/components/assistant-message.js +6 -2
  67. package/dist/tui/components/hyperlink-markdown.js +32 -0
  68. package/dist/tui/components/searchable-select-list.js +12 -1
  69. package/dist/tui/components/user-message.js +6 -2
  70. package/dist/tui/index.js +611 -0
  71. package/dist/tui/theme/theme-detection.js +226 -0
  72. package/dist/tui/tui-command-handlers.js +20 -0
  73. package/dist/tui/tui-formatters.js +4 -3
  74. package/dist/tui/utils/ctrl-c-handler.js +67 -0
  75. package/dist/tui/utils/osc8-hyperlinks.js +208 -0
  76. package/dist/tui/utils/safe-stop.js +180 -0
  77. package/dist/tui/utils/session-key-utils.js +81 -0
  78. package/dist/tui/utils/text-sanitization.js +284 -0
  79. package/dist/utils/lru-cache.js +116 -0
  80. package/dist/utils/performance.js +199 -0
  81. package/dist/utils/retry.js +240 -0
  82. package/docs/INTEGRATION_PLAN.md +475 -0
  83. package/docs/INTEGRATION_SUMMARY.md +215 -0
  84. package/docs/MELHORIAS_IMPLEMENTADAS.md +228 -0
  85. package/docs/MELHORIAS_PROFISSIONAIS.md +282 -0
  86. package/docs/PLANO_ACAO_TUI.md +357 -0
  87. package/docs/PROGRESSO_TUI.md +66 -0
  88. package/docs/RELATORIO_FINAL.md +217 -0
  89. package/docs/diagnostico-shell-completion.md +265 -0
  90. package/docs/features/advanced-memory.md +585 -0
  91. package/docs/features/discord-components-v2.md +277 -0
  92. package/docs/features/swarm.md +100 -0
  93. package/docs/features/telemetry.md +284 -0
  94. package/docs/integrations/HEXSTRIKE_PLAN.md +796 -0
  95. package/docs/integrations/INTEGRATION_PLAN.md +744 -0
  96. package/docs/integrations/PAGE_AGENT_PLAN.md +370 -0
  97. package/docs/integrations/XYOPS_PLAN.md +978 -0
  98. package/docs/models/provider-infrastructure.md +400 -0
  99. package/docs/security/exec-approvals.md +294 -0
  100. package/docs/skills/IMPLEMENTATION_SUMMARY.md +145 -0
  101. package/docs/skills/SKILL.md +524 -0
  102. package/docs/skills.md +405 -0
  103. package/extensions/bluebubbles/package.json +1 -1
  104. package/extensions/copilot-proxy/package.json +1 -1
  105. package/extensions/diagnostics-otel/package.json +1 -1
  106. package/extensions/discord/package.json +1 -1
  107. package/extensions/feishu/package.json +1 -1
  108. package/extensions/google-antigravity-auth/package.json +1 -1
  109. package/extensions/google-gemini-cli-auth/package.json +1 -1
  110. package/extensions/googlechat/package.json +1 -1
  111. package/extensions/hexstrike-bridge/README.md +119 -0
  112. package/extensions/hexstrike-bridge/index.test.ts +247 -0
  113. package/extensions/hexstrike-bridge/index.ts +487 -0
  114. package/extensions/hexstrike-bridge/package.json +17 -0
  115. package/extensions/imessage/package.json +1 -1
  116. package/extensions/irc/package.json +1 -1
  117. package/extensions/line/package.json +1 -1
  118. package/extensions/llm-task/package.json +1 -1
  119. package/extensions/lobster/package.json +1 -1
  120. package/extensions/matrix/CHANGELOG.md +5 -0
  121. package/extensions/matrix/package.json +1 -1
  122. package/extensions/mattermost/package.json +1 -1
  123. package/extensions/mcp-server/index.ts +14 -0
  124. package/extensions/mcp-server/package.json +11 -0
  125. package/extensions/mcp-server/src/service.ts +540 -0
  126. package/extensions/memory-core/package.json +1 -1
  127. package/extensions/memory-lancedb/package.json +1 -1
  128. package/extensions/minimax-portal-auth/package.json +1 -1
  129. package/extensions/msteams/CHANGELOG.md +5 -0
  130. package/extensions/msteams/package.json +1 -1
  131. package/extensions/nextcloud-talk/package.json +1 -1
  132. package/extensions/nostr/CHANGELOG.md +5 -0
  133. package/extensions/nostr/package.json +1 -1
  134. package/extensions/open-prose/package.json +1 -1
  135. package/extensions/openai-codex-auth/package.json +1 -1
  136. package/extensions/signal/package.json +1 -1
  137. package/extensions/slack/package.json +1 -1
  138. package/extensions/telegram/package.json +1 -1
  139. package/extensions/tlon/package.json +1 -1
  140. package/extensions/twitch/CHANGELOG.md +5 -0
  141. package/extensions/twitch/package.json +1 -1
  142. package/extensions/voice-call/CHANGELOG.md +5 -0
  143. package/extensions/voice-call/package.json +1 -1
  144. package/extensions/whatsapp/package.json +1 -1
  145. package/extensions/zalo/CHANGELOG.md +5 -0
  146. package/extensions/zalo/package.json +1 -1
  147. package/extensions/zalouser/CHANGELOG.md +5 -0
  148. package/extensions/zalouser/package.json +1 -1
  149. package/package.json +8 -1
  150. package/skills/example-skill/SKILL.md +195 -0
@@ -85,5 +85,101 @@ 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)
99
+ ? resolved.maxDelayMs
100
+ : Number.POSITIVE_INFINITY;
101
+ const jitter = resolved.jitter;
102
+ const shouldRetry = options.shouldRetry ?? (() => true);
103
+ let lastErr;
104
+ let totalDelayMs = 0;
105
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
106
+ try {
107
+ const result = await fn();
108
+ return { result, attempts: attempt, totalDelayMs };
109
+ }
110
+ catch (err) {
111
+ lastErr = err;
112
+ if (attempt >= maxAttempts || !shouldRetry(err, attempt)) {
113
+ break;
114
+ }
115
+ const retryAfterMs = options.retryAfterMs?.(err);
116
+ const hasRetryAfter = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs);
117
+ const baseDelay = hasRetryAfter
118
+ ? Math.max(retryAfterMs, minDelayMs)
119
+ : minDelayMs * 2 ** (attempt - 1);
120
+ let delay = Math.min(baseDelay, maxDelayMs);
121
+ delay = applyJitter(delay, jitter);
122
+ delay = Math.min(Math.max(delay, minDelayMs), maxDelayMs);
123
+ totalDelayMs += delay;
124
+ options.onRetry?.({
125
+ attempt,
126
+ maxAttempts,
127
+ delayMs: delay,
128
+ err,
129
+ label: options.label,
130
+ });
131
+ await sleep(delay);
132
+ }
133
+ }
134
+ options.onExhausted?.(lastErr, maxAttempts);
135
+ throw lastErr ?? new Error("Retry failed");
136
+ }
137
+ /**
138
+ * Check if error is retryable (network errors, rate limits, etc.)
139
+ */
140
+ export function isRetryableError(error) {
141
+ if (error instanceof Error) {
142
+ const message = error.message.toLowerCase();
143
+ // Network errors
144
+ if (message.includes("econnreset"))
145
+ return true;
146
+ if (message.includes("etimedout"))
147
+ return true;
148
+ if (message.includes("econnrefused"))
149
+ return true;
150
+ if (message.includes("enotfound"))
151
+ return true;
152
+ if (message.includes("network"))
153
+ return true;
154
+ if (message.includes("timeout"))
155
+ return true;
156
+ // HTTP status codes that are retryable
157
+ const statusMatch = error.message.match(/status\s+(\d+)/i);
158
+ if (statusMatch) {
159
+ const status = parseInt(statusMatch[1], 10);
160
+ // 429 = Too Many Requests, 502/503/504 = Gateway errors
161
+ if (status === 429 || status === 502 || status === 503 || status === 504) {
162
+ return true;
163
+ }
164
+ }
165
+ }
166
+ return false;
167
+ }
168
+ /**
169
+ * Default retry configuration for API calls
170
+ */
171
+ export const API_RETRY_CONFIG = {
172
+ attempts: 3,
173
+ minDelayMs: 1000,
174
+ maxDelayMs: 10000,
175
+ jitter: 0.1,
176
+ };
177
+ /**
178
+ * Default retry configuration for network calls
179
+ */
180
+ export const NETWORK_RETRY_CONFIG = {
181
+ attempts: 5,
182
+ minDelayMs: 500,
183
+ maxDelayMs: 30000,
184
+ jitter: 0.1,
185
+ };
@@ -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 {};
@@ -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,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 {};