@poolzin/pool-bot 2026.3.7 → 2026.3.9

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 +16 -0
  2. package/dist/.buildstamp +1 -1
  3. package/dist/agents/error-classifier.js +302 -0
  4. package/dist/agents/skills/security.js +217 -0
  5. package/dist/build-info.json +3 -3
  6. package/dist/cli/lazy-commands.example.js +113 -0
  7. package/dist/cli/lazy-commands.js +329 -0
  8. package/dist/cli/program/command-registry.js +13 -0
  9. package/dist/cli/program/register.skills.js +4 -0
  10. package/dist/config/config.js +1 -0
  11. package/dist/config/secrets-integration.js +88 -0
  12. package/dist/context-engine/index.js +33 -0
  13. package/dist/context-engine/legacy.js +181 -0
  14. package/dist/context-engine/registry.js +86 -0
  15. package/dist/context-engine/summarizing.js +293 -0
  16. package/dist/context-engine/types.js +7 -0
  17. package/dist/infra/abort-pattern.js +106 -0
  18. package/dist/infra/retry.js +94 -0
  19. package/dist/secrets/index.js +28 -0
  20. package/dist/secrets/resolver.js +185 -0
  21. package/dist/secrets/runtime.js +142 -0
  22. package/dist/secrets/types.js +11 -0
  23. package/dist/security/dangerous-tools.js +80 -0
  24. package/dist/security/types.js +12 -0
  25. package/dist/skills/commands.js +351 -0
  26. package/dist/skills/index.js +167 -0
  27. package/dist/skills/loader.js +282 -0
  28. package/dist/skills/parser.js +461 -0
  29. package/dist/skills/registry.js +397 -0
  30. package/dist/skills/security.js +318 -0
  31. package/dist/skills/types.js +21 -0
  32. package/dist/test-utils/index.js +219 -0
  33. package/dist/tui/index.js +595 -0
  34. package/docs/INTEGRATION_PLAN.md +475 -0
  35. package/docs/INTEGRATION_SUMMARY.md +215 -0
  36. package/docs/integrations/HEXSTRIKE_PLAN.md +796 -0
  37. package/docs/integrations/INTEGRATION_PLAN.md +424 -0
  38. package/docs/integrations/PAGE_AGENT_PLAN.md +370 -0
  39. package/docs/integrations/XYOPS_PLAN.md +978 -0
  40. package/docs/skills/IMPLEMENTATION_SUMMARY.md +145 -0
  41. package/docs/skills/SKILL.md +524 -0
  42. package/docs/skills.md +405 -0
  43. package/package.json +1 -1
  44. package/skills/example-skill/SKILL.md +195 -0
@@ -0,0 +1,978 @@
1
+ # xyOps Integration - Implementation Plan
2
+
3
+ **Status**: Ready for implementation
4
+ **Priority**: High
5
+ **Estimated Duration**: 3 weeks
6
+ **Dependencies**: None (Node.js based)
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ Integrate xyOps as both a Plugin Extension and Gateway Node to enable workflow automation, job scheduling, and infrastructure monitoring within PoolBot.
13
+
14
+ ## Architecture
15
+
16
+ ```
17
+ ┌─────────────────────────────────────────────────────────────┐
18
+ │ PoolBot Core │
19
+ ├─────────────────────────────────────────────────────────────┤
20
+ │ Plugin Layer (Deep Integration) │
21
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
22
+ │ │ Workflow │ │ Schedule │ │ Monitor │ │
23
+ │ │ Engine │ │ Engine │ │ Engine │ │
24
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
25
+ ├─────────────────────────────────────────────────────────────┤
26
+ │ Gateway Node Layer (External Process Support) │
27
+ │ ┌─────────────────────────────────────────────────────┐ │
28
+ │ │ xyOps Gateway Node │ │
29
+ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │
30
+ │ │ │ Node Client │ │ xyOps Core │ │ Visual │ │ │
31
+ │ │ │ (WebSocket) │──│ │──│ Editor │ │ │
32
+ │ │ └──────────────┘ └──────────────┘ └──────────┘ │ │
33
+ │ └─────────────────────────────────────────────────────┘ │
34
+ └─────────────────────────────────────────────────────────────┘
35
+ ```
36
+
37
+ ## Integration Modes
38
+
39
+ | Mode | Use Case | Implementation |
40
+ |------|----------|----------------|
41
+ | **Plugin** | Single-instance, deep integration | Direct PoolBot extension |
42
+ | **Gateway Node** | Multi-instance, distributed | External process via WebSocket |
43
+ | **Hybrid** | Best of both | Plugin + optional external nodes |
44
+
45
+ ## Implementation Steps
46
+
47
+ ### Week 1: Plugin Foundation
48
+
49
+ #### Day 1-2: Plugin Structure
50
+ ```typescript
51
+ // extensions/xyops/src/plugin.ts
52
+ import { PoolBotPlugin, PluginContext } from '@poolbot/plugin-sdk';
53
+ import { WorkflowEngine } from './workflow/engine';
54
+ import { ScheduleEngine } from './schedule/engine';
55
+ import { MonitorEngine } from './monitor/engine';
56
+
57
+ export default class XyOpsPlugin implements PoolBotPlugin {
58
+ name = 'xyops';
59
+ version = '1.0.0';
60
+
61
+ private workflowEngine: WorkflowEngine;
62
+ private scheduleEngine: ScheduleEngine;
63
+ private monitorEngine: MonitorEngine;
64
+
65
+ async onLoad(context: PluginContext) {
66
+ // Initialize engines
67
+ this.workflowEngine = new WorkflowEngine(context);
68
+ this.scheduleEngine = new ScheduleEngine(context);
69
+ this.monitorEngine = new MonitorEngine(context);
70
+
71
+ // Register CLI commands
72
+ context.registerCommand({
73
+ name: 'workflow',
74
+ description: 'Manage workflows',
75
+ subcommands: [
76
+ { name: 'create', handler: this.handleWorkflowCreate },
77
+ { name: 'list', handler: this.handleWorkflowList },
78
+ { name: 'run', handler: this.handleWorkflowRun },
79
+ { name: 'delete', handler: this.handleWorkflowDelete }
80
+ ]
81
+ });
82
+
83
+ context.registerCommand({
84
+ name: 'schedule',
85
+ description: 'Manage scheduled jobs',
86
+ subcommands: [
87
+ { name: 'add', handler: this.handleScheduleAdd },
88
+ { name: 'list', handler: this.handleScheduleList },
89
+ { name: 'remove', handler: this.handleScheduleRemove }
90
+ ]
91
+ });
92
+
93
+ // Register skills
94
+ context.registerSkill({
95
+ name: 'workflow.create',
96
+ description: 'Create a new workflow',
97
+ parameters: z.object({
98
+ name: z.string(),
99
+ steps: z.array(z.object({
100
+ name: z.string(),
101
+ type: z.enum(['agent', 'tool', 'condition', 'loop']),
102
+ config: z.record(z.any())
103
+ }))
104
+ }),
105
+ handler: this.workflowEngine.create.bind(this.workflowEngine)
106
+ });
107
+
108
+ context.registerSkill({
109
+ name: 'schedule.cron',
110
+ description: 'Schedule a workflow with cron expression',
111
+ parameters: z.object({
112
+ workflowId: z.string(),
113
+ cron: z.string(),
114
+ enabled: z.boolean().optional()
115
+ }),
116
+ handler: this.scheduleEngine.schedule.bind(this.scheduleEngine)
117
+ });
118
+
119
+ context.registerSkill({
120
+ name: 'monitor.check',
121
+ description: 'Set up monitoring for a target',
122
+ parameters: z.object({
123
+ target: z.string(),
124
+ type: z.enum(['http', 'tcp', 'dns']),
125
+ interval: z.number(),
126
+ alerts: z.array(z.object({
127
+ condition: z.string(),
128
+ action: z.enum(['notify', 'webhook', 'workflow'])
129
+ }))
130
+ }),
131
+ handler: this.monitorEngine.addCheck.bind(this.monitorEngine)
132
+ });
133
+ }
134
+
135
+ async onReady() {
136
+ // Start scheduled jobs
137
+ await this.scheduleEngine.start();
138
+
139
+ // Start monitoring
140
+ await this.monitorEngine.start();
141
+ }
142
+
143
+ async onUnload() {
144
+ // Cleanup
145
+ await this.scheduleEngine.stop();
146
+ await this.monitorEngine.stop();
147
+ }
148
+ }
149
+ ```
150
+
151
+ #### Day 3-4: Workflow Engine
152
+ ```typescript
153
+ // extensions/xyops/src/workflow/engine.ts
154
+ export interface Workflow {
155
+ id: string;
156
+ name: string;
157
+ description?: string;
158
+ steps: WorkflowStep[];
159
+ variables: Record<string, any>;
160
+ createdAt: Date;
161
+ updatedAt: Date;
162
+ }
163
+
164
+ export interface WorkflowStep {
165
+ id: string;
166
+ name: string;
167
+ type: 'agent' | 'tool' | 'condition' | 'loop' | 'wait' | 'parallel';
168
+ config: Record<string, any>;
169
+ transitions: {
170
+ onSuccess?: string;
171
+ onFailure?: string;
172
+ onCondition?: {
173
+ condition: string;
174
+ target: string;
175
+ }[];
176
+ };
177
+ }
178
+
179
+ export class WorkflowEngine {
180
+ private workflows: Map<string, Workflow> = new Map();
181
+ private executions: Map<string, WorkflowExecution> = new Map();
182
+
183
+ async create(params: CreateWorkflowParams): Promise<Workflow> {
184
+ const workflow: Workflow = {
185
+ id: generateId(),
186
+ name: params.name,
187
+ description: params.description,
188
+ steps: params.steps,
189
+ variables: params.variables || {},
190
+ createdAt: new Date(),
191
+ updatedAt: new Date()
192
+ };
193
+
194
+ this.workflows.set(workflow.id, workflow);
195
+ await this.persistWorkflow(workflow);
196
+
197
+ return workflow;
198
+ }
199
+
200
+ async run(workflowId: string, inputs?: Record<string, any>): Promise<WorkflowResult> {
201
+ const workflow = this.workflows.get(workflowId);
202
+ if (!workflow) {
203
+ throw new Error(`Workflow ${workflowId} not found`);
204
+ }
205
+
206
+ const execution = new WorkflowExecution({
207
+ workflow,
208
+ inputs,
209
+ context: this.context
210
+ });
211
+
212
+ this.executions.set(execution.id, execution);
213
+
214
+ try {
215
+ const result = await execution.run();
216
+ return result;
217
+ } finally {
218
+ this.executions.delete(execution.id);
219
+ }
220
+ }
221
+
222
+ async executeStep(step: WorkflowStep, context: ExecutionContext): Promise<StepResult> {
223
+ switch (step.type) {
224
+ case 'agent':
225
+ return this.executeAgentStep(step, context);
226
+ case 'tool':
227
+ return this.executeToolStep(step, context);
228
+ case 'condition':
229
+ return this.executeConditionStep(step, context);
230
+ case 'loop':
231
+ return this.executeLoopStep(step, context);
232
+ case 'wait':
233
+ return this.executeWaitStep(step, context);
234
+ case 'parallel':
235
+ return this.executeParallelStep(step, context);
236
+ default:
237
+ throw new Error(`Unknown step type: ${step.type}`);
238
+ }
239
+ }
240
+
241
+ private async executeAgentStep(step: WorkflowStep, context: ExecutionContext): Promise<StepResult> {
242
+ const agent = await this.context.createAgent({
243
+ type: step.config.agentType || 'standard',
244
+ systemPrompt: step.config.systemPrompt
245
+ });
246
+
247
+ const result = await agent.execute({
248
+ message: step.config.prompt,
249
+ context: context.variables
250
+ });
251
+
252
+ return {
253
+ success: true,
254
+ output: result,
255
+ variables: {
256
+ [step.config.outputVar || 'result']: result
257
+ }
258
+ };
259
+ }
260
+
261
+ private async executeToolStep(step: WorkflowStep, context: ExecutionContext): Promise<StepResult> {
262
+ const result = await this.context.callTool({
263
+ tool: step.config.tool,
264
+ params: this.interpolateParams(step.config.params, context.variables)
265
+ });
266
+
267
+ return {
268
+ success: result.success,
269
+ output: result.data,
270
+ error: result.error,
271
+ variables: {
272
+ [step.config.outputVar || 'result']: result.data
273
+ }
274
+ };
275
+ }
276
+
277
+ private interpolateParams(params: Record<string, any>, variables: Record<string, any>): Record<string, any> {
278
+ return JSON.parse(
279
+ JSON.stringify(params).replace(/\{\{(\w+)\}\}/g, (match, key) => {
280
+ return variables[key] ?? match;
281
+ })
282
+ );
283
+ }
284
+ }
285
+ ```
286
+
287
+ #### Day 5: Schedule Engine
288
+ ```typescript
289
+ // extensions/xyops/src/schedule/engine.ts
290
+ import { CronJob } from 'cron';
291
+
292
+ export interface ScheduledJob {
293
+ id: string;
294
+ name: string;
295
+ workflowId: string;
296
+ cronExpression: string;
297
+ enabled: boolean;
298
+ inputs?: Record<string, any>;
299
+ timezone?: string;
300
+ lastRun?: Date;
301
+ nextRun?: Date;
302
+ runCount: number;
303
+ }
304
+
305
+ export class ScheduleEngine {
306
+ private jobs: Map<string, CronJob> = new Map();
307
+ private scheduledJobs: Map<string, ScheduledJob> = new Map();
308
+
309
+ async schedule(params: ScheduleParams): Promise<ScheduledJob> {
310
+ const job: ScheduledJob = {
311
+ id: generateId(),
312
+ name: params.name,
313
+ workflowId: params.workflowId,
314
+ cronExpression: params.cron,
315
+ enabled: params.enabled ?? true,
316
+ inputs: params.inputs,
317
+ timezone: params.timezone,
318
+ runCount: 0
319
+ };
320
+
321
+ this.scheduledJobs.set(job.id, job);
322
+
323
+ if (job.enabled) {
324
+ await this.startJob(job);
325
+ }
326
+
327
+ await this.persistJob(job);
328
+ return job;
329
+ }
330
+
331
+ private async startJob(job: ScheduledJob): Promise<void> {
332
+ const cronJob = new CronJob(
333
+ job.cronExpression,
334
+ async () => {
335
+ await this.executeJob(job);
336
+ },
337
+ null,
338
+ true,
339
+ job.timezone
340
+ );
341
+
342
+ this.jobs.set(job.id, cronJob);
343
+ job.nextRun = cronJob.nextDate().toJSDate();
344
+ }
345
+
346
+ private async executeJob(job: ScheduledJob): Promise<void> {
347
+ console.log(`[Schedule] Executing job ${job.name} (${job.id})`);
348
+
349
+ try {
350
+ const result = await this.workflowEngine.run(job.workflowId, job.inputs);
351
+
352
+ job.lastRun = new Date();
353
+ job.runCount++;
354
+ job.nextRun = this.jobs.get(job.id)?.nextDate().toJSDate();
355
+
356
+ await this.persistJob(job);
357
+
358
+ // Notify on completion if configured
359
+ if (job.notifyOnComplete) {
360
+ await this.context.notify({
361
+ type: 'job_complete',
362
+ jobId: job.id,
363
+ result
364
+ });
365
+ }
366
+ } catch (error) {
367
+ console.error(`[Schedule] Job ${job.id} failed:`, error);
368
+
369
+ if (job.notifyOnFailure) {
370
+ await this.context.notify({
371
+ type: 'job_failed',
372
+ jobId: job.id,
373
+ error: error.message
374
+ });
375
+ }
376
+ }
377
+ }
378
+
379
+ parseNaturalLanguage(input: string): ScheduleParams {
380
+ // Use LLM to parse natural language into cron
381
+ // Examples:
382
+ // "every day at 9am" -> "0 9 * * *"
383
+ // "every Monday at 8am" -> "0 8 * * 1"
384
+ // "every hour" -> "0 * * * *"
385
+
386
+ const patterns = [
387
+ {
388
+ regex: /every day at (\d+)(?::(\d+))?\s*(am|pm)?/i,
389
+ handler: (match) => {
390
+ let hour = parseInt(match[1]);
391
+ const minute = match[2] ? parseInt(match[2]) : 0;
392
+ const period = match[3]?.toLowerCase();
393
+
394
+ if (period === 'pm' && hour !== 12) hour += 12;
395
+ if (period === 'am' && hour === 12) hour = 0;
396
+
397
+ return `${minute} ${hour} * * *`;
398
+ }
399
+ },
400
+ {
401
+ regex: /every (\w+) at (\d+)(?::(\d+))?\s*(am|pm)?/i,
402
+ handler: (match) => {
403
+ const days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
404
+ const dayIndex = days.indexOf(match[1].toLowerCase());
405
+ if (dayIndex === -1) return null;
406
+
407
+ let hour = parseInt(match[2]);
408
+ const minute = match[3] ? parseInt(match[3]) : 0;
409
+ const period = match[4]?.toLowerCase();
410
+
411
+ if (period === 'pm' && hour !== 12) hour += 12;
412
+ if (period === 'am' && hour === 12) hour = 0;
413
+
414
+ return `${minute} ${hour} * * ${dayIndex}`;
415
+ }
416
+ }
417
+ ];
418
+
419
+ for (const pattern of patterns) {
420
+ const match = input.match(pattern.regex);
421
+ if (match) {
422
+ const cron = pattern.handler(match);
423
+ if (cron) {
424
+ return {
425
+ cron,
426
+ name: input,
427
+ // ... other params
428
+ };
429
+ }
430
+ }
431
+ }
432
+
433
+ throw new Error(`Could not parse schedule: ${input}`);
434
+ }
435
+ }
436
+ ```
437
+
438
+ ### Week 2: Monitoring & Visual Editor
439
+
440
+ #### Day 6-7: Monitor Engine
441
+ ```typescript
442
+ // extensions/xyops/src/monitor/engine.ts
443
+ export interface HealthCheck {
444
+ id: string;
445
+ name: string;
446
+ target: string;
447
+ type: 'http' | 'tcp' | 'dns' | 'ping';
448
+ interval: number; // seconds
449
+ timeout: number; // seconds
450
+ retries: number;
451
+ alerts: AlertConfig[];
452
+ status: 'up' | 'down' | 'unknown';
453
+ lastCheck?: Date;
454
+ lastSuccess?: Date;
455
+ consecutiveFailures: number;
456
+ }
457
+
458
+ export interface AlertConfig {
459
+ condition: 'down' | 'slow' | 'error_rate';
460
+ threshold?: number;
461
+ action: 'notify' | 'webhook' | 'workflow';
462
+ config: Record<string, any>;
463
+ }
464
+
465
+ export class MonitorEngine {
466
+ private checks: Map<string, HealthCheck> = new Map();
467
+ private intervals: Map<string, NodeJS.Timeout> = new Map();
468
+
469
+ async addCheck(params: CreateCheckParams): Promise<HealthCheck> {
470
+ const check: HealthCheck = {
471
+ id: generateId(),
472
+ name: params.name,
473
+ target: params.target,
474
+ type: params.type,
475
+ interval: params.interval,
476
+ timeout: params.timeout || 30,
477
+ retries: params.retries || 3,
478
+ alerts: params.alerts || [],
479
+ status: 'unknown',
480
+ consecutiveFailures: 0
481
+ };
482
+
483
+ this.checks.set(check.id, check);
484
+
485
+ // Start monitoring
486
+ this.startCheck(check);
487
+
488
+ await this.persistCheck(check);
489
+ return check;
490
+ }
491
+
492
+ private startCheck(check: HealthCheck): void {
493
+ const interval = setInterval(async () => {
494
+ await this.runCheck(check);
495
+ }, check.interval * 1000);
496
+
497
+ this.intervals.set(check.id, interval);
498
+ }
499
+
500
+ private async runCheck(check: HealthCheck): Promise<void> {
501
+ const startTime = Date.now();
502
+
503
+ try {
504
+ const result = await this.performCheck(check);
505
+ const responseTime = Date.now() - startTime;
506
+
507
+ check.lastCheck = new Date();
508
+
509
+ if (result.success) {
510
+ check.status = 'up';
511
+ check.lastSuccess = new Date();
512
+ check.consecutiveFailures = 0;
513
+ } else {
514
+ check.consecutiveFailures++;
515
+
516
+ if (check.consecutiveFailures >= check.retries) {
517
+ check.status = 'down';
518
+ await this.triggerAlert(check, 'down', result.error);
519
+ }
520
+ }
521
+
522
+ // Check for slow responses
523
+ if (responseTime > (check.timeout * 1000) / 2) {
524
+ await this.triggerAlert(check, 'slow', { responseTime });
525
+ }
526
+
527
+ } catch (error) {
528
+ check.consecutiveFailures++;
529
+
530
+ if (check.consecutiveFailures >= check.retries) {
531
+ check.status = 'down';
532
+ await this.triggerAlert(check, 'down', error.message);
533
+ }
534
+ }
535
+
536
+ await this.persistCheck(check);
537
+ }
538
+
539
+ private async performCheck(check: HealthCheck): Promise<CheckResult> {
540
+ switch (check.type) {
541
+ case 'http':
542
+ return this.checkHttp(check);
543
+ case 'tcp':
544
+ return this.checkTcp(check);
545
+ case 'dns':
546
+ return this.checkDns(check);
547
+ case 'ping':
548
+ return this.checkPing(check);
549
+ default:
550
+ throw new Error(`Unknown check type: ${check.type}`);
551
+ }
552
+ }
553
+
554
+ private async checkHttp(check: HealthCheck): Promise<CheckResult> {
555
+ try {
556
+ const response = await fetch(check.target, {
557
+ method: 'GET',
558
+ signal: AbortSignal.timeout(check.timeout * 1000)
559
+ });
560
+
561
+ return {
562
+ success: response.ok,
563
+ statusCode: response.status,
564
+ error: response.ok ? undefined : `HTTP ${response.status}`
565
+ };
566
+ } catch (error) {
567
+ return {
568
+ success: false,
569
+ error: error.message
570
+ };
571
+ }
572
+ }
573
+
574
+ private async triggerAlert(check: HealthCheck, type: string, details: any): Promise<void> {
575
+ const matchingAlerts = check.alerts.filter(a => a.condition === type);
576
+
577
+ for (const alert of matchingAlerts) {
578
+ switch (alert.action) {
579
+ case 'notify':
580
+ await this.context.notify({
581
+ type: 'monitor_alert',
582
+ checkId: check.id,
583
+ checkName: check.name,
584
+ alertType: type,
585
+ details
586
+ });
587
+ break;
588
+
589
+ case 'webhook':
590
+ await fetch(alert.config.url, {
591
+ method: 'POST',
592
+ headers: { 'Content-Type': 'application/json' },
593
+ body: JSON.stringify({
594
+ check: check.name,
595
+ type,
596
+ details,
597
+ timestamp: new Date().toISOString()
598
+ })
599
+ });
600
+ break;
601
+
602
+ case 'workflow':
603
+ await this.workflowEngine.run(alert.config.workflowId, {
604
+ checkId: check.id,
605
+ alertType: type,
606
+ details
607
+ });
608
+ break;
609
+ }
610
+ }
611
+ }
612
+ }
613
+ ```
614
+
615
+ #### Day 8-10: Visual Workflow Editor
616
+ ```typescript
617
+ // extensions/xyops/src/web/components/WorkflowEditor.tsx
618
+ import React, { useState, useCallback } from 'react';
619
+ import ReactFlow, {
620
+ Node,
621
+ Edge,
622
+ addEdge,
623
+ Background,
624
+ Controls,
625
+ useNodesState,
626
+ useEdgesState,
627
+ Connection
628
+ } from 'reactflow';
629
+ import 'reactflow/dist/style.css';
630
+
631
+ const nodeTypes = {
632
+ agent: AgentNode,
633
+ tool: ToolNode,
634
+ condition: ConditionNode,
635
+ loop: LoopNode,
636
+ wait: WaitNode
637
+ };
638
+
639
+ export const WorkflowEditor: React.FC = () => {
640
+ const [nodes, setNodes, onNodesChange] = useNodesState([]);
641
+ const [edges, setEdges, onEdgesChange] = useEdgesState([]);
642
+ const [selectedNode, setSelectedNode] = useState<Node | null>(null);
643
+
644
+ const onConnect = useCallback(
645
+ (params: Connection) => setEdges((eds) => addEdge(params, eds)),
646
+ [setEdges]
647
+ );
648
+
649
+ const addNode = (type: string) => {
650
+ const newNode: Node = {
651
+ id: generateId(),
652
+ type,
653
+ position: { x: 100, y: 100 },
654
+ data: { label: `${type} node` }
655
+ };
656
+ setNodes((nds) => [...nds, newNode]);
657
+ };
658
+
659
+ const saveWorkflow = async () => {
660
+ const workflow = {
661
+ nodes,
662
+ edges,
663
+ // Convert to workflow format
664
+ steps: nodes.map(node => ({
665
+ id: node.id,
666
+ type: node.type,
667
+ config: node.data
668
+ }))
669
+ };
670
+
671
+ await fetch('/api/workflows', {
672
+ method: 'POST',
673
+ headers: { 'Content-Type': 'application/json' },
674
+ body: JSON.stringify(workflow)
675
+ });
676
+ };
677
+
678
+ return (
679
+ <div style={{ height: '100vh', display: 'flex' }}>
680
+ <div style={{ width: 250, padding: 20, borderRight: '1px solid #ddd' }}>
681
+ <h3>Toolbox</h3>
682
+ <button onClick={() => addNode('agent')}>Add Agent</button>
683
+ <button onClick={() => addNode('tool')}>Add Tool</button>
684
+ <button onClick={() => addNode('condition')}>Add Condition</button>
685
+ <button onClick={() => addNode('loop')}>Add Loop</button>
686
+ <button onClick={() => addNode('wait')}>Add Wait</button>
687
+ <hr />
688
+ <button onClick={saveWorkflow}>Save Workflow</button>
689
+ </div>
690
+
691
+ <div style={{ flex: 1 }}>
692
+ <ReactFlow
693
+ nodes={nodes}
694
+ edges={edges}
695
+ onNodesChange={onNodesChange}
696
+ onEdgesChange={onEdgesChange}
697
+ onConnect={onConnect}
698
+ nodeTypes={nodeTypes}
699
+ onNodeClick={(_, node) => setSelectedNode(node)}
700
+ fitView
701
+ >
702
+ <Background />
703
+ <Controls />
704
+ </ReactFlow>
705
+ </div>
706
+
707
+ {selectedNode && (
708
+ <NodeConfigPanel
709
+ node={selectedNode}
710
+ onUpdate={(data) => {
711
+ setNodes((nds) =>
712
+ nds.map((n) =>
713
+ n.id === selectedNode.id ? { ...n, data } : n
714
+ )
715
+ );
716
+ }}
717
+ />
718
+ )}
719
+ </div>
720
+ );
721
+ };
722
+ ```
723
+
724
+ ### Week 3: Gateway Node & Integration
725
+
726
+ #### Day 11-12: Gateway Node
727
+ ```typescript
728
+ // extensions/xyops-gateway/src/node.ts
729
+ import { GatewayNode } from '@poolbot/node-sdk';
730
+
731
+ class XyOpsGatewayNode extends GatewayNode {
732
+ private workflowEngine: WorkflowEngine;
733
+ private scheduleEngine: ScheduleEngine;
734
+ private monitorEngine: MonitorEngine;
735
+
736
+ async register() {
737
+ await this.send({
738
+ type: 'register',
739
+ payload: {
740
+ nodeId: this.nodeId,
741
+ capabilities: ['tools.workflow.*', 'tools.schedule.*', 'tools.monitor.*'],
742
+ tools: [
743
+ {
744
+ name: 'workflow.create',
745
+ description: 'Create a workflow',
746
+ parameters: { /* ... */ }
747
+ },
748
+ {
749
+ name: 'workflow.run',
750
+ description: 'Run a workflow',
751
+ parameters: { /* ... */ }
752
+ },
753
+ {
754
+ name: 'schedule.cron',
755
+ description: 'Schedule with cron',
756
+ parameters: { /* ... */ }
757
+ },
758
+ {
759
+ name: 'monitor.check',
760
+ description: 'Add health check',
761
+ parameters: { /* ... */ }
762
+ }
763
+ ]
764
+ }
765
+ });
766
+ }
767
+
768
+ async handleToolCall(call: ToolCall) {
769
+ switch (call.tool) {
770
+ case 'workflow.create':
771
+ return this.workflowEngine.create(call.params);
772
+ case 'workflow.run':
773
+ return this.workflowEngine.run(call.params.workflowId, call.params.inputs);
774
+ case 'schedule.cron':
775
+ return this.scheduleEngine.schedule(call.params);
776
+ case 'monitor.check':
777
+ return this.monitorEngine.addCheck(call.params);
778
+ default:
779
+ throw new Error(`Unknown tool: ${call.tool}`);
780
+ }
781
+ }
782
+ }
783
+ ```
784
+
785
+ #### Day 13-14: CLI Integration
786
+ ```typescript
787
+ // src/cli/mods.ts (enhancement)
788
+ command('mods:xyops')
789
+ .description('Manage xyOps workflow automation')
790
+ .option('--workflow-create <name>', 'Create new workflow')
791
+ .option('--workflow-run <id>', 'Run workflow')
792
+ .option('--schedule-add <cron>', 'Add scheduled job')
793
+ .option('--monitor-add <target>', 'Add health check')
794
+ .option('--status', 'Show status')
795
+ .action(async (options) => {
796
+ if (options.workflowCreate) {
797
+ const workflow = await createWorkflowFromPrompt(options.workflowCreate);
798
+ console.log(`Created workflow: ${workflow.id}`);
799
+ }
800
+ // ...
801
+ });
802
+
803
+ // Natural language workflow creation
804
+ async function createWorkflowFromPrompt(prompt: string): Promise<Workflow> {
805
+ const agent = await createAgent({ type: 'standard' });
806
+
807
+ const result = await agent.execute({
808
+ message: `
809
+ Create a workflow based on this request: "${prompt}"
810
+
811
+ Return a JSON object with:
812
+ - name: workflow name
813
+ - steps: array of steps with type, name, and config
814
+
815
+ Available step types:
816
+ - agent: AI agent execution
817
+ - tool: Tool call
818
+ - condition: If/else branch
819
+ - loop: Repeat steps
820
+ - wait: Delay execution
821
+ `
822
+ });
823
+
824
+ return workflowEngine.create(result.parsed);
825
+ }
826
+ ```
827
+
828
+ #### Day 15: Testing & Documentation
829
+ - Unit tests for all engines
830
+ - Integration tests with Gateway
831
+ - Visual editor tests
832
+ - Documentation
833
+
834
+ ## File Structure
835
+
836
+ ```
837
+ extensions/xyops/
838
+ ├── src/
839
+ │ ├── plugin.ts # PoolBot plugin entry
840
+ │ ├── workflow/
841
+ │ │ ├── engine.ts # Workflow execution
842
+ │ │ ├── execution.ts # Execution context
843
+ │ │ └── types.ts # Type definitions
844
+ │ ├── schedule/
845
+ │ │ ├── engine.ts # Cron scheduling
846
+ │ │ └── types.ts
847
+ │ ├── monitor/
848
+ │ │ ├── engine.ts # Health monitoring
849
+ │ │ └── types.ts
850
+ │ ├── web/
851
+ │ │ ├── components/
852
+ │ │ │ ├── WorkflowEditor.tsx
853
+ │ │ │ ├── NodeConfigPanel.tsx
854
+ │ │ │ └── NodeTypes/
855
+ │ │ ├── App.tsx
856
+ │ │ └── index.tsx
857
+ │ └── index.ts
858
+ ├── package.json
859
+ ├── tsconfig.json
860
+ └── README.md
861
+ ```
862
+
863
+ ## Usage Examples
864
+
865
+ ### Example 1: Create Workflow
866
+ ```typescript
867
+ const workflow = await agent.execute({
868
+ skill: 'workflow.create',
869
+ params: {
870
+ name: 'Daily Report',
871
+ steps: [
872
+ {
873
+ name: 'fetch_data',
874
+ type: 'tool',
875
+ config: {
876
+ tool: 'database.query',
877
+ params: { sql: 'SELECT * FROM sales WHERE date = TODAY' }
878
+ }
879
+ },
880
+ {
881
+ name: 'analyze',
882
+ type: 'agent',
883
+ config: {
884
+ prompt: 'Analyze this sales data and create a summary',
885
+ outputVar: 'summary'
886
+ }
887
+ },
888
+ {
889
+ name: 'send_report',
890
+ type: 'tool',
891
+ config: {
892
+ tool: 'email.send',
893
+ params: {
894
+ to: 'manager@company.com',
895
+ subject: 'Daily Sales Report',
896
+ body: '{{summary}}'
897
+ }
898
+ }
899
+ }
900
+ ]
901
+ }
902
+ });
903
+ ```
904
+
905
+ ### Example 2: Schedule Workflow
906
+ ```typescript
907
+ await agent.execute({
908
+ skill: 'schedule.cron',
909
+ params: {
910
+ workflowId: workflow.id,
911
+ cron: '0 9 * * *', // Every day at 9am
912
+ name: 'Daily morning report'
913
+ }
914
+ });
915
+
916
+ // Or use natural language
917
+ await agent.execute({
918
+ skill: 'schedule.cron',
919
+ params: {
920
+ workflowId: workflow.id,
921
+ cron: 'natural:every weekday at 9am'
922
+ }
923
+ });
924
+ ```
925
+
926
+ ### Example 3: Monitor Service
927
+ ```typescript
928
+ await agent.execute({
929
+ skill: 'monitor.check',
930
+ params: {
931
+ name: 'API Health',
932
+ target: 'https://api.example.com/health',
933
+ type: 'http',
934
+ interval: 60,
935
+ alerts: [
936
+ {
937
+ condition: 'down',
938
+ action: 'notify'
939
+ },
940
+ {
941
+ condition: 'slow',
942
+ threshold: 5000,
943
+ action: 'webhook',
944
+ config: { url: 'https://alerts.example.com/webhook' }
945
+ }
946
+ ]
947
+ }
948
+ });
949
+ ```
950
+
951
+ ## Success Criteria
952
+
953
+ - [ ] Workflow engine functional
954
+ - [ ] Schedule engine with cron support
955
+ - [ ] Monitor engine with HTTP/TCP/DNS checks
956
+ - [ ] Visual workflow editor
957
+ - [ ] Natural language workflow creation
958
+ - [ ] Gateway Node mode working
959
+ - [ ] CLI integration complete
960
+ - [ ] Tests pass (>80% coverage)
961
+ - [ ] Documentation complete
962
+
963
+ ## Docker Support
964
+
965
+ ```dockerfile
966
+ FROM node:20-alpine
967
+
968
+ WORKDIR /app
969
+ COPY package*.json ./
970
+ RUN npm install
971
+
972
+ COPY . .
973
+ RUN npm run build
974
+
975
+ EXPOSE 3000
976
+
977
+ CMD ["node", "dist/node.js"]
978
+ ```