@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,335 @@
1
+ /**
2
+ * HexStrike Client Tests
3
+ * Tests for the HexStrike AI HTTP client
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { HexStrikeClient, type HealthStatus, type ScanResult } from './client.js';
8
+
9
+ const mockFetch = vi.fn();
10
+ vi.stubGlobal('fetch', mockFetch);
11
+
12
+ describe('HexStrikeClient', () => {
13
+ let client: HexStrikeClient;
14
+
15
+ beforeEach(() => {
16
+ vi.clearAllMocks();
17
+ client = new HexStrikeClient({
18
+ host: '127.0.0.1',
19
+ port: 8888,
20
+ token: 'test-token',
21
+ });
22
+ });
23
+
24
+ afterEach(() => {
25
+ vi.clearAllMocks();
26
+ });
27
+
28
+ describe('Constructor', () => {
29
+ it('should create client with default config', () => {
30
+ const defaultClient = new HexStrikeClient();
31
+ expect(defaultClient).toBeDefined();
32
+ });
33
+
34
+ it('should create client with custom host', () => {
35
+ const customClient = new HexStrikeClient({ host: '192.168.1.100' });
36
+ expect(customClient).toBeDefined();
37
+ });
38
+
39
+ it('should create client with custom port', () => {
40
+ const customClient = new HexStrikeClient({ port: 9999 });
41
+ expect(customClient).toBeDefined();
42
+ });
43
+
44
+ it('should create client without token', () => {
45
+ const noTokenClient = new HexStrikeClient({ token: undefined });
46
+ expect(noTokenClient).toBeDefined();
47
+ });
48
+ });
49
+
50
+ describe('health()', () => {
51
+ it('should return health status on success', async () => {
52
+ const mockHealth: HealthStatus = {
53
+ status: 'healthy',
54
+ version: '6.0.0',
55
+ uptime: 3600,
56
+ };
57
+
58
+ mockFetch.mockResolvedValueOnce({
59
+ ok: true,
60
+ json: async () => mockHealth,
61
+ });
62
+
63
+ const result = await client.health();
64
+
65
+ expect(result).toEqual(mockHealth);
66
+ expect(mockFetch).toHaveBeenCalledWith('http://127.0.0.1:8888/health');
67
+ });
68
+
69
+ it('should throw error on health check failure', async () => {
70
+ mockFetch.mockResolvedValueOnce({
71
+ ok: false,
72
+ status: 503,
73
+ });
74
+
75
+ await expect(client.health()).rejects.toThrow('Health check failed: 503');
76
+ });
77
+
78
+ it('should handle network errors', async () => {
79
+ mockFetch.mockRejectedValueOnce(new Error('ECONNREFUSED'));
80
+
81
+ await expect(client.health()).rejects.toThrow('ECONNREFUSED');
82
+ });
83
+ });
84
+
85
+ describe('getTools()', () => {
86
+ it('should return list of available tools', async () => {
87
+ const mockTools = ['nmap', 'nuclei', 'sqlmap', 'gobuster', 'wpscan'];
88
+
89
+ mockFetch.mockResolvedValueOnce({
90
+ ok: true,
91
+ json: async () => ({ tools: mockTools }),
92
+ });
93
+
94
+ const result = await client.getTools();
95
+
96
+ expect(result).toEqual(mockTools);
97
+ expect(mockFetch).toHaveBeenCalledWith('http://127.0.0.1:8888/api/tools', {
98
+ headers: {
99
+ 'Content-Type': 'application/json',
100
+ 'Authorization': 'Bearer test-token',
101
+ },
102
+ });
103
+ });
104
+
105
+ it('should return empty array when tools is undefined', async () => {
106
+ mockFetch.mockResolvedValueOnce({
107
+ ok: true,
108
+ json: async () => ({}),
109
+ });
110
+
111
+ const result = await client.getTools();
112
+
113
+ expect(result).toEqual([]);
114
+ });
115
+
116
+ it('should throw error on failure', async () => {
117
+ mockFetch.mockResolvedValueOnce({
118
+ ok: false,
119
+ status: 500,
120
+ });
121
+
122
+ await expect(client.getTools()).rejects.toThrow('Failed to get tools: 500');
123
+ });
124
+
125
+ it('should include authorization header when token is provided', async () => {
126
+ mockFetch.mockResolvedValueOnce({
127
+ ok: true,
128
+ json: async () => ({ tools: [] }),
129
+ });
130
+
131
+ await client.getTools();
132
+
133
+ expect(mockFetch).toHaveBeenCalledWith(
134
+ expect.any(String),
135
+ expect.objectContaining({
136
+ headers: expect.objectContaining({
137
+ 'Authorization': 'Bearer test-token',
138
+ }),
139
+ })
140
+ );
141
+ });
142
+
143
+ it('should not include authorization header when token is not provided', async () => {
144
+ const noTokenClient = new HexStrikeClient({ token: undefined });
145
+ mockFetch.mockResolvedValueOnce({
146
+ ok: true,
147
+ json: async () => ({ tools: [] }),
148
+ });
149
+
150
+ await noTokenClient.getTools();
151
+
152
+ expect(mockFetch).toHaveBeenCalledWith(
153
+ expect.any(String),
154
+ expect.objectContaining({
155
+ headers: expect.not.objectContaining({
156
+ 'Authorization': expect.any(String),
157
+ }),
158
+ })
159
+ );
160
+ });
161
+ });
162
+
163
+ describe('scan()', () => {
164
+ it('should start scan with target only', async () => {
165
+ const mockResponse = { id: 'scan-123' };
166
+
167
+ mockFetch.mockResolvedValueOnce({
168
+ ok: true,
169
+ json: async () => mockResponse,
170
+ });
171
+
172
+ const result = await client.scan({ target: 'https://example.com' });
173
+
174
+ expect(result).toEqual({ scanId: 'scan-123' });
175
+ expect(mockFetch).toHaveBeenCalledWith('http://127.0.0.1:8888/api/scan', {
176
+ method: 'POST',
177
+ headers: {
178
+ 'Content-Type': 'application/json',
179
+ 'Authorization': 'Bearer test-token',
180
+ },
181
+ body: JSON.stringify({ target: 'https://example.com' }),
182
+ });
183
+ });
184
+
185
+ it('should start scan with specific scanners', async () => {
186
+ mockFetch.mockResolvedValueOnce({
187
+ ok: true,
188
+ json: async () => ({ id: 'scan-456' }),
189
+ });
190
+
191
+ await client.scan({
192
+ target: 'https://example.com',
193
+ scanners: ['nmap', 'nuclei'],
194
+ });
195
+
196
+ expect(mockFetch).toHaveBeenCalledWith(
197
+ expect.any(String),
198
+ expect.objectContaining({
199
+ body: JSON.stringify({
200
+ target: 'https://example.com',
201
+ scanners: ['nmap', 'nuclei'],
202
+ }),
203
+ })
204
+ );
205
+ });
206
+
207
+ it('should start scan with custom options', async () => {
208
+ mockFetch.mockResolvedValueOnce({
209
+ ok: true,
210
+ json: async () => ({ id: 'scan-789' }),
211
+ });
212
+
213
+ await client.scan({
214
+ target: '192.168.1.1',
215
+ options: { timeout: 300, threads: 10 },
216
+ });
217
+
218
+ expect(mockFetch).toHaveBeenCalledWith(
219
+ expect.any(String),
220
+ expect.objectContaining({
221
+ body: JSON.stringify({
222
+ target: '192.168.1.1',
223
+ options: { timeout: 300, threads: 10 },
224
+ }),
225
+ })
226
+ );
227
+ });
228
+
229
+ it('should throw error on scan failure', async () => {
230
+ mockFetch.mockResolvedValueOnce({
231
+ ok: false,
232
+ status: 400,
233
+ });
234
+
235
+ await expect(client.scan({ target: 'invalid' })).rejects.toThrow('Scan failed: 400');
236
+ });
237
+
238
+ it('should handle network errors', async () => {
239
+ mockFetch.mockRejectedValueOnce(new Error('ENOTFOUND'));
240
+
241
+ await expect(client.scan({ target: 'https://example.com' }))
242
+ .rejects.toThrow('ENOTFOUND');
243
+ });
244
+ });
245
+
246
+ describe('getScanResult()', () => {
247
+ it('should return scan result on success', async () => {
248
+ const mockResult: ScanResult = {
249
+ id: 'scan-123',
250
+ status: 'completed',
251
+ findings: [
252
+ {
253
+ severity: 'high',
254
+ title: 'SQL Injection',
255
+ description: 'SQL injection vulnerability found',
256
+ remediation: 'Use parameterized queries',
257
+ },
258
+ {
259
+ severity: 'medium',
260
+ title: 'XSS Vulnerability',
261
+ description: 'Cross-site scripting vulnerability',
262
+ },
263
+ ],
264
+ metadata: {
265
+ startedAt: '2026-03-12T10:00:00Z',
266
+ completedAt: '2026-03-12T10:30:00Z',
267
+ duration: 1800,
268
+ },
269
+ };
270
+
271
+ mockFetch.mockResolvedValueOnce({
272
+ ok: true,
273
+ json: async () => mockResult,
274
+ });
275
+
276
+ const result = await client.getScanResult('scan-123');
277
+
278
+ expect(result).toEqual(mockResult);
279
+ expect(mockFetch).toHaveBeenCalledWith('http://127.0.0.1:8888/api/scan/scan-123', {
280
+ headers: {
281
+ 'Content-Type': 'application/json',
282
+ 'Authorization': 'Bearer test-token',
283
+ },
284
+ });
285
+ });
286
+
287
+ it('should handle scan with no findings', async () => {
288
+ mockFetch.mockResolvedValueOnce({
289
+ ok: true,
290
+ json: async () => ({
291
+ id: 'scan-456',
292
+ status: 'completed',
293
+ findings: [],
294
+ metadata: {
295
+ startedAt: '2026-03-12T10:00:00Z',
296
+ completedAt: '2026-03-12T10:05:00Z',
297
+ },
298
+ }),
299
+ });
300
+
301
+ const result = await client.getScanResult('scan-456');
302
+
303
+ expect(result.findings).toEqual([]);
304
+ });
305
+
306
+ it('should handle running scan', async () => {
307
+ mockFetch.mockResolvedValueOnce({
308
+ ok: true,
309
+ json: async () => ({
310
+ id: 'scan-789',
311
+ status: 'running',
312
+ findings: [],
313
+ metadata: {
314
+ startedAt: '2026-03-12T10:00:00Z',
315
+ },
316
+ }),
317
+ });
318
+
319
+ const result = await client.getScanResult('scan-789');
320
+
321
+ expect(result.status).toBe('running');
322
+ expect(result.metadata.completedAt).toBeUndefined();
323
+ });
324
+
325
+ it('should throw error on failure', async () => {
326
+ mockFetch.mockResolvedValueOnce({
327
+ ok: false,
328
+ status: 404,
329
+ });
330
+
331
+ await expect(client.getScanResult('non-existent'))
332
+ .rejects.toThrow('Failed to get scan: 404');
333
+ });
334
+ });
335
+ });
@@ -0,0 +1,286 @@
1
+ /**
2
+ * HexStrike Server Manager Tests
3
+ * Tests for the HexStrike Python server process manager
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { HexStrikeServerManager } from './server-manager.js';
8
+ import { spawn } from 'node:child_process';
9
+ import EventEmitter from 'node:events';
10
+
11
+ vi.mock('node:child_process', () => ({
12
+ spawn: vi.fn(),
13
+ }));
14
+
15
+ describe('HexStrikeServerManager', () => {
16
+ let serverManager: HexStrikeServerManager;
17
+ let mockProcess: any;
18
+ let mockStdout: EventEmitter;
19
+ let mockStderr: EventEmitter;
20
+
21
+ beforeEach(() => {
22
+ vi.clearAllMocks();
23
+
24
+ mockStdout = new EventEmitter();
25
+ mockStderr = new EventEmitter();
26
+ mockProcess = {
27
+ stdout: mockStdout,
28
+ stderr: mockStderr,
29
+ on: vi.fn(),
30
+ kill: vi.fn(),
31
+ killed: false,
32
+ };
33
+
34
+ vi.mocked(spawn).mockReturnValue(mockProcess);
35
+
36
+ serverManager = new HexStrikeServerManager({
37
+ port: 8888,
38
+ host: '127.0.0.1',
39
+ pythonPath: 'python3',
40
+ });
41
+ });
42
+
43
+ afterEach(() => {
44
+ vi.clearAllMocks();
45
+ });
46
+
47
+ describe('Constructor', () => {
48
+ it('should create server manager with default config', () => {
49
+ const defaultManager = new HexStrikeServerManager();
50
+ expect(defaultManager).toBeDefined();
51
+ });
52
+
53
+ it('should create server manager with custom port', () => {
54
+ const customManager = new HexStrikeServerManager({ port: 9999 });
55
+ expect(customManager).toBeDefined();
56
+ });
57
+
58
+ it('should create server manager with custom host', () => {
59
+ const customManager = new HexStrikeServerManager({ host: '0.0.0.0' });
60
+ expect(customManager).toBeDefined();
61
+ });
62
+
63
+ it('should create server manager with custom python path', () => {
64
+ const customManager = new HexStrikeServerManager({ pythonPath: '/usr/bin/python3.11' });
65
+ expect(customManager).toBeDefined();
66
+ });
67
+
68
+ it('should use defaults for missing config values', () => {
69
+ const partialManager = new HexStrikeServerManager({});
70
+ expect(partialManager).toBeDefined();
71
+ });
72
+ });
73
+
74
+ describe('start()', () => {
75
+ it('should spawn Python process with correct arguments', async () => {
76
+ mockProcess.on = vi.fn();
77
+
78
+ setTimeout(() => {
79
+ mockStdout.emit('data', Buffer.from('Server started on port 8888'));
80
+ }, 10);
81
+
82
+ await serverManager.start();
83
+
84
+ expect(spawn).toHaveBeenCalledWith('python3', expect.any(Array), {
85
+ env: expect.objectContaining({
86
+ HEXSTRIKE_PORT: '8888',
87
+ HEXSTRIKE_HOST: '127.0.0.1',
88
+ }),
89
+ stdio: ['ignore', 'pipe', 'pipe'],
90
+ });
91
+ });
92
+
93
+ it('should set environment variables correctly', async () => {
94
+ mockProcess.on = vi.fn();
95
+
96
+ setTimeout(() => {
97
+ mockStdout.emit('data', Buffer.from('Server started'));
98
+ }, 10);
99
+
100
+ await serverManager.start();
101
+
102
+ const spawnCall = vi.mocked(spawn).mock.calls[0];
103
+ const options = spawnCall[2];
104
+
105
+ expect(options?.env).toEqual(
106
+ expect.objectContaining({
107
+ HEXSTRIKE_PORT: '8888',
108
+ HEXSTRIKE_HOST: '127.0.0.1',
109
+ })
110
+ );
111
+ });
112
+
113
+ it('should resolve promise when server starts', async () => {
114
+ mockProcess.on = vi.fn();
115
+
116
+ setTimeout(() => {
117
+ mockStdout.emit('data', Buffer.from('Server started on port 8888'));
118
+ }, 10);
119
+
120
+ await expect(serverManager.start()).resolves.toBeUndefined();
121
+ });
122
+
123
+ it('should resolve on "Listening" message', async () => {
124
+ mockProcess.on = vi.fn();
125
+
126
+ setTimeout(() => {
127
+ mockStdout.emit('data', Buffer.from('Listening on 127.0.0.1:8888'));
128
+ }, 10);
129
+
130
+ await expect(serverManager.start()).resolves.toBeUndefined();
131
+ });
132
+
133
+ it('should reject on timeout', async () => {
134
+ mockProcess.on = vi.fn();
135
+
136
+ vi.useFakeTimers();
137
+
138
+ const startPromise = serverManager.start();
139
+
140
+ vi.advanceTimersByTime(30000);
141
+
142
+ await expect(startPromise).rejects.toThrow('HexStrike server failed to start within 30s');
143
+
144
+ vi.useRealTimers();
145
+ });
146
+
147
+ it('should reject on spawn error', async () => {
148
+ const error = new Error('python3 not found');
149
+ mockProcess.on = vi.fn((event: string, callback: any) => {
150
+ if (event === 'error') {
151
+ setTimeout(() => callback(error), 10);
152
+ }
153
+ return mockProcess;
154
+ });
155
+
156
+ await expect(serverManager.start()).rejects.toThrow('python3 not found');
157
+ });
158
+
159
+ it('should reject on non-zero exit code', async () => {
160
+ mockProcess.on = vi.fn((event: string, callback: any) => {
161
+ if (event === 'exit') {
162
+ setTimeout(() => callback(1, null), 10);
163
+ }
164
+ return mockProcess;
165
+ });
166
+
167
+ await expect(serverManager.start()).rejects.toThrow('HexStrike server exited with code 1');
168
+ });
169
+
170
+ it('should log stdout output', async () => {
171
+ const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
172
+
173
+ mockProcess.on = vi.fn();
174
+
175
+ setTimeout(() => {
176
+ mockStdout.emit('data', Buffer.from('[INFO] Server starting'));
177
+ }, 10);
178
+
179
+ await serverManager.start();
180
+
181
+ expect(consoleLogSpy).toHaveBeenCalledWith('[HexStrike] [INFO] Server starting');
182
+
183
+ consoleLogSpy.mockRestore();
184
+ });
185
+
186
+ it('should log stderr output', async () => {
187
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
188
+
189
+ mockProcess.on = vi.fn();
190
+
191
+ setTimeout(() => {
192
+ mockStderr.emit('data', Buffer.from('[ERROR] Something went wrong'));
193
+ }, 10);
194
+
195
+ serverManager.start().catch(() => {});
196
+
197
+ expect(consoleErrorSpy).toHaveBeenCalledWith('[HexStrike] [ERROR] Something went wrong');
198
+
199
+ consoleErrorSpy.mockRestore();
200
+ });
201
+ });
202
+
203
+ describe('stop()', () => {
204
+ it('should kill running process with SIGTERM', async () => {
205
+ serverManager = new HexStrikeServerManager();
206
+ (serverManager as any).process = mockProcess;
207
+
208
+ await serverManager.stop();
209
+
210
+ expect(mockProcess.kill).toHaveBeenCalledWith('SIGTERM');
211
+ });
212
+
213
+ it('should wait for process to exit', async () => {
214
+ serverManager = new HexStrikeServerManager();
215
+ (serverManager as any).process = mockProcess;
216
+
217
+ const setTimeoutSpy = vi.spyOn(global, 'setTimeout').mockImplementation((callback: any) => {
218
+ callback();
219
+ return 0 as any;
220
+ });
221
+
222
+ await serverManager.stop();
223
+
224
+ expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 5000);
225
+
226
+ setTimeoutSpy.mockRestore();
227
+ });
228
+
229
+ it('should use SIGKILL if process does not exit', async () => {
230
+ serverManager = new HexStrikeServerManager();
231
+ (serverManager as any).process = {
232
+ ...mockProcess,
233
+ killed: false,
234
+ };
235
+
236
+ await serverManager.stop();
237
+
238
+ expect(mockProcess.kill).toHaveBeenCalledWith('SIGKILL');
239
+ });
240
+
241
+ it('should set process to null after stop', async () => {
242
+ serverManager = new HexStrikeServerManager();
243
+ (serverManager as any).process = mockProcess;
244
+
245
+ await serverManager.stop();
246
+
247
+ expect((serverManager as any).process).toBeNull();
248
+ });
249
+
250
+ it('should do nothing if process is not running', async () => {
251
+ serverManager = new HexStrikeServerManager();
252
+ (serverManager as any).process = null;
253
+
254
+ await serverManager.stop();
255
+
256
+ expect(mockProcess.kill).not.toHaveBeenCalled();
257
+ });
258
+ });
259
+
260
+ describe('isRunning', () => {
261
+ it('should return true when process is running', () => {
262
+ serverManager = new HexStrikeServerManager();
263
+ (serverManager as any).process = {
264
+ killed: false,
265
+ };
266
+
267
+ expect(serverManager.isRunning).toBe(true);
268
+ });
269
+
270
+ it('should return false when process is null', () => {
271
+ serverManager = new HexStrikeServerManager();
272
+ (serverManager as any).process = null;
273
+
274
+ expect(serverManager.isRunning).toBe(false);
275
+ });
276
+
277
+ it('should return false when process is killed', () => {
278
+ serverManager = new HexStrikeServerManager();
279
+ (serverManager as any).process = {
280
+ killed: true,
281
+ };
282
+
283
+ expect(serverManager.isRunning).toBe(false);
284
+ });
285
+ });
286
+ });
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "page-agent",
3
+ "name": "Page Agent",
4
+ "description": "GUI Browser Automation for PoolBot with AI-powered web interaction",
5
+ "version": "2026.3.14",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "headless": {
11
+ "type": "boolean",
12
+ "default": true,
13
+ "description": "Run browser in headless mode"
14
+ },
15
+ "viewport": {
16
+ "type": "object",
17
+ "properties": {
18
+ "width": { "type": "number", "default": 1280 },
19
+ "height": { "type": "number", "default": 720 }
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "id": "xyops",
3
+ "name": "XYOps",
4
+ "description": "Workflow automation and job scheduling for PoolBot",
5
+ "version": "2026.3.14",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "apiKey": {
11
+ "type": "string",
12
+ "description": "XYOps API key"
13
+ },
14
+ "endpoint": {
15
+ "type": "string",
16
+ "format": "uri",
17
+ "description": "XYOps API endpoint"
18
+ }
19
+ }
20
+ }
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/pool-bot",
3
- "version": "2026.3.14",
3
+ "version": "2026.3.16",
4
4
  "description": "🎱 Pool Bot - AI assistant with PLCODE integrations",
5
5
  "keywords": [],
6
6
  "license": "MIT",