@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.
- package/CHANGELOG.md +40 -0
- package/README.md +147 -69
- package/dist/.buildstamp +1 -1
- package/dist/agents/error-classifier.js +251 -0
- package/dist/agents/skills/security.js +211 -0
- 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/lazy-commands.example.js +113 -0
- package/dist/cli/lazy-commands.js +329 -0
- package/dist/cli/program/command-registry.js +26 -0
- package/dist/cli/program/register.maintenance.js +21 -0
- package/dist/cli/program/register.skills.js +4 -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/config/config.js +1 -0
- package/dist/config/secrets-integration.js +88 -0
- package/dist/context-engine/index.js +33 -0
- package/dist/context-engine/legacy.js +179 -0
- package/dist/context-engine/registry.js +86 -0
- package/dist/context-engine/summarizing.js +290 -0
- package/dist/context-engine/types.js +7 -0
- 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 +106 -0
- package/dist/infra/retry.js +96 -0
- package/dist/secrets/index.js +28 -0
- package/dist/secrets/resolver.js +185 -0
- package/dist/secrets/runtime.js +142 -0
- package/dist/secrets/types.js +11 -0
- package/dist/security/dangerous-tools.js +80 -0
- package/dist/security/types.js +12 -0
- package/dist/skills/commands.js +333 -0
- package/dist/skills/index.js +164 -0
- package/dist/skills/loader.js +282 -0
- package/dist/skills/parser.js +446 -0
- package/dist/skills/registry.js +394 -0
- package/dist/skills/security.js +312 -0
- package/dist/skills/types.js +21 -0
- 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/test-utils/index.js +219 -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 +611 -0
- 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/INTEGRATION_PLAN.md +475 -0
- package/docs/INTEGRATION_SUMMARY.md +215 -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/HEXSTRIKE_PLAN.md +796 -0
- package/docs/integrations/INTEGRATION_PLAN.md +744 -0
- package/docs/integrations/PAGE_AGENT_PLAN.md +370 -0
- package/docs/integrations/XYOPS_PLAN.md +978 -0
- package/docs/models/provider-infrastructure.md +400 -0
- package/docs/security/exec-approvals.md +294 -0
- package/docs/skills/IMPLEMENTATION_SUMMARY.md +145 -0
- package/docs/skills/SKILL.md +524 -0
- package/docs/skills.md +405 -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 +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- 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 +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -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 +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +8 -1
- package/skills/example-skill/SKILL.md +195 -0
|
@@ -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.10",
|
|
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,14 @@
|
|
|
1
|
+
import type { PoolBotPluginApi } from "../../src/plugins/types.js";
|
|
2
|
+
|
|
3
|
+
import { createMcpServerService } from "./src/service.js";
|
|
4
|
+
|
|
5
|
+
const plugin = {
|
|
6
|
+
id: "mcp-server",
|
|
7
|
+
name: "MCP Server",
|
|
8
|
+
description: "MCP (Model Context Protocol) server - exposes PoolBot tools via MCP protocol",
|
|
9
|
+
register(api: PoolBotPluginApi) {
|
|
10
|
+
api.registerService(createMcpServerService());
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default plugin;
|