@poolzin/pool-bot 2026.3.9 → 2026.3.11
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.
- package/CHANGELOG.md +35 -0
- package/README.md +147 -69
- package/dist/.buildstamp +1 -1
- package/dist/agents/error-classifier.js +26 -77
- package/dist/agents/skills/security.js +1 -7
- package/dist/build-info.json +3 -3
- package/dist/cli/cron-cli/register.cron-dashboard.js +339 -0
- package/dist/cli/cron-cli/register.js +2 -0
- package/dist/cli/errors.js +187 -0
- package/dist/cli/program/command-registry.js +13 -0
- package/dist/cli/program/register.maintenance.js +21 -0
- package/dist/cli/program/register.subclis.js +9 -0
- package/dist/cli/swarm-cli/register.js +8 -0
- package/dist/cli/swarm-cli/register.swarm-status.js +488 -0
- package/dist/cli/telemetry-cli/register.js +10 -0
- package/dist/cli/telemetry-cli/register.telemetry-alerts.js +176 -0
- package/dist/cli/telemetry-cli/register.telemetry-metrics.js +323 -0
- package/dist/cli/telemetry-cli/register.telemetry-status.js +179 -0
- package/dist/commands/doctor-checks.js +498 -0
- package/dist/context-engine/index.js +1 -1
- package/dist/context-engine/legacy.js +1 -3
- package/dist/context-engine/summarizing.js +5 -8
- package/dist/cron/service/timer.js +18 -0
- package/dist/gateway/protocol/index.js +5 -2
- package/dist/gateway/protocol/schema/error-codes.js +1 -0
- package/dist/gateway/protocol/schema/swarm.js +80 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/server-close.js +4 -0
- package/dist/gateway/server-constants.js +1 -0
- package/dist/gateway/server-cron.js +29 -0
- package/dist/gateway/server-maintenance.js +35 -2
- package/dist/gateway/server-methods/swarm.js +58 -0
- package/dist/gateway/server-methods/telemetry.js +71 -0
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +9 -2
- package/dist/gateway/server.impl.js +33 -16
- package/dist/infra/abort-pattern.js +4 -4
- package/dist/infra/retry.js +3 -1
- package/dist/skills/commands.js +7 -25
- package/dist/skills/index.js +14 -17
- package/dist/skills/parser.js +12 -27
- package/dist/skills/registry.js +3 -6
- package/dist/skills/security.js +2 -8
- package/dist/swarm/service.js +247 -0
- package/dist/telemetry/alert-engine.js +258 -0
- package/dist/telemetry/cron-instrumentation.js +49 -0
- package/dist/telemetry/gateway-instrumentation.js +80 -0
- package/dist/telemetry/instrumentation.js +66 -0
- package/dist/telemetry/service.js +345 -0
- package/dist/tui/components/assistant-message.js +6 -2
- package/dist/tui/components/hyperlink-markdown.js +32 -0
- package/dist/tui/components/searchable-select-list.js +12 -1
- package/dist/tui/components/user-message.js +6 -2
- package/dist/tui/index.js +22 -6
- package/dist/tui/theme/theme-detection.js +226 -0
- package/dist/tui/tui-command-handlers.js +20 -0
- package/dist/tui/tui-formatters.js +4 -3
- package/dist/tui/utils/ctrl-c-handler.js +67 -0
- package/dist/tui/utils/osc8-hyperlinks.js +208 -0
- package/dist/tui/utils/safe-stop.js +180 -0
- package/dist/tui/utils/session-key-utils.js +81 -0
- package/dist/tui/utils/text-sanitization.js +284 -0
- package/dist/utils/lru-cache.js +116 -0
- package/dist/utils/performance.js +199 -0
- package/dist/utils/retry.js +240 -0
- package/docs/MELHORIAS_IMPLEMENTADAS.md +228 -0
- package/docs/MELHORIAS_PROFISSIONAIS.md +282 -0
- package/docs/PLANO_ACAO_TUI.md +357 -0
- package/docs/PROGRESSO_TUI.md +66 -0
- package/docs/RELATORIO_FINAL.md +217 -0
- package/docs/diagnostico-shell-completion.md +265 -0
- package/docs/features/advanced-memory.md +585 -0
- package/docs/features/discord-components-v2.md +277 -0
- package/docs/features/swarm.md +100 -0
- package/docs/features/telemetry.md +284 -0
- package/docs/integrations/INTEGRATION_PLAN.md +665 -345
- package/docs/models/provider-infrastructure.md +400 -0
- package/docs/security/exec-approvals.md +294 -0
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/hexstrike-bridge/README.md +119 -0
- package/extensions/hexstrike-bridge/index.test.ts +247 -0
- package/extensions/hexstrike-bridge/index.ts +487 -0
- package/extensions/hexstrike-bridge/package.json +17 -0
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +10 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mavalie/README.md +97 -0
- package/extensions/mavalie/package.json +15 -0
- package/extensions/mavalie/src/index.ts +62 -0
- package/extensions/mcp-server/index.ts +14 -0
- package/extensions/mcp-server/package.json +11 -0
- package/extensions/mcp-server/src/service.ts +540 -0
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +10 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +10 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +10 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +10 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +10 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +10 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +8 -1
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import type { PoolBotPluginApi, PoolBotPluginDefinition, PoolBotPluginConfigSchema } from "../../src/plugins/types.js";
|
|
2
|
+
import type { GatewayRequestHandlerOptions } from "../../src/gateway/server-methods/types.js";
|
|
3
|
+
import { ErrorCodes } from "../../src/gateway/protocol/schema/error-codes.js";
|
|
4
|
+
import { getGlobalTelemetryService } from "../../src/telemetry/service.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
const HexStrikeConfigSchema = z.object({
|
|
8
|
+
baseUrl: z.string().default("http://localhost:8888"),
|
|
9
|
+
timeoutMs: z.number().default(300000),
|
|
10
|
+
maxConcurrentScans: z.number().default(3),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
type HexStrikeConfig = z.infer<typeof HexStrikeConfigSchema>;
|
|
14
|
+
|
|
15
|
+
interface ScanJob {
|
|
16
|
+
id: string;
|
|
17
|
+
tool: string;
|
|
18
|
+
target: string;
|
|
19
|
+
status: "pending" | "running" | "completed" | "failed";
|
|
20
|
+
progress: number;
|
|
21
|
+
result?: unknown;
|
|
22
|
+
error?: string;
|
|
23
|
+
startedAt?: Date;
|
|
24
|
+
completedAt?: Date;
|
|
25
|
+
durationMs?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface HexStrikeTool {
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
category: string;
|
|
32
|
+
params: Array<{
|
|
33
|
+
name: string;
|
|
34
|
+
type: string;
|
|
35
|
+
required: boolean;
|
|
36
|
+
description: string;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class HexStrikeClient {
|
|
41
|
+
private config: HexStrikeConfig;
|
|
42
|
+
private activeScans = new Map<string, ScanJob>();
|
|
43
|
+
private metrics = {
|
|
44
|
+
totalScans: 0,
|
|
45
|
+
completedScans: 0,
|
|
46
|
+
failedScans: 0,
|
|
47
|
+
totalDurationMs: 0,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
constructor(config: HexStrikeConfig) {
|
|
51
|
+
this.config = config;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private recordMetrics(job: ScanJob): void {
|
|
55
|
+
const telemetry = getGlobalTelemetryService();
|
|
56
|
+
if (!telemetry) return;
|
|
57
|
+
|
|
58
|
+
const duration = job.durationMs ?? 0;
|
|
59
|
+
|
|
60
|
+
telemetry.recordCounter("poolbot.security.scans_total", 1, {
|
|
61
|
+
tool: job.tool,
|
|
62
|
+
status: job.status,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (duration > 0) {
|
|
66
|
+
telemetry.recordHistogram("poolbot.security.scan_duration_ms", duration, {
|
|
67
|
+
tool: job.tool,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (job.status === "completed") {
|
|
72
|
+
this.metrics.completedScans++;
|
|
73
|
+
} else if (job.status === "failed") {
|
|
74
|
+
this.metrics.failedScans++;
|
|
75
|
+
telemetry.recordCounter("poolbot.security.scan_failures", 1, {
|
|
76
|
+
tool: job.tool,
|
|
77
|
+
error: job.error ? job.error.substring(0, 50) : "unknown",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.metrics.totalScans++;
|
|
82
|
+
this.metrics.totalDurationMs += duration;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async listTools(): Promise<HexStrikeTool[]> {
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
const telemetry = getGlobalTelemetryService();
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(`${this.config.baseUrl}/api/tools`, {
|
|
91
|
+
method: "GET",
|
|
92
|
+
headers: { "Content-Type": "application/json" },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`HexStrike API error: ${response.status}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const data = await response.json();
|
|
100
|
+
const tools = data.tools || [];
|
|
101
|
+
|
|
102
|
+
telemetry?.recordCounter("poolbot.security.api_calls", 1, {
|
|
103
|
+
endpoint: "list_tools",
|
|
104
|
+
status: "success",
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return tools;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
telemetry?.recordCounter("poolbot.security.api_calls", 1, {
|
|
110
|
+
endpoint: "list_tools",
|
|
111
|
+
status: "error",
|
|
112
|
+
});
|
|
113
|
+
throw new Error(`Failed to list tools: ${String(error)}`);
|
|
114
|
+
} finally {
|
|
115
|
+
telemetry?.recordHistogram("poolbot.security.api_latency_ms", Date.now() - startTime, {
|
|
116
|
+
endpoint: "list_tools",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async executeTool(tool: string, params: Record<string, unknown>): Promise<ScanJob> {
|
|
122
|
+
const jobId = `scan-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
123
|
+
|
|
124
|
+
const job: ScanJob = {
|
|
125
|
+
id: jobId,
|
|
126
|
+
tool,
|
|
127
|
+
target: typeof params.target === "string" ? params.target : typeof params.host === "string" ? params.host : typeof params.url === "string" ? params.url : "unknown",
|
|
128
|
+
status: "pending",
|
|
129
|
+
progress: 0,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.activeScans.set(jobId, job);
|
|
133
|
+
|
|
134
|
+
const telemetry = getGlobalTelemetryService();
|
|
135
|
+
telemetry?.recordGauge("poolbot.security.active_scans", this.getActiveScanCount());
|
|
136
|
+
|
|
137
|
+
const startTime = Date.now();
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
job.status = "running";
|
|
141
|
+
job.startedAt = new Date();
|
|
142
|
+
|
|
143
|
+
const response = await fetch(`${this.config.baseUrl}/api/scan`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: { "Content-Type": "application/json" },
|
|
146
|
+
body: JSON.stringify({ tool, params }),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
throw new Error(`Scan failed: ${response.status}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const result = await response.json();
|
|
154
|
+
|
|
155
|
+
job.status = "completed";
|
|
156
|
+
job.progress = 100;
|
|
157
|
+
job.result = result;
|
|
158
|
+
job.completedAt = new Date();
|
|
159
|
+
job.durationMs = Date.now() - startTime;
|
|
160
|
+
|
|
161
|
+
this.recordMetrics(job);
|
|
162
|
+
|
|
163
|
+
return job;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
job.status = "failed";
|
|
166
|
+
job.error = String(error);
|
|
167
|
+
job.completedAt = new Date();
|
|
168
|
+
job.durationMs = Date.now() - startTime;
|
|
169
|
+
|
|
170
|
+
this.recordMetrics(job);
|
|
171
|
+
|
|
172
|
+
throw error;
|
|
173
|
+
} finally {
|
|
174
|
+
telemetry?.recordGauge("poolbot.security.active_scans", this.getActiveScanCount());
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
getJob(jobId: string): ScanJob | undefined {
|
|
179
|
+
return this.activeScans.get(jobId);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
listJobs(): ScanJob[] {
|
|
183
|
+
return Array.from(this.activeScans.values());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
getActiveScanCount(): number {
|
|
187
|
+
return Array.from(this.activeScans.values()).filter((j: ScanJob) => j.status === "running").length;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
getMetrics() {
|
|
191
|
+
return { ...this.metrics };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async getHealth(): Promise<{ status: string; version?: string; latencyMs?: number }> {
|
|
195
|
+
const startTime = Date.now();
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const response = await fetch(`${this.config.baseUrl}/health`, {
|
|
199
|
+
method: "GET",
|
|
200
|
+
} as RequestInit);
|
|
201
|
+
|
|
202
|
+
const latencyMs = Date.now() - startTime;
|
|
203
|
+
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
return { status: "unhealthy", latencyMs };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const data = await response.json();
|
|
209
|
+
return { status: "healthy", version: data.version, latencyMs };
|
|
210
|
+
} catch {
|
|
211
|
+
return { status: "offline" };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Wrap Zod schema to match PoolBotPluginConfigSchema
|
|
217
|
+
const configSchema: PoolBotPluginConfigSchema = {
|
|
218
|
+
parse(value: unknown) {
|
|
219
|
+
return HexStrikeConfigSchema.parse(value);
|
|
220
|
+
},
|
|
221
|
+
safeParse(value: unknown) {
|
|
222
|
+
const result = HexStrikeConfigSchema.safeParse(value);
|
|
223
|
+
if (result.success) {
|
|
224
|
+
return { success: true, data: result.data };
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
success: false,
|
|
228
|
+
error: {
|
|
229
|
+
issues: result.error?.issues?.map((issue) => ({
|
|
230
|
+
path: issue.path.map(String),
|
|
231
|
+
message: issue.message,
|
|
232
|
+
})),
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const definition: PoolBotPluginDefinition = {
|
|
239
|
+
id: "hexstrike-bridge",
|
|
240
|
+
name: "HexStrike Security Bridge",
|
|
241
|
+
description: "Integrates HexStrike AI security tools (150+ scanners)",
|
|
242
|
+
version: "2026.3.9",
|
|
243
|
+
|
|
244
|
+
configSchema,
|
|
245
|
+
|
|
246
|
+
async register(api: PoolBotPluginApi) {
|
|
247
|
+
const config = HexStrikeConfigSchema.parse(api.pluginConfig || {});
|
|
248
|
+
const client = new HexStrikeClient(config);
|
|
249
|
+
|
|
250
|
+
api.logger.info(`HexStrike bridge registering (baseUrl: ${config.baseUrl})`);
|
|
251
|
+
|
|
252
|
+
// Record plugin load metric
|
|
253
|
+
const telemetry = getGlobalTelemetryService();
|
|
254
|
+
telemetry?.recordCounter("poolbot.security.plugin_loads", 1);
|
|
255
|
+
|
|
256
|
+
// Register gateway methods
|
|
257
|
+
api.registerGatewayMethod("security.status", async (opts: GatewayRequestHandlerOptions) => {
|
|
258
|
+
const health = await client.getHealth();
|
|
259
|
+
const metrics = client.getMetrics();
|
|
260
|
+
|
|
261
|
+
opts.respond(true, {
|
|
262
|
+
connected: health.status === "healthy",
|
|
263
|
+
version: health.version,
|
|
264
|
+
latencyMs: health.latencyMs,
|
|
265
|
+
maxConcurrent: config.maxConcurrentScans,
|
|
266
|
+
activeScans: client.getActiveScanCount(),
|
|
267
|
+
totalScans: metrics.totalScans,
|
|
268
|
+
completedScans: metrics.completedScans,
|
|
269
|
+
failedScans: metrics.failedScans,
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
api.registerGatewayMethod("security.tools.list", async (opts: GatewayRequestHandlerOptions) => {
|
|
274
|
+
const tools = await client.listTools();
|
|
275
|
+
opts.respond(true, { tools });
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
api.registerGatewayMethod("security.scan.start", async (opts: GatewayRequestHandlerOptions) => {
|
|
279
|
+
const params = opts.params as { tool: string; target: string; options?: Record<string, unknown> };
|
|
280
|
+
|
|
281
|
+
// Check concurrent scan limit
|
|
282
|
+
if (client.getActiveScanCount() >= config.maxConcurrentScans) {
|
|
283
|
+
opts.respond(false, undefined, {
|
|
284
|
+
code: ErrorCodes.UNAVAILABLE,
|
|
285
|
+
message: `Maximum concurrent scans (${config.maxConcurrentScans}) reached`,
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const job = await client.executeTool(params.tool, {
|
|
291
|
+
target: params.target,
|
|
292
|
+
...params.options,
|
|
293
|
+
});
|
|
294
|
+
opts.respond(true, { jobId: job.id, status: job.status });
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
api.registerGatewayMethod("security.scan.status", async (opts: GatewayRequestHandlerOptions) => {
|
|
298
|
+
const params = opts.params as { jobId: string };
|
|
299
|
+
const job = client.getJob(params.jobId);
|
|
300
|
+
if (!job) {
|
|
301
|
+
opts.respond(false, undefined, { code: ErrorCodes.INVALID_REQUEST, message: `Job not found: ${params.jobId}` });
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
opts.respond(true, {
|
|
305
|
+
jobId: job.id,
|
|
306
|
+
status: job.status,
|
|
307
|
+
progress: job.progress,
|
|
308
|
+
result: job.result,
|
|
309
|
+
error: job.error,
|
|
310
|
+
durationMs: job.durationMs,
|
|
311
|
+
startedAt: job.startedAt,
|
|
312
|
+
completedAt: job.completedAt,
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
api.registerGatewayMethod("security.scan.list", async (opts: GatewayRequestHandlerOptions) => {
|
|
317
|
+
const jobs = client.listJobs();
|
|
318
|
+
opts.respond(true, {
|
|
319
|
+
jobs: jobs.map(j => ({
|
|
320
|
+
jobId: j.id,
|
|
321
|
+
tool: j.tool,
|
|
322
|
+
target: j.target,
|
|
323
|
+
status: j.status,
|
|
324
|
+
progress: j.progress,
|
|
325
|
+
durationMs: j.durationMs,
|
|
326
|
+
startedAt: j.startedAt,
|
|
327
|
+
completedAt: j.completedAt,
|
|
328
|
+
})),
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
api.registerGatewayMethod("security.metrics", async (opts: GatewayRequestHandlerOptions) => {
|
|
333
|
+
const metrics = client.getMetrics();
|
|
334
|
+
const health = await client.getHealth();
|
|
335
|
+
|
|
336
|
+
opts.respond(true, {
|
|
337
|
+
...metrics,
|
|
338
|
+
activeScans: client.getActiveScanCount(),
|
|
339
|
+
connected: health.status === "healthy",
|
|
340
|
+
averageDurationMs: metrics.totalScans > 0 ? Math.round(metrics.totalDurationMs / metrics.totalScans) : 0,
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Register CLI commands
|
|
345
|
+
api.registerCli((ctx) => {
|
|
346
|
+
const securityCmd = ctx.program
|
|
347
|
+
.command("security")
|
|
348
|
+
.description("Security scanning via HexStrike AI");
|
|
349
|
+
|
|
350
|
+
securityCmd
|
|
351
|
+
.command("status")
|
|
352
|
+
.description("Check HexStrike connection status")
|
|
353
|
+
.action(async () => {
|
|
354
|
+
const health = await client.getHealth();
|
|
355
|
+
console.log(`HexStrike Status: ${health.status}`);
|
|
356
|
+
if (health.version) {
|
|
357
|
+
console.log(`Version: ${health.version}`);
|
|
358
|
+
}
|
|
359
|
+
if (health.latencyMs) {
|
|
360
|
+
console.log(`Latency: ${health.latencyMs}ms`);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
securityCmd
|
|
365
|
+
.command("tools")
|
|
366
|
+
.description("List available security tools")
|
|
367
|
+
.action(async () => {
|
|
368
|
+
const tools = await client.listTools();
|
|
369
|
+
console.log(`\nAvailable Security Tools (${tools.length}):\n`);
|
|
370
|
+
|
|
371
|
+
const byCategory = new Map<string, HexStrikeTool[]>();
|
|
372
|
+
for (const tool of tools) {
|
|
373
|
+
const list = byCategory.get(tool.category) || [];
|
|
374
|
+
list.push(tool);
|
|
375
|
+
byCategory.set(tool.category, list);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
for (const [category, categoryTools] of byCategory) {
|
|
379
|
+
console.log(`\n${category}:`);
|
|
380
|
+
for (const tool of categoryTools) {
|
|
381
|
+
console.log(` • ${tool.name} - ${tool.description}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
securityCmd
|
|
387
|
+
.command("scan <tool> <target>")
|
|
388
|
+
.description("Run a security scan")
|
|
389
|
+
.option("-w, --wait", "Wait for scan completion", false)
|
|
390
|
+
.option("-t, --timeout <seconds>", "Timeout in seconds", "300")
|
|
391
|
+
.action(async (tool: string, target: string, options: { wait?: boolean; timeout?: string }) => {
|
|
392
|
+
console.log(`Starting ${tool} scan against ${target}...`);
|
|
393
|
+
|
|
394
|
+
const job = await client.executeTool(tool, {
|
|
395
|
+
target,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
console.log(`Scan started: ${job.id}`);
|
|
399
|
+
|
|
400
|
+
if (options.wait) {
|
|
401
|
+
console.log("Waiting for completion...");
|
|
402
|
+
|
|
403
|
+
const startTime = Date.now();
|
|
404
|
+
const timeoutMs = parseInt(options.timeout || "300", 10) * 1000;
|
|
405
|
+
|
|
406
|
+
while (job.status === "running" || job.status === "pending") {
|
|
407
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
408
|
+
console.log("Timeout reached");
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
413
|
+
const current = client.getJob(job.id);
|
|
414
|
+
if (current) {
|
|
415
|
+
Object.assign(job, current);
|
|
416
|
+
if (job.progress > 0) {
|
|
417
|
+
process.stdout.write(`\rProgress: ${job.progress}%`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
console.log("\n");
|
|
423
|
+
|
|
424
|
+
if (job.status === "completed" && job.result) {
|
|
425
|
+
console.log("Scan completed successfully!");
|
|
426
|
+
console.log(JSON.stringify(job.result, null, 2));
|
|
427
|
+
} else if (job.error) {
|
|
428
|
+
console.error(`Scan failed: ${job.error}`);
|
|
429
|
+
process.exit(1);
|
|
430
|
+
}
|
|
431
|
+
} else {
|
|
432
|
+
console.log(`Use 'poolbot security scan-status ${job.id}' to check progress`);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
securityCmd
|
|
437
|
+
.command("scan-status <jobId>")
|
|
438
|
+
.description("Check scan status")
|
|
439
|
+
.action(async (jobId: string) => {
|
|
440
|
+
const job = client.getJob(jobId);
|
|
441
|
+
if (!job) {
|
|
442
|
+
console.error(`Job not found: ${jobId}`);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
console.log(`Job: ${job.id}`);
|
|
447
|
+
console.log(`Tool: ${job.tool}`);
|
|
448
|
+
console.log(`Target: ${job.target}`);
|
|
449
|
+
console.log(`Status: ${job.status}`);
|
|
450
|
+
console.log(`Progress: ${job.progress}%`);
|
|
451
|
+
if (job.durationMs) {
|
|
452
|
+
console.log(`Duration: ${job.durationMs}ms`);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (job.result) {
|
|
456
|
+
console.log("\nResult:");
|
|
457
|
+
console.log(JSON.stringify(job.result, null, 2));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (job.error) {
|
|
461
|
+
console.error(`\nError: ${job.error}`);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
securityCmd
|
|
466
|
+
.command("metrics")
|
|
467
|
+
.description("Show security scan metrics")
|
|
468
|
+
.action(async () => {
|
|
469
|
+
const metrics = client.getMetrics();
|
|
470
|
+
const health = await client.getHealth();
|
|
471
|
+
|
|
472
|
+
console.log("\nSecurity Scan Metrics:\n");
|
|
473
|
+
console.log(`Connection: ${health.status}`);
|
|
474
|
+
console.log(`Active Scans: ${client.getActiveScanCount()}`);
|
|
475
|
+
console.log(`Total Scans: ${metrics.totalScans}`);
|
|
476
|
+
console.log(`Completed: ${metrics.completedScans}`);
|
|
477
|
+
console.log(`Failed: ${metrics.failedScans}`);
|
|
478
|
+
console.log(`Success Rate: ${metrics.totalScans > 0 ? Math.round((metrics.completedScans / metrics.totalScans) * 100) : 0}%`);
|
|
479
|
+
if (metrics.totalScans > 0) {
|
|
480
|
+
console.log(`Avg Duration: ${Math.round(metrics.totalDurationMs / metrics.totalScans)}ms`);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
},
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
export default definition;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@poolbot/hexstrike-bridge",
|
|
3
|
+
"version": "2026.3.11",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "HexStrike AI security tools bridge for PoolBot - integrates 150+ security scanners",
|
|
6
|
+
"poolbot": {
|
|
7
|
+
"extensions": [
|
|
8
|
+
"./src/index.ts"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"zod": "^3.22.4"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"poolbot": "workspace:*"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Mavalie Plugin for PoolBot
|
|
2
|
+
|
|
3
|
+
Plugin template válido para PoolBot.
|
|
4
|
+
|
|
5
|
+
## Estrutura
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
extensions/mavalie/
|
|
9
|
+
├── package.json # Manifest do plugin
|
|
10
|
+
├── src/
|
|
11
|
+
│ └── index.ts # Entry point
|
|
12
|
+
└── README.md # Esta documentação
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Instalação
|
|
16
|
+
|
|
17
|
+
1. **Build do plugin:**
|
|
18
|
+
```bash
|
|
19
|
+
cd extensions/mavalie
|
|
20
|
+
npm install
|
|
21
|
+
npm run build # ou pnpm build
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
2. **Ativação no PoolBot:**
|
|
25
|
+
O plugin é carregado automaticamente pelo PoolBot quando:
|
|
26
|
+
- O diretório está em `extensions/mavalie/`
|
|
27
|
+
- O `package.json` tem a seção `poolbot.extensions` configurada
|
|
28
|
+
- O entry point (`dist/index.js`) existe
|
|
29
|
+
|
|
30
|
+
## Configuração
|
|
31
|
+
|
|
32
|
+
O plugin usa `emptyPluginConfigSchema()`, ou seja, não requer configuração.
|
|
33
|
+
|
|
34
|
+
Para adicionar configurações, substitua por:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { z } from "zod";
|
|
38
|
+
|
|
39
|
+
const configSchema = z.object({
|
|
40
|
+
apiKey: z.string().optional(),
|
|
41
|
+
endpoint: z.string().url().default("https://api.mavalie.com"),
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Desenvolvimento
|
|
46
|
+
|
|
47
|
+
### Padrões de Plugin
|
|
48
|
+
|
|
49
|
+
O PoolBot suporta 4 tipos de extensões:
|
|
50
|
+
|
|
51
|
+
1. **Provider** - Adiciona novos modelos LLM
|
|
52
|
+
2. **Channel** - Adiciona canais de comunicação (Discord, Slack, etc)
|
|
53
|
+
3. **Tool** - Adiciona ferramentas para agentes
|
|
54
|
+
4. **Hook** - Intercepta eventos do ciclo de vida
|
|
55
|
+
|
|
56
|
+
### Exemplo: Registrando um Provider
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
api.registerProvider({
|
|
60
|
+
id: "mavalie",
|
|
61
|
+
label: "Mavalie AI",
|
|
62
|
+
auth: [{
|
|
63
|
+
id: "api-key",
|
|
64
|
+
kind: "apiKey",
|
|
65
|
+
run: async (ctx) => {
|
|
66
|
+
const key = await ctx.prompter.password({
|
|
67
|
+
message: "Mavalie API Key:"
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
profiles: [{
|
|
71
|
+
profileId: "mavalie:default",
|
|
72
|
+
credential: { type: "apiKey", key: String(key) }
|
|
73
|
+
}]
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}]
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Troubleshooting
|
|
81
|
+
|
|
82
|
+
### "plugin manifest not found"
|
|
83
|
+
- Verifique se `package.json` existe e tem `poolbot.extensions`
|
|
84
|
+
- Verifique se o caminho em `extensions` aponta para o arquivo correto
|
|
85
|
+
|
|
86
|
+
### "extension entry escapes package directory"
|
|
87
|
+
- O entry point deve estar dentro do diretório do plugin
|
|
88
|
+
- Use `./dist/index.js` (não `./src/index.ts` para produção)
|
|
89
|
+
|
|
90
|
+
### Erros de TypeScript "Cannot find module 'poolbot/plugin-sdk'"
|
|
91
|
+
- Normal durante desenvolvimento - o alias só resolve após build
|
|
92
|
+
- O build do PoolBot principal resolve essas dependências
|
|
93
|
+
|
|
94
|
+
## Referências
|
|
95
|
+
|
|
96
|
+
- [Plugin SDK Documentation](../../docs/refactor/plugin-sdk.md)
|
|
97
|
+
- [Exemplos de Plugins](../discord/, ../slack/, etc.)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@poolbot/mavalie",
|
|
3
|
+
"version": "2026.3.11",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Mavalie plugin for PoolBot - custom integration",
|
|
6
|
+
"poolbot": {
|
|
7
|
+
"extensions": [
|
|
8
|
+
"./src/index.ts"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"poolbot": "workspace:*"
|
|
14
|
+
}
|
|
15
|
+
}
|