snow-flow 1.3.1 → 1.3.2

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 (40) hide show
  1. package/.claude-flow/queen/queen-memory.db +0 -0
  2. package/.env.example +249 -14
  3. package/CLAUDE.md +185 -24
  4. package/README.md +55 -5
  5. package/dist/api/error-handling.js +898 -4
  6. package/dist/api/performance-optimizer.js +3 -2
  7. package/dist/cli.js +590 -200
  8. package/dist/config/snow-flow-config.js +320 -8
  9. package/dist/health/system-health.js +288 -21
  10. package/dist/mcp/http-transport-wrapper.js +65 -4
  11. package/dist/mcp/servicenow-automation-mcp-refactored.js +90 -9
  12. package/dist/mcp/servicenow-deployment-mcp-refactored.js +151 -2
  13. package/dist/mcp/servicenow-deployment-mcp.js +828 -15
  14. package/dist/mcp/servicenow-integration-mcp-refactored.js +100 -9
  15. package/dist/mcp/servicenow-intelligent-mcp.js +198 -7
  16. package/dist/mcp/servicenow-memory-mcp.js +2 -1
  17. package/dist/mcp/servicenow-operations-mcp-refactored.js +3 -2
  18. package/dist/mcp/servicenow-xml-flow-mcp.js +671 -0
  19. package/dist/mcp/shared/base-mcp-server.js +1356 -8
  20. package/dist/mcp/shared/mcp-resource-manager.js +304 -0
  21. package/dist/queen/parallel-agent-engine.js +26 -8
  22. package/dist/queen/servicenow-queen.js +47 -44
  23. package/dist/sparc/sparc-help.js +37 -26
  24. package/dist/sparc/team-sparc.js +60 -16
  25. package/dist/utils/action-type-cache.js +2 -1
  26. package/dist/utils/mcp-config-manager.js +7 -3
  27. package/dist/utils/mcp-server-manager.js +7 -3
  28. package/dist/utils/servicenow-client.js +134 -107
  29. package/dist/utils/servicenow-id-generator.js +171 -0
  30. package/dist/utils/snow-oauth.js +13 -8
  31. package/dist/utils/widget-template-generator.js +1690 -0
  32. package/dist/utils/xml-first-flow-generator.js +473 -0
  33. package/flow-update-sets/flow_build_automated_approval_flow_with_notifications_flow.xml +203 -0
  34. package/flow-update-sets/flow_create_approval_flow_for_equipment_requests_flow.xml +206 -0
  35. package/flow-update-sets/flow_create_equipment_approval_flow_with_manager_approv_flow.xml +254 -0
  36. package/flow-update-sets/iphone_15_pro_approval_flow.xml +203 -0
  37. package/flow-update-sets/test_iphone_approval_flow_flow.xml +303 -0
  38. package/package.json +2 -1
  39. package/test-config.js +55 -0
  40. package/test-real-monitoring.js +184 -0
@@ -0,0 +1,671 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * ServiceNow XML Flow MCP Server
5
+ * Provides XML-first flow generation capabilities
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.ServiceNowXMLFlowMCP = void 0;
42
+ const base_mcp_server_1 = require("./base-mcp-server");
43
+ const xml_first_flow_generator_1 = __importStar(require("../utils/xml-first-flow-generator"));
44
+ const natural_language_mapper_1 = require("../api/natural-language-mapper");
45
+ const servicenow_id_generator_js_1 = require("../utils/servicenow-id-generator.js");
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ class ServiceNowXMLFlowMCP extends base_mcp_server_1.BaseMCPServer {
49
+ constructor() {
50
+ super({
51
+ name: 'servicenow-xml-flow',
52
+ version: '1.0.0',
53
+ description: 'XML-first flow generation for ServiceNow - bypasses API issues'
54
+ });
55
+ this.nlMapper = new natural_language_mapper_1.NaturalLanguageFlowMapper();
56
+ }
57
+ setupTools() {
58
+ // Generate complete flow XML
59
+ this.registerTool({
60
+ name: 'snow_xml_flow_generate',
61
+ description: 'Generate complete Update Set XML for a flow that can be imported directly into ServiceNow',
62
+ inputSchema: {
63
+ type: 'object',
64
+ properties: {
65
+ name: {
66
+ type: 'string',
67
+ description: 'Flow name'
68
+ },
69
+ description: {
70
+ type: 'string',
71
+ description: 'Flow description'
72
+ },
73
+ table: {
74
+ type: 'string',
75
+ description: 'Table to trigger on (e.g., incident, sc_request)'
76
+ },
77
+ trigger_type: {
78
+ type: 'string',
79
+ enum: ['record_created', 'record_updated', 'manual', 'scheduled'],
80
+ description: 'Trigger type'
81
+ },
82
+ trigger_condition: {
83
+ type: 'string',
84
+ description: 'Trigger condition (encoded query)'
85
+ },
86
+ activities: {
87
+ type: 'array',
88
+ description: 'Flow activities',
89
+ items: {
90
+ type: 'object',
91
+ properties: {
92
+ name: { type: 'string' },
93
+ type: {
94
+ type: 'string',
95
+ enum: ['notification', 'approval', 'script', 'create_record', 'update_record', 'rest_step']
96
+ },
97
+ order: { type: 'number' },
98
+ inputs: { type: 'object' },
99
+ outputs: { type: 'object' },
100
+ condition: { type: 'string' }
101
+ },
102
+ required: ['name', 'type', 'inputs']
103
+ }
104
+ },
105
+ update_set_name: {
106
+ type: 'string',
107
+ description: 'Name for the Update Set (optional)'
108
+ },
109
+ save_to_file: {
110
+ type: 'boolean',
111
+ default: true,
112
+ description: 'Save XML to file'
113
+ }
114
+ },
115
+ required: ['name', 'description', 'trigger_type', 'activities']
116
+ }
117
+ }, this.generateFlowXML.bind(this));
118
+ // Generate flow XML from natural language
119
+ this.registerTool({
120
+ name: 'snow_xml_flow_from_instruction',
121
+ description: 'Generate flow Update Set XML from natural language instruction',
122
+ inputSchema: {
123
+ type: 'object',
124
+ properties: {
125
+ instruction: {
126
+ type: 'string',
127
+ description: 'Natural language description of the flow (e.g., "create approval flow for iPhone requests")'
128
+ },
129
+ save_to_file: {
130
+ type: 'boolean',
131
+ default: true,
132
+ description: 'Save XML to file'
133
+ }
134
+ },
135
+ required: ['instruction']
136
+ }
137
+ }, this.generateFlowFromInstruction.bind(this));
138
+ // Generate example flows
139
+ this.registerTool({
140
+ name: 'snow_xml_flow_examples',
141
+ description: 'Generate example flow XML files with common patterns',
142
+ inputSchema: {
143
+ type: 'object',
144
+ properties: {
145
+ example_type: {
146
+ type: 'string',
147
+ enum: ['approval', 'incident_notification', 'equipment_provisioning', 'data_processing', 'user_onboarding'],
148
+ description: 'Type of example flow to generate'
149
+ }
150
+ },
151
+ required: ['example_type']
152
+ }
153
+ }, this.generateExampleFlow.bind(this));
154
+ // List generated XML files
155
+ this.registerTool({
156
+ name: 'snow_xml_flow_list',
157
+ description: 'List all generated flow XML files',
158
+ inputSchema: {
159
+ type: 'object',
160
+ properties: {}
161
+ }
162
+ }, this.listGeneratedFiles.bind(this));
163
+ }
164
+ /**
165
+ * Generate flow XML from definition
166
+ */
167
+ async generateFlowXML(args) {
168
+ try {
169
+ const generator = new xml_first_flow_generator_1.default(args.update_set_name);
170
+ const flowDef = {
171
+ name: args.name,
172
+ description: args.description,
173
+ table: args.table,
174
+ trigger_type: args.trigger_type,
175
+ trigger_condition: args.trigger_condition,
176
+ activities: args.activities.map((act, index) => ({
177
+ ...act,
178
+ order: act.order || (index + 1) * 100
179
+ }))
180
+ };
181
+ const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
182
+ return {
183
+ success: true,
184
+ xml: args.save_to_file === false ? result.xml : undefined,
185
+ file_path: result.filePath,
186
+ message: `Generated PRODUCTION-READY Update Set XML for flow: ${args.name}`,
187
+ import_instructions: result.instructions,
188
+ flow_structure: {
189
+ flow_sys_id: generator.flowSysId,
190
+ activities_count: flowDef.activities.length,
191
+ trigger_type: flowDef.trigger_type,
192
+ table: flowDef.table || 'none'
193
+ }
194
+ };
195
+ }
196
+ catch (error) {
197
+ return {
198
+ success: false,
199
+ error: error instanceof Error ? error.message : String(error)
200
+ };
201
+ }
202
+ }
203
+ /**
204
+ * Generate flow from natural language instruction
205
+ */
206
+ async generateFlowFromInstruction(args) {
207
+ try {
208
+ const { instruction } = args;
209
+ // Parse natural language to flow components
210
+ const flowRequirements = await this.nlMapper.parseFlowRequirements(instruction);
211
+ // Convert to XML flow definition
212
+ const flowDef = {
213
+ name: flowRequirements.name || `Flow ${Date.now()}`,
214
+ description: flowRequirements.description || instruction,
215
+ table: flowRequirements.tables?.[0] || 'incident',
216
+ trigger_type: this.mapTriggerType(flowRequirements.trigger_type || 'manual'),
217
+ trigger_condition: flowRequirements.trigger_condition || '',
218
+ activities: this.convertToXMLActivities(flowRequirements)
219
+ };
220
+ const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
221
+ return {
222
+ success: true,
223
+ xml: args.save_to_file === false ? result.xml : undefined,
224
+ file_path: result.filePath,
225
+ flow_definition: flowDef,
226
+ message: `Generated PRODUCTION flow XML from instruction: ${instruction}`,
227
+ import_instructions: result.instructions
228
+ };
229
+ }
230
+ catch (error) {
231
+ return {
232
+ success: false,
233
+ error: error instanceof Error ? error.message : String(error)
234
+ };
235
+ }
236
+ }
237
+ /**
238
+ * Generate example flows
239
+ */
240
+ async generateExampleFlow(args) {
241
+ try {
242
+ const { example_type } = args;
243
+ let flowDef;
244
+ switch (example_type) {
245
+ case 'approval':
246
+ flowDef = xml_first_flow_generator_1.default.createRealWorldExample(); // Use real-world example
247
+ break;
248
+ case 'incident_notification':
249
+ flowDef = this.getIncidentNotificationExample();
250
+ break;
251
+ case 'equipment_provisioning':
252
+ flowDef = this.getEquipmentProvisioningExample();
253
+ break;
254
+ case 'data_processing':
255
+ flowDef = this.getDataProcessingExample();
256
+ break;
257
+ case 'user_onboarding':
258
+ flowDef = this.getUserOnboardingExample();
259
+ break;
260
+ default:
261
+ throw new Error(`Unknown example type: ${example_type}`);
262
+ }
263
+ const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
264
+ return {
265
+ success: true,
266
+ xml: result.xml,
267
+ file_path: result.filePath,
268
+ flow_definition: flowDef,
269
+ message: `Generated REAL example ${example_type} flow (NO placeholders!)`,
270
+ import_instructions: result.instructions,
271
+ warning: 'This is a PRODUCTION-READY flow with real ServiceNow action IDs - ready for import!'
272
+ };
273
+ }
274
+ catch (error) {
275
+ return {
276
+ success: false,
277
+ error: error instanceof Error ? error.message : String(error)
278
+ };
279
+ }
280
+ }
281
+ /**
282
+ * List generated XML files
283
+ */
284
+ async listGeneratedFiles(args) {
285
+ try {
286
+ const outputDir = path.join(process.cwd(), 'flow-update-sets');
287
+ if (!fs.existsSync(outputDir)) {
288
+ return {
289
+ success: true,
290
+ files: [],
291
+ message: 'No flow XML files generated yet'
292
+ };
293
+ }
294
+ const files = fs.readdirSync(outputDir)
295
+ .filter(file => file.endsWith('.xml'))
296
+ .map(file => {
297
+ const filePath = path.join(outputDir, file);
298
+ const stats = fs.statSync(filePath);
299
+ return {
300
+ name: file,
301
+ path: filePath,
302
+ size: stats.size,
303
+ created: stats.birthtime,
304
+ modified: stats.mtime
305
+ };
306
+ })
307
+ .sort((a, b) => b.modified.getTime() - a.modified.getTime());
308
+ return {
309
+ success: true,
310
+ files: files,
311
+ count: files.length,
312
+ directory: outputDir,
313
+ message: `Found ${files.length} flow XML files`
314
+ };
315
+ }
316
+ catch (error) {
317
+ return {
318
+ success: false,
319
+ error: error instanceof Error ? error.message : String(error)
320
+ };
321
+ }
322
+ }
323
+ /**
324
+ * Helper methods for examples
325
+ */
326
+ getApprovalFlowExample() {
327
+ return {
328
+ name: 'Multi-Level Approval Flow',
329
+ description: 'Production-ready multi-level approval workflow',
330
+ internal_name: 'multi_level_approval',
331
+ table: 'sc_request',
332
+ trigger_type: 'record_created',
333
+ trigger_condition: 'approval=requested',
334
+ run_as: 'user',
335
+ activities: [
336
+ {
337
+ name: 'Manager Approval',
338
+ type: 'approval',
339
+ order: 100,
340
+ inputs: {
341
+ table: 'sc_request',
342
+ record: '{{trigger.current.sys_id}}',
343
+ approver: '{{trigger.current.requested_for.manager}}',
344
+ approval_field: 'approval',
345
+ message: 'Please approve request {{trigger.current.number}} for {{trigger.current.requested_for.name}}'
346
+ },
347
+ outputs: {
348
+ state: 'string',
349
+ approver_sys_id: 'string'
350
+ }
351
+ },
352
+ {
353
+ name: 'Director Approval',
354
+ type: 'approval',
355
+ order: 200,
356
+ condition: '{{manager_approval.state}} == "approved" && {{trigger.current.price}} > 5000',
357
+ inputs: {
358
+ table: 'sc_request',
359
+ record: '{{trigger.current.sys_id}}',
360
+ approver: '{{trigger.current.requested_for.manager.manager}}',
361
+ approval_field: 'approval',
362
+ message: 'High-value request requires director approval: {{trigger.current.number}}'
363
+ },
364
+ outputs: {
365
+ state: 'string',
366
+ approver_sys_id: 'string'
367
+ }
368
+ },
369
+ {
370
+ name: 'Send Result Notification',
371
+ type: 'notification',
372
+ order: 300,
373
+ inputs: {
374
+ notification_id: (0, servicenow_id_generator_js_1.getNotificationTemplateSysId)('generic_notification'),
375
+ recipients: '{{trigger.current.requested_for}}',
376
+ values: {
377
+ request_number: '{{trigger.current.number}}',
378
+ final_status: '{{director_approval.state || manager_approval.state}}'
379
+ }
380
+ },
381
+ outputs: {
382
+ sent: 'boolean'
383
+ }
384
+ }
385
+ ]
386
+ };
387
+ }
388
+ getIncidentNotificationExample() {
389
+ return {
390
+ name: 'High Priority Incident Notification',
391
+ description: 'Notifies management of high priority incidents',
392
+ table: 'incident',
393
+ trigger_type: 'record_created',
394
+ trigger_condition: 'priority<=2',
395
+ activities: [
396
+ {
397
+ name: 'Check Business Hours',
398
+ type: 'script',
399
+ order: 100,
400
+ inputs: {
401
+ script: `
402
+ var isBusinessHours = gs.isBusinessHours();
403
+ current.u_notified_outside_hours = !isBusinessHours;
404
+ return { is_business_hours: isBusinessHours };
405
+ `.trim()
406
+ },
407
+ outputs: {
408
+ is_business_hours: 'boolean'
409
+ }
410
+ },
411
+ {
412
+ name: 'Send Management Alert',
413
+ type: 'notification',
414
+ order: 200,
415
+ inputs: {
416
+ recipient: 'it-management@company.com',
417
+ subject: 'URGENT: P${current.priority} Incident Created',
418
+ message: 'High priority incident ${current.number} requires attention'
419
+ }
420
+ },
421
+ {
422
+ name: 'Create War Room Task',
423
+ type: 'create_record',
424
+ order: 300,
425
+ condition: '${current.priority} == 1',
426
+ inputs: {
427
+ table: 'task',
428
+ fields: {
429
+ short_description: 'War Room: ${current.number}',
430
+ description: 'Coordinate response for critical incident',
431
+ assigned_to: '${current.assignment_group.manager}'
432
+ }
433
+ }
434
+ }
435
+ ]
436
+ };
437
+ }
438
+ getEquipmentProvisioningExample() {
439
+ return {
440
+ name: 'IT Equipment Provisioning',
441
+ description: 'Automated provisioning of IT equipment',
442
+ table: 'sc_request',
443
+ trigger_type: 'record_updated',
444
+ trigger_condition: 'state=approved^cat_item.category=hardware',
445
+ activities: [
446
+ {
447
+ name: 'Check Inventory',
448
+ type: 'rest_step',
449
+ order: 100,
450
+ inputs: {
451
+ endpoint: '${system.property.inventory_api_url}/check',
452
+ method: 'POST',
453
+ headers: {
454
+ 'Content-Type': 'application/json',
455
+ 'Authorization': 'Bearer ${system.property.inventory_api_token}'
456
+ },
457
+ body: {
458
+ item_code: '${current.cat_item.model_number}',
459
+ quantity: '${current.quantity}'
460
+ }
461
+ },
462
+ outputs: {
463
+ in_stock: 'boolean',
464
+ available_quantity: 'integer'
465
+ }
466
+ },
467
+ {
468
+ name: 'Create Asset Record',
469
+ type: 'create_record',
470
+ order: 200,
471
+ condition: '${check_inventory.in_stock} == true',
472
+ inputs: {
473
+ table: 'alm_asset',
474
+ fields: {
475
+ display_name: '${current.cat_item.name} - ${current.requested_for.name}',
476
+ assigned_to: '${current.requested_for}',
477
+ state: 'In use',
478
+ po_number: '${current.number}'
479
+ }
480
+ }
481
+ },
482
+ {
483
+ name: 'Send Delivery Instructions',
484
+ type: 'notification',
485
+ order: 300,
486
+ inputs: {
487
+ recipient: '${current.requested_for.email}',
488
+ subject: 'Equipment Ready for Pickup',
489
+ message: 'Your ${current.cat_item.name} is ready. Pickup location: ${pickup_location}'
490
+ }
491
+ }
492
+ ]
493
+ };
494
+ }
495
+ getDataProcessingExample() {
496
+ return {
497
+ name: 'Daily Data Processing',
498
+ description: 'Process and analyze daily operational data',
499
+ trigger_type: 'scheduled',
500
+ trigger_condition: '0 2 * * *', // 2 AM daily
501
+ activities: [
502
+ {
503
+ name: 'Extract Yesterday Data',
504
+ type: 'script',
505
+ order: 100,
506
+ inputs: {
507
+ script: `
508
+ var yesterday = new GlideDateTime();
509
+ yesterday.addDays(-1);
510
+ var gr = new GlideRecord('incident');
511
+ gr.addQuery('opened_at', '>=', yesterday.getDate());
512
+ gr.query();
513
+ var count = gr.getRowCount();
514
+ return { record_count: count, date: yesterday.getDate() };
515
+ `.trim()
516
+ },
517
+ outputs: {
518
+ record_count: 'integer',
519
+ date: 'string'
520
+ }
521
+ },
522
+ {
523
+ name: 'Generate Report',
524
+ type: 'script',
525
+ order: 200,
526
+ inputs: {
527
+ script: `
528
+ // Generate daily report logic
529
+ var report = generateDailyReport(current.record_count);
530
+ return { report_id: report.sys_id };
531
+ `.trim()
532
+ }
533
+ },
534
+ {
535
+ name: 'Send Report',
536
+ type: 'notification',
537
+ order: 300,
538
+ inputs: {
539
+ recipient: 'operations@company.com',
540
+ subject: 'Daily Operations Report - ${date}',
541
+ message: 'Daily report is ready. ${record_count} incidents processed.',
542
+ attachments: '${report_id}'
543
+ }
544
+ }
545
+ ]
546
+ };
547
+ }
548
+ getUserOnboardingExample() {
549
+ return {
550
+ name: 'Employee Onboarding Workflow',
551
+ description: 'Automated onboarding process for new employees',
552
+ table: 'sys_user',
553
+ trigger_type: 'record_created',
554
+ trigger_condition: 'employee_number!=NULL',
555
+ activities: [
556
+ {
557
+ name: 'Create AD Account',
558
+ type: 'rest_step',
559
+ order: 100,
560
+ inputs: {
561
+ endpoint: '${system.property.ad_api_url}/users',
562
+ method: 'POST',
563
+ body: {
564
+ username: '${current.user_name}',
565
+ email: '${current.email}',
566
+ department: '${current.department}'
567
+ }
568
+ }
569
+ },
570
+ {
571
+ name: 'Assign Equipment',
572
+ type: 'create_record',
573
+ order: 200,
574
+ inputs: {
575
+ table: 'sc_request',
576
+ fields: {
577
+ requested_for: '${current.sys_id}',
578
+ cat_item: '${system.property.standard_laptop_item}',
579
+ short_description: 'New Employee Equipment - ${current.name}'
580
+ }
581
+ }
582
+ },
583
+ {
584
+ name: 'Schedule Training',
585
+ type: 'create_record',
586
+ order: 300,
587
+ inputs: {
588
+ table: 'task',
589
+ fields: {
590
+ short_description: 'Onboarding Training - ${current.name}',
591
+ assigned_to: '${current.department.training_coordinator}',
592
+ due_date: '+7 days'
593
+ }
594
+ }
595
+ },
596
+ {
597
+ name: 'Send Welcome Email',
598
+ type: 'notification',
599
+ order: 400,
600
+ inputs: {
601
+ recipient: '${current.email}',
602
+ cc: '${current.manager.email}',
603
+ subject: 'Welcome to the Team!',
604
+ message: 'Welcome ${current.first_name}! Your accounts are being set up.'
605
+ }
606
+ }
607
+ ]
608
+ };
609
+ }
610
+ /**
611
+ * Helper methods
612
+ */
613
+ mapTriggerType(type) {
614
+ const typeMap = {
615
+ 'create': 'record_created',
616
+ 'update': 'record_updated',
617
+ 'manual': 'manual',
618
+ 'scheduled': 'scheduled',
619
+ 'cron': 'scheduled'
620
+ };
621
+ return typeMap[type.toLowerCase()] || 'manual';
622
+ }
623
+ convertToXMLActivities(requirements) {
624
+ const activities = [];
625
+ // Convert actions to activities
626
+ if (requirements.actions && Array.isArray(requirements.actions)) {
627
+ requirements.actions.forEach((action, index) => {
628
+ activities.push({
629
+ name: action.name || `Activity ${index + 1}`,
630
+ type: this.mapActionType(action.type || 'script'),
631
+ order: (index + 1) * 100,
632
+ inputs: action.config || action.inputs || {},
633
+ outputs: action.outputs,
634
+ condition: action.condition
635
+ });
636
+ });
637
+ }
638
+ // If no activities but has requirements, generate default activities
639
+ if (activities.length === 0 && requirements.description) {
640
+ activities.push({
641
+ name: 'Process Request',
642
+ type: 'script',
643
+ order: 100,
644
+ inputs: {
645
+ script: '// Process logic here\ngs.info("Processing: " + current.number);'
646
+ }
647
+ });
648
+ }
649
+ return activities;
650
+ }
651
+ mapActionType(type) {
652
+ const typeMap = {
653
+ 'email': 'notification',
654
+ 'notify': 'notification',
655
+ 'approve': 'approval',
656
+ 'script': 'script',
657
+ 'create': 'create_record',
658
+ 'update': 'update_record',
659
+ 'rest': 'rest_step',
660
+ 'api': 'rest_step'
661
+ };
662
+ return typeMap[type.toLowerCase()] || 'script';
663
+ }
664
+ }
665
+ exports.ServiceNowXMLFlowMCP = ServiceNowXMLFlowMCP;
666
+ // Start the server
667
+ const server = new ServiceNowXMLFlowMCP();
668
+ server.start().catch(error => {
669
+ console.error('Failed to start XML Flow MCP server:', error);
670
+ process.exit(1);
671
+ });