@poolzin/pool-bot 2026.3.14 → 2026.3.16

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 (44) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/agents/checkpoint-manager.js +1 -2
  3. package/dist/build-info.json +3 -3
  4. package/docs/assets-evaluation.md +418 -0
  5. package/docs/commit-evaluation-42f463de4.md +362 -0
  6. package/docs/extensions-evaluation.md +696 -0
  7. package/docs/hexstrike-evaluation.md +514 -0
  8. package/docs/implementations-summary.md +300 -0
  9. package/extensions/agency-agents/poolbot.plugin.json +11 -0
  10. package/extensions/dexter/README.md +147 -0
  11. package/extensions/dexter/dist/agent.d.ts +44 -0
  12. package/extensions/dexter/dist/agent.js +265 -0
  13. package/extensions/dexter/dist/index.d.ts +12 -0
  14. package/extensions/dexter/dist/index.js +99 -0
  15. package/extensions/dexter/node_modules/.bin/tsc +21 -0
  16. package/extensions/dexter/node_modules/.bin/tsserver +21 -0
  17. package/extensions/dexter/package.json +33 -0
  18. package/extensions/dexter/poolbot.plugin.json +35 -0
  19. package/extensions/dexter/src/agent.ts +375 -0
  20. package/extensions/dexter/src/index.ts +129 -0
  21. package/extensions/dexter/tsconfig.json +20 -0
  22. package/extensions/hackingtool/README.md +75 -0
  23. package/extensions/hackingtool/dist/client.d.ts +34 -0
  24. package/extensions/hackingtool/dist/client.js +82 -0
  25. package/extensions/hackingtool/dist/index.d.ts +12 -0
  26. package/extensions/hackingtool/dist/index.js +163 -0
  27. package/extensions/hackingtool/dist/server-manager.d.ts +25 -0
  28. package/extensions/hackingtool/dist/server-manager.js +107 -0
  29. package/extensions/hackingtool/node_modules/.bin/tsc +21 -0
  30. package/extensions/hackingtool/node_modules/.bin/tsserver +21 -0
  31. package/extensions/hackingtool/package.json +36 -0
  32. package/extensions/hackingtool/poolbot.plugin.json +55 -0
  33. package/extensions/hackingtool/src/client.ts +120 -0
  34. package/extensions/hackingtool/src/index.ts +181 -0
  35. package/extensions/hackingtool/src/server/hackingtool_mcp.py +454 -0
  36. package/extensions/hackingtool/src/server/requirements.txt +2 -0
  37. package/extensions/hackingtool/src/server-manager.ts +128 -0
  38. package/extensions/hackingtool/tsconfig.json +20 -0
  39. package/extensions/hexstrike-ai/README.md +693 -44
  40. package/extensions/hexstrike-ai/src/client.test.ts +335 -0
  41. package/extensions/hexstrike-ai/src/server-manager.test.ts +286 -0
  42. package/extensions/page-agent/poolbot.plugin.json +24 -0
  43. package/extensions/xyops/poolbot.plugin.json +21 -0
  44. package/package.json +1 -1
@@ -0,0 +1,82 @@
1
+ import { EventEmitter } from "events";
2
+ export class HackingToolClient extends EventEmitter {
3
+ baseUrl;
4
+ token;
5
+ constructor(config = {}) {
6
+ super();
7
+ const host = config.host ?? "127.0.0.1";
8
+ const port = config.port ?? 8889;
9
+ this.baseUrl = `http://${host}:${port}`;
10
+ this.token = config.token;
11
+ }
12
+ async health() {
13
+ const response = await fetch(`${this.baseUrl}/health`);
14
+ if (!response.ok) {
15
+ throw new Error(`Health check failed: ${response.statusText}`);
16
+ }
17
+ return response.json();
18
+ }
19
+ async getTools() {
20
+ const response = await fetch(`${this.baseUrl}/tools`);
21
+ if (!response.ok) {
22
+ throw new Error(`Failed to get tools: ${response.statusText}`);
23
+ }
24
+ return response.json();
25
+ }
26
+ async runTool(category, toolName, target, options) {
27
+ const response = await fetch(`${this.baseUrl}/run_tool`, {
28
+ method: "POST",
29
+ headers: {
30
+ "Content-Type": "application/json",
31
+ ...(this.token ? { Authorization: `Bearer ${this.token}` } : {}),
32
+ },
33
+ body: JSON.stringify({
34
+ method: "run_tool",
35
+ params: {
36
+ category,
37
+ tool_name: toolName,
38
+ target,
39
+ options,
40
+ },
41
+ }),
42
+ });
43
+ if (!response.ok) {
44
+ throw new Error(`Tool execution failed: ${response.statusText}`);
45
+ }
46
+ const data = await response.json();
47
+ return {
48
+ scanId: data.result.scan_id,
49
+ status: data.result.status,
50
+ category,
51
+ tool: toolName,
52
+ target,
53
+ result: data.result.result,
54
+ error: data.result.error,
55
+ };
56
+ }
57
+ async getScanStatus(scanId) {
58
+ const response = await fetch(`${this.baseUrl}/scan/${scanId}`);
59
+ if (!response.ok) {
60
+ throw new Error(`Failed to get scan status: ${response.statusText}`);
61
+ }
62
+ const data = await response.json();
63
+ return {
64
+ scanId,
65
+ status: data.status,
66
+ category: data.category,
67
+ tool: data.tool,
68
+ target: data.target,
69
+ startedAt: data.started_at,
70
+ completedAt: data.completed_at,
71
+ result: data.result,
72
+ error: data.error,
73
+ };
74
+ }
75
+ async listScans() {
76
+ const response = await fetch(`${this.baseUrl}/scans`);
77
+ if (!response.ok) {
78
+ throw new Error(`Failed to list scans: ${response.statusText}`);
79
+ }
80
+ return response.json();
81
+ }
82
+ }
@@ -0,0 +1,12 @@
1
+ import { HackingToolServerManager } from "./server-manager.js";
2
+ import { HackingToolClient } from "./client.js";
3
+ interface HackingToolConfig {
4
+ port?: number;
5
+ host?: string;
6
+ autoStart?: boolean;
7
+ token?: string;
8
+ pythonPath?: string;
9
+ }
10
+ export default function createPlugin(ctx: any): Promise<any>;
11
+ export { HackingToolServerManager, HackingToolClient };
12
+ export type { HackingToolConfig };
@@ -0,0 +1,163 @@
1
+ import { HackingToolServerManager } from "./server-manager.js";
2
+ import { HackingToolClient } from "./client.js";
3
+ export default async function createPlugin(ctx) {
4
+ const config = ctx.config;
5
+ const serverManager = new HackingToolServerManager({
6
+ port: config.port,
7
+ host: config.host,
8
+ pythonPath: config.pythonPath,
9
+ });
10
+ const client = new HackingToolClient({
11
+ host: config.host,
12
+ port: config.port,
13
+ token: config.token,
14
+ });
15
+ if (config.autoStart !== false) {
16
+ ctx.logger.info("Starting HackingTool MCP server...");
17
+ try {
18
+ await serverManager.start();
19
+ ctx.logger.info("HackingTool MCP server started successfully");
20
+ }
21
+ catch (err) {
22
+ ctx.logger.error("Failed to start HackingTool MCP server:", err);
23
+ throw err;
24
+ }
25
+ }
26
+ ctx.cli
27
+ .command("pentest.status")
28
+ .description("Check HackingTool server status")
29
+ .action(async () => {
30
+ try {
31
+ const health = await client.health();
32
+ console.log("✅ HackingTool is running");
33
+ console.log(" Status:", health.status);
34
+ console.log(" Version:", health.version ?? "unknown");
35
+ console.log(" Uptime:", health.uptime ? `${Math.floor(health.uptime / 60)}m` : "N/A");
36
+ console.log(" Tools Available:", health.toolsAvailable);
37
+ console.log(" Active Scans:", health.activeScans);
38
+ }
39
+ catch (err) {
40
+ console.error("❌ HackingTool is not running");
41
+ console.error(" Error:", err instanceof Error ? err.message : String(err));
42
+ process.exit(1);
43
+ }
44
+ });
45
+ ctx.cli
46
+ .command("pentest.tools")
47
+ .description("List available penetration testing tools")
48
+ .action(async () => {
49
+ try {
50
+ const tools = await client.getTools();
51
+ console.log("🔧 Available Penetration Testing Tools:\n");
52
+ for (const [category, toolList] of Object.entries(tools)) {
53
+ if (Array.isArray(toolList)) {
54
+ console.log(`📁 ${category.toUpperCase().replace("_", " ")}`);
55
+ for (const tool of toolList.slice(0, 10)) {
56
+ console.log(` • ${tool}`);
57
+ }
58
+ if (toolList.length > 10) {
59
+ console.log(` ... and ${toolList.length - 10} more`);
60
+ }
61
+ console.log();
62
+ }
63
+ else {
64
+ console.log(`📁 ${category.toUpperCase().replace("_", " ")}`);
65
+ const subCategories = toolList;
66
+ for (const [subcat, subtools] of Object.entries(subCategories)) {
67
+ console.log(` ${subcat.replace("_", " ")}: ${subtools.slice(0, 5).join(", ")}`);
68
+ if (subtools.length > 5) {
69
+ console.log(` ... and ${subtools.length - 5} more`);
70
+ }
71
+ }
72
+ console.log();
73
+ }
74
+ }
75
+ }
76
+ catch (err) {
77
+ console.error("❌ Failed to get tools:", err instanceof Error ? err.message : String(err));
78
+ process.exit(1);
79
+ }
80
+ });
81
+ ctx.cli
82
+ .command("pentest.scan")
83
+ .description("Run penetration testing tool")
84
+ .argument("<category>", "Tool category (e.g., information_gathering, sql_injection, web_attack)")
85
+ .argument("<tool>", "Tool name (e.g., nmap, sqlmap, dirb)")
86
+ .argument("[target]", "Target URL or IP (optional)")
87
+ .option("-o, --output <file>", "Save results to file")
88
+ .action(async (category, tool, target, options) => {
89
+ try {
90
+ console.log(`🚀 Running ${tool} from ${category}...`);
91
+ if (target) {
92
+ console.log(` Target: ${target}`);
93
+ }
94
+ const result = await client.runTool(category, tool, target);
95
+ console.log(`✅ Tool execution ${result.status}`);
96
+ console.log(` Scan ID: ${result.scanId}`);
97
+ if (result.result) {
98
+ if (result.result.simulated) {
99
+ console.log(` ℹ️ ${result.result.message}`);
100
+ }
101
+ else if (result.result.stdout) {
102
+ console.log("\n📊 Output:");
103
+ console.log(result.result.stdout);
104
+ }
105
+ else if (result.result.error) {
106
+ console.log(` ❌ Error: ${result.result.error}`);
107
+ }
108
+ }
109
+ if (options?.output && result.result) {
110
+ const fs = await import("fs");
111
+ fs.writeFileSync(options.output, JSON.stringify(result.result, null, 2));
112
+ console.log(`\n💾 Results saved to: ${options.output}`);
113
+ }
114
+ }
115
+ catch (err) {
116
+ console.error("❌ Scan failed:", err instanceof Error ? err.message : String(err));
117
+ process.exit(1);
118
+ }
119
+ });
120
+ ctx.cli
121
+ .command("pentest.scans")
122
+ .description("List active scans")
123
+ .action(async () => {
124
+ try {
125
+ const scans = await client.listScans();
126
+ if (scans.length === 0) {
127
+ console.log("ℹ️ No active scans");
128
+ return;
129
+ }
130
+ console.log("🔍 Active Scans:\n");
131
+ for (const scan of scans) {
132
+ const statusIcon = scan.status === "running" ? "🔄" : scan.status === "completed" ? "✅" : "❌";
133
+ console.log(`${statusIcon} ${scan.scanId} - ${scan.tool} (${scan.status})`);
134
+ if (scan.target) {
135
+ console.log(` Target: ${scan.target}`);
136
+ }
137
+ console.log(` Started: ${new Date((scan.startedAt || 0) * 1000).toLocaleString()}`);
138
+ console.log();
139
+ }
140
+ }
141
+ catch (err) {
142
+ console.error("❌ Failed to list scans:", err instanceof Error ? err.message : String(err));
143
+ process.exit(1);
144
+ }
145
+ });
146
+ ctx.cli
147
+ .command("pentest.stop")
148
+ .description("Stop HackingTool server")
149
+ .action(async () => {
150
+ ctx.logger.info("Stopping HackingTool server...");
151
+ await serverManager.stop();
152
+ console.log("✅ HackingTool server stopped");
153
+ });
154
+ return {
155
+ name: "hackingtool",
156
+ version: "1.2.0",
157
+ async onShutdown() {
158
+ ctx.logger.info("Stopping HackingTool server...");
159
+ await serverManager.stop();
160
+ },
161
+ };
162
+ }
163
+ export { HackingToolServerManager, HackingToolClient };
@@ -0,0 +1,25 @@
1
+ import { EventEmitter } from "events";
2
+ interface ServerManagerConfig {
3
+ port?: number;
4
+ host?: string;
5
+ pythonPath?: string;
6
+ }
7
+ export declare class HackingToolServerManager extends EventEmitter {
8
+ private port;
9
+ private host;
10
+ private pythonPath;
11
+ private process;
12
+ private isRunning;
13
+ private healthCheckInterval?;
14
+ constructor(config?: ServerManagerConfig);
15
+ start(): Promise<void>;
16
+ stop(): Promise<void>;
17
+ getStatus(): {
18
+ running: boolean;
19
+ port: number;
20
+ host: string;
21
+ };
22
+ private startHealthChecks;
23
+ private stopHealthChecks;
24
+ }
25
+ export {};
@@ -0,0 +1,107 @@
1
+ import { spawn } from "child_process";
2
+ import { EventEmitter } from "events";
3
+ import { dirname, resolve } from "path";
4
+ import { fileURLToPath } from "url";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ export class HackingToolServerManager extends EventEmitter {
7
+ port;
8
+ host;
9
+ pythonPath;
10
+ process = null;
11
+ isRunning = false;
12
+ healthCheckInterval;
13
+ constructor(config = {}) {
14
+ super();
15
+ this.port = config.port ?? 8889;
16
+ this.host = config.host ?? "127.0.0.1";
17
+ this.pythonPath = config.pythonPath ?? "python3";
18
+ }
19
+ async start() {
20
+ if (this.isRunning) {
21
+ throw new Error("Server is already running");
22
+ }
23
+ const serverScript = resolve(__dirname, "./server/hackingtool_mcp.py");
24
+ return new Promise((resolve, reject) => {
25
+ try {
26
+ this.process = spawn(this.pythonPath, [
27
+ serverScript,
28
+ "--port",
29
+ this.port.toString(),
30
+ "--host",
31
+ this.host,
32
+ ]);
33
+ this.process.stdout?.on("data", (data) => {
34
+ const output = data.toString();
35
+ this.emit("output", output);
36
+ if (output.includes("running on")) {
37
+ this.isRunning = true;
38
+ this.startHealthChecks();
39
+ resolve();
40
+ }
41
+ });
42
+ this.process.stderr?.on("data", (data) => {
43
+ const error = data.toString();
44
+ this.emit("error", error);
45
+ if (!this.isRunning) {
46
+ reject(new Error(`Server failed to start: ${error}`));
47
+ }
48
+ });
49
+ this.process.on("error", (err) => {
50
+ this.isRunning = false;
51
+ reject(new Error(`Spawn error: ${err.message}`));
52
+ });
53
+ this.process.on("exit", (code) => {
54
+ this.isRunning = false;
55
+ this.stopHealthChecks();
56
+ this.emit("exit", code);
57
+ });
58
+ setTimeout(() => {
59
+ if (!this.isRunning) {
60
+ reject(new Error("Server startup timeout"));
61
+ }
62
+ }, 10000);
63
+ }
64
+ catch (err) {
65
+ reject(err);
66
+ }
67
+ });
68
+ }
69
+ async stop() {
70
+ if (!this.process || !this.isRunning) {
71
+ return;
72
+ }
73
+ return new Promise((resolve) => {
74
+ this.stopHealthChecks();
75
+ this.process?.kill("SIGTERM");
76
+ this.isRunning = false;
77
+ this.process = null;
78
+ resolve();
79
+ });
80
+ }
81
+ getStatus() {
82
+ return {
83
+ running: this.isRunning,
84
+ port: this.port,
85
+ host: this.host,
86
+ };
87
+ }
88
+ startHealthChecks() {
89
+ this.healthCheckInterval = setInterval(async () => {
90
+ try {
91
+ const response = await fetch(`http://${this.host}:${this.port}/health`);
92
+ if (!response.ok) {
93
+ this.emit("health_check_failed", "Health check returned non-OK status");
94
+ }
95
+ }
96
+ catch (err) {
97
+ this.emit("health_check_failed", err instanceof Error ? err.message : String(err));
98
+ }
99
+ }, 30000);
100
+ }
101
+ stopHealthChecks() {
102
+ if (this.healthCheckInterval) {
103
+ clearInterval(this.healthCheckInterval);
104
+ this.healthCheckInterval = undefined;
105
+ }
106
+ }
107
+ }
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
19
+ else
20
+ exec node "$basedir/../typescript/bin/tsc" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
19
+ else
20
+ exec node "$basedir/../typescript/bin/tsserver" "$@"
21
+ fi
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@poolbot/hackingtool",
3
+ "version": "2026.3.12",
4
+ "description": "HackingTool Security Platform - 100+ Penetration Testing Tools for PoolBot",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "dev": "tsc --watch",
11
+ "start:server": "python3 src/server/hackingtool_mcp.py",
12
+ "install:deps": "pip3 install -r src/server/requirements.txt"
13
+ },
14
+ "dependencies": {
15
+ "poolbot": "workspace:*"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^22.0.0",
19
+ "typescript": "^5.0.0"
20
+ },
21
+ "poolbot": {
22
+ "plugin": true,
23
+ "server": true,
24
+ "python": true
25
+ },
26
+ "keywords": [
27
+ "security",
28
+ "pentest",
29
+ "penetration-testing",
30
+ "scanning",
31
+ "vulnerability-assessment",
32
+ "ethical-hacking"
33
+ ],
34
+ "author": "PoolBot Team",
35
+ "license": "MIT"
36
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "id": "hackingtool",
3
+ "name": "HackingTool",
4
+ "version": "1.2.0",
5
+ "description": "Comprehensive penetration testing platform with 100+ security tools for ethical hacking and vulnerability assessment",
6
+ "author": "PoolBot Team",
7
+ "main": "dist/index.js",
8
+ "capabilities": [
9
+ "security",
10
+ "pentest",
11
+ "vulnerability-assessment",
12
+ "scanning",
13
+ "reconnaissance",
14
+ "exploitation"
15
+ ],
16
+ "commands": [
17
+ "pentest.status",
18
+ "pentest.tools",
19
+ "pentest.scan",
20
+ "pentest.scans",
21
+ "pentest.stop"
22
+ ],
23
+ "hooks": ["onInit", "onShutdown"],
24
+ "config": {
25
+ "port": 8889,
26
+ "host": "127.0.0.1",
27
+ "autoStart": true,
28
+ "pythonPath": "python3",
29
+ "toolCategories": [
30
+ "anonymity",
31
+ "information_gathering",
32
+ "wordlist",
33
+ "wireless",
34
+ "sql_injection",
35
+ "phishing",
36
+ "web_attack",
37
+ "post_exploitation",
38
+ "forensic",
39
+ "payload",
40
+ "exploit",
41
+ "reverse_engineering",
42
+ "ddos",
43
+ "rat",
44
+ "xss",
45
+ "steganography"
46
+ ],
47
+ "maxConcurrentScans": 5,
48
+ "scanTimeout": 600
49
+ },
50
+ "permissions": [
51
+ "gateway.rpc",
52
+ "telemetry.events",
53
+ "config.read"
54
+ ]
55
+ }
@@ -0,0 +1,120 @@
1
+ import { EventEmitter } from "events";
2
+
3
+ interface HackingToolClientConfig {
4
+ host?: string;
5
+ port?: number;
6
+ token?: string;
7
+ }
8
+
9
+ interface ScanResult {
10
+ scanId: string;
11
+ status: "running" | "completed" | "failed";
12
+ category?: string;
13
+ tool?: string;
14
+ target?: string;
15
+ result?: any;
16
+ error?: string;
17
+ startedAt?: number;
18
+ completedAt?: number;
19
+ }
20
+
21
+ export class HackingToolClient extends EventEmitter {
22
+ private baseUrl: string;
23
+ private token?: string;
24
+
25
+ constructor(config: HackingToolClientConfig = {}) {
26
+ super();
27
+ const host = config.host ?? "127.0.0.1";
28
+ const port = config.port ?? 8889;
29
+ this.baseUrl = `http://${host}:${port}`;
30
+ this.token = config.token;
31
+ }
32
+
33
+ async health(): Promise<{
34
+ status: string;
35
+ version: string;
36
+ uptime: number;
37
+ activeScans: number;
38
+ toolsAvailable: number;
39
+ }> {
40
+ const response = await fetch(`${this.baseUrl}/health`);
41
+ if (!response.ok) {
42
+ throw new Error(`Health check failed: ${response.statusText}`);
43
+ }
44
+ return response.json();
45
+ }
46
+
47
+ async getTools(): Promise<Record<string, string[]>> {
48
+ const response = await fetch(`${this.baseUrl}/tools`);
49
+ if (!response.ok) {
50
+ throw new Error(`Failed to get tools: ${response.statusText}`);
51
+ }
52
+ return response.json();
53
+ }
54
+
55
+ async runTool(
56
+ category: string,
57
+ toolName: string,
58
+ target?: string,
59
+ options?: Record<string, any>
60
+ ): Promise<ScanResult> {
61
+ const response = await fetch(`${this.baseUrl}/run_tool`, {
62
+ method: "POST",
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ ...(this.token ? { Authorization: `Bearer ${this.token}` } : {}),
66
+ },
67
+ body: JSON.stringify({
68
+ method: "run_tool",
69
+ params: {
70
+ category,
71
+ tool_name: toolName,
72
+ target,
73
+ options,
74
+ },
75
+ }),
76
+ });
77
+
78
+ if (!response.ok) {
79
+ throw new Error(`Tool execution failed: ${response.statusText}`);
80
+ }
81
+
82
+ const data = await response.json();
83
+ return {
84
+ scanId: data.result.scan_id,
85
+ status: data.result.status,
86
+ category,
87
+ tool: toolName,
88
+ target,
89
+ result: data.result.result,
90
+ error: data.result.error,
91
+ };
92
+ }
93
+
94
+ async getScanStatus(scanId: string): Promise<ScanResult> {
95
+ const response = await fetch(`${this.baseUrl}/scan/${scanId}`);
96
+ if (!response.ok) {
97
+ throw new Error(`Failed to get scan status: ${response.statusText}`);
98
+ }
99
+ const data = await response.json();
100
+ return {
101
+ scanId,
102
+ status: data.status,
103
+ category: data.category,
104
+ tool: data.tool,
105
+ target: data.target,
106
+ startedAt: data.started_at,
107
+ completedAt: data.completed_at,
108
+ result: data.result,
109
+ error: data.error,
110
+ };
111
+ }
112
+
113
+ async listScans(): Promise<ScanResult[]> {
114
+ const response = await fetch(`${this.baseUrl}/scans`);
115
+ if (!response.ok) {
116
+ throw new Error(`Failed to list scans: ${response.statusText}`);
117
+ }
118
+ return response.json();
119
+ }
120
+ }