snow-flow 1.3.0 → 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.
- package/.claude-flow/queen/queen-memory.db +0 -0
- package/.env.example +249 -14
- package/CLAUDE.md +185 -24
- package/README.md +55 -5
- package/dist/api/error-handling.js +898 -4
- package/dist/api/performance-optimizer.js +3 -2
- package/dist/cli.js +590 -200
- package/dist/config/snow-flow-config.js +320 -8
- package/dist/health/system-health.js +288 -21
- package/dist/mcp/base-mcp-server.js +2 -0
- package/dist/mcp/http-transport-wrapper.js +65 -4
- package/dist/mcp/servicenow-automation-mcp-refactored.js +90 -9
- package/dist/mcp/servicenow-deployment-mcp-refactored.js +151 -2
- package/dist/mcp/servicenow-deployment-mcp.js +828 -15
- package/dist/mcp/servicenow-integration-mcp-refactored.js +100 -9
- package/dist/mcp/servicenow-intelligent-mcp.js +198 -7
- package/dist/mcp/servicenow-memory-mcp.js +2 -1
- package/dist/mcp/servicenow-operations-mcp-refactored.js +3 -2
- package/dist/mcp/servicenow-xml-flow-mcp.js +671 -0
- package/dist/mcp/shared/base-mcp-server.js +1356 -8
- package/dist/mcp/shared/mcp-resource-manager.js +304 -0
- package/dist/queen/parallel-agent-engine.js +26 -8
- package/dist/queen/servicenow-queen.js +47 -44
- package/dist/sparc/sparc-help.js +37 -26
- package/dist/sparc/team-sparc.js +60 -16
- package/dist/utils/action-type-cache.js +2 -1
- package/dist/utils/mcp-config-manager.js +7 -3
- package/dist/utils/mcp-server-manager.js +7 -3
- package/dist/utils/servicenow-client.js +134 -107
- package/dist/utils/servicenow-id-generator.js +171 -0
- package/dist/utils/snow-oauth.js +13 -8
- package/dist/utils/widget-template-generator.js +1690 -0
- package/dist/utils/xml-first-flow-generator.js +473 -0
- package/dist/version.js +7 -1
- package/flow-update-sets/flow_build_automated_approval_flow_with_notifications_flow.xml +203 -0
- package/flow-update-sets/flow_create_approval_flow_for_equipment_requests_flow.xml +206 -0
- package/flow-update-sets/flow_create_equipment_approval_flow_with_manager_approv_flow.xml +254 -0
- package/flow-update-sets/iphone_15_pro_approval_flow.xml +203 -0
- package/flow-update-sets/test_iphone_approval_flow_flow.xml +303 -0
- package/package.json +2 -1
- package/test-config.js +55 -0
- package/test-real-monitoring.js +184 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* ServiceNow ID Generator - Dynamic sys_id and identifier generation
|
|
5
|
+
*
|
|
6
|
+
* Replaces hardcoded sys_ids with proper dynamic generation
|
|
7
|
+
* Ensures consistent ServiceNow-compatible identifiers across the system
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.COMMON_NOTIFICATION_TEMPLATES = void 0;
|
|
14
|
+
exports.generateServiceNowSysId = generateServiceNowSysId;
|
|
15
|
+
exports.generateMultipleSysIds = generateMultipleSysIds;
|
|
16
|
+
exports.generateDeterministicSysId = generateDeterministicSysId;
|
|
17
|
+
exports.generateMockSysId = generateMockSysId;
|
|
18
|
+
exports.generateUpdateSetName = generateUpdateSetName;
|
|
19
|
+
exports.generateTestUserName = generateTestUserName;
|
|
20
|
+
exports.generateTestGroupName = generateTestGroupName;
|
|
21
|
+
exports.generateCatalogItemName = generateCatalogItemName;
|
|
22
|
+
exports.generateRequestNumber = generateRequestNumber;
|
|
23
|
+
exports.generateIncidentNumber = generateIncidentNumber;
|
|
24
|
+
exports.isValidServiceNowSysId = isValidServiceNowSysId;
|
|
25
|
+
exports.generateMockRecords = generateMockRecords;
|
|
26
|
+
exports.generateFlowIdentifiers = generateFlowIdentifiers;
|
|
27
|
+
exports.getNotificationTemplateSysId = getNotificationTemplateSysId;
|
|
28
|
+
const uuid_1 = require("uuid");
|
|
29
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
30
|
+
/**
|
|
31
|
+
* Generate a ServiceNow-compatible sys_id (32-character hex string)
|
|
32
|
+
* ServiceNow uses lowercase 32-character hex strings without dashes
|
|
33
|
+
*/
|
|
34
|
+
function generateServiceNowSysId() {
|
|
35
|
+
return (0, uuid_1.v4)().replace(/-/g, '').toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate multiple unique sys_ids at once
|
|
39
|
+
*/
|
|
40
|
+
function generateMultipleSysIds(count) {
|
|
41
|
+
return Array.from({ length: count }, () => generateServiceNowSysId());
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate a deterministic sys_id based on input string
|
|
45
|
+
* Useful for generating consistent sys_ids for the same input
|
|
46
|
+
*/
|
|
47
|
+
function generateDeterministicSysId(input) {
|
|
48
|
+
const hash = crypto_1.default.createHash('md5').update(input).digest('hex');
|
|
49
|
+
return hash.toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Generate a prefixed sys_id for mock/test scenarios
|
|
53
|
+
* Maintains the 32-character requirement while being identifiable
|
|
54
|
+
*/
|
|
55
|
+
function generateMockSysId(prefix = 'mock') {
|
|
56
|
+
const timestamp = Date.now().toString(16);
|
|
57
|
+
const random = Math.random().toString(16).substring(2, 10);
|
|
58
|
+
const base = `${prefix}_${timestamp}_${random}`;
|
|
59
|
+
// Ensure it's exactly 32 characters by padding or truncating
|
|
60
|
+
const hash = crypto_1.default.createHash('md5').update(base).digest('hex');
|
|
61
|
+
return hash.toLowerCase();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Generate dynamic update set names with timestamp
|
|
65
|
+
*/
|
|
66
|
+
function generateUpdateSetName(prefix = 'Auto') {
|
|
67
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '_');
|
|
68
|
+
return `${prefix}_${timestamp}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Generate dynamic user names for testing
|
|
72
|
+
*/
|
|
73
|
+
function generateTestUserName(prefix = 'test_user') {
|
|
74
|
+
const timestamp = Date.now();
|
|
75
|
+
const random = Math.random().toString(36).substring(7);
|
|
76
|
+
return `${prefix}_${timestamp}_${random}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Generate dynamic group names
|
|
80
|
+
*/
|
|
81
|
+
function generateTestGroupName(prefix = 'test_group') {
|
|
82
|
+
const timestamp = Date.now();
|
|
83
|
+
const random = Math.random().toString(36).substring(7);
|
|
84
|
+
return `${prefix}_${timestamp}_${random}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Generate dynamic catalog item names
|
|
88
|
+
*/
|
|
89
|
+
function generateCatalogItemName(baseType) {
|
|
90
|
+
const timestamp = Date.now();
|
|
91
|
+
const random = Math.random().toString(36).substring(7);
|
|
92
|
+
return `${baseType}_${timestamp}_${random}`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Generate dynamic request numbers in ServiceNow format
|
|
96
|
+
*/
|
|
97
|
+
function generateRequestNumber(prefix = 'REQ') {
|
|
98
|
+
const number = Math.floor(Math.random() * 999999).toString().padStart(7, '0');
|
|
99
|
+
return `${prefix}${number}`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Generate dynamic incident numbers in ServiceNow format
|
|
103
|
+
*/
|
|
104
|
+
function generateIncidentNumber(prefix = 'INC') {
|
|
105
|
+
const number = Math.floor(Math.random() * 999999).toString().padStart(7, '0');
|
|
106
|
+
return `${prefix}${number}`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validate if a string is a valid ServiceNow sys_id format
|
|
110
|
+
*/
|
|
111
|
+
function isValidServiceNowSysId(sysId) {
|
|
112
|
+
const sysIdPattern = /^[a-f0-9]{32}$/;
|
|
113
|
+
return sysIdPattern.test(sysId);
|
|
114
|
+
}
|
|
115
|
+
function generateMockRecords(count, type) {
|
|
116
|
+
return Array.from({ length: count }, (_, index) => ({
|
|
117
|
+
sys_id: generateServiceNowSysId(),
|
|
118
|
+
name: `${type}_${index + 1}_${Date.now()}`,
|
|
119
|
+
type
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate workflow/flow-related identifiers
|
|
124
|
+
*/
|
|
125
|
+
function generateFlowIdentifiers(flowName) {
|
|
126
|
+
const baseSysId = generateDeterministicSysId(flowName);
|
|
127
|
+
return {
|
|
128
|
+
flowSysId: baseSysId,
|
|
129
|
+
triggerSysId: generateDeterministicSysId(`${flowName}_trigger`),
|
|
130
|
+
updateSetSysId: generateServiceNowSysId(),
|
|
131
|
+
updateSetName: generateUpdateSetName(`Flow_${flowName.replace(/\s+/g, '_')}`)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* ServiceNow system notification IDs - for common notification templates
|
|
136
|
+
* These should be looked up dynamically in real implementations
|
|
137
|
+
*/
|
|
138
|
+
exports.COMMON_NOTIFICATION_TEMPLATES = {
|
|
139
|
+
// Generic notification template - should be replaced with actual lookup
|
|
140
|
+
generic_notification: '3c7d23a4db01030077c9a4d3ca961985',
|
|
141
|
+
// Default fallback - generates a deterministic sys_id for consistent behavior
|
|
142
|
+
default: generateDeterministicSysId('default_notification_template')
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Get a notification template sys_id
|
|
146
|
+
* In production, this should query ServiceNow for actual notification templates
|
|
147
|
+
*/
|
|
148
|
+
function getNotificationTemplateSysId(templateName = 'default') {
|
|
149
|
+
if (templateName in exports.COMMON_NOTIFICATION_TEMPLATES) {
|
|
150
|
+
return exports.COMMON_NOTIFICATION_TEMPLATES[templateName];
|
|
151
|
+
}
|
|
152
|
+
// Generate a consistent sys_id for unknown templates
|
|
153
|
+
return generateDeterministicSysId(`notification_template_${templateName}`);
|
|
154
|
+
}
|
|
155
|
+
exports.default = {
|
|
156
|
+
generateServiceNowSysId,
|
|
157
|
+
generateMultipleSysIds,
|
|
158
|
+
generateDeterministicSysId,
|
|
159
|
+
generateMockSysId,
|
|
160
|
+
generateUpdateSetName,
|
|
161
|
+
generateTestUserName,
|
|
162
|
+
generateTestGroupName,
|
|
163
|
+
generateCatalogItemName,
|
|
164
|
+
generateRequestNumber,
|
|
165
|
+
generateIncidentNumber,
|
|
166
|
+
isValidServiceNowSysId,
|
|
167
|
+
generateMockRecords,
|
|
168
|
+
generateFlowIdentifiers,
|
|
169
|
+
getNotificationTemplateSysId,
|
|
170
|
+
COMMON_NOTIFICATION_TEMPLATES: exports.COMMON_NOTIFICATION_TEMPLATES
|
|
171
|
+
};
|
package/dist/utils/snow-oauth.js
CHANGED
|
@@ -11,15 +11,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
11
11
|
exports.ServiceNowOAuth = void 0;
|
|
12
12
|
const fs_1 = require("fs");
|
|
13
13
|
const path_1 = require("path");
|
|
14
|
+
const os_1 = __importDefault(require("os"));
|
|
14
15
|
const http_1 = require("http");
|
|
15
16
|
const url_1 = require("url");
|
|
16
17
|
const axios_1 = __importDefault(require("axios"));
|
|
17
18
|
const net_1 = __importDefault(require("net"));
|
|
18
19
|
const crypto_1 = __importDefault(require("crypto"));
|
|
20
|
+
const snow_flow_config_js_1 = require("../config/snow-flow-config.js");
|
|
19
21
|
class ServiceNowOAuth {
|
|
20
22
|
constructor() {
|
|
21
23
|
// Store tokens in user's home directory
|
|
22
|
-
const configDir = (0, path_1.join)(
|
|
24
|
+
const configDir = process.env.SNOW_FLOW_HOME || (0, path_1.join)(os_1.default.homedir(), '.snow-flow');
|
|
23
25
|
this.tokenPath = (0, path_1.join)(configDir, 'auth.json');
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
@@ -75,9 +77,12 @@ class ServiceNowOAuth {
|
|
|
75
77
|
error: secretValidation.reason
|
|
76
78
|
};
|
|
77
79
|
}
|
|
78
|
-
//
|
|
79
|
-
const
|
|
80
|
-
const
|
|
80
|
+
// Get OAuth redirect configuration from environment or use defaults
|
|
81
|
+
const oauthConfig = snow_flow_config_js_1.snowFlowConfig.servicenow.oauth;
|
|
82
|
+
const port = oauthConfig.redirectPort;
|
|
83
|
+
const host = oauthConfig.redirectHost;
|
|
84
|
+
const path = oauthConfig.redirectPath;
|
|
85
|
+
const redirectUri = `http://${host}:${port}${path}`;
|
|
81
86
|
// Check if port is available
|
|
82
87
|
const isPortAvailable = await this.checkPortAvailable(port);
|
|
83
88
|
if (!isPortAvailable) {
|
|
@@ -156,7 +161,7 @@ class ServiceNowOAuth {
|
|
|
156
161
|
return new Promise((resolve) => {
|
|
157
162
|
const server = (0, http_1.createServer)(async (req, res) => {
|
|
158
163
|
try {
|
|
159
|
-
const url = new url_1.URL(req.url, `http
|
|
164
|
+
const url = new url_1.URL(req.url, `http://${snow_flow_config_js_1.snowFlowConfig.servicenow.oauth.redirectHost}:${port}`);
|
|
160
165
|
if (url.pathname === '/callback') {
|
|
161
166
|
const code = url.searchParams.get('code');
|
|
162
167
|
const error = url.searchParams.get('error');
|
|
@@ -265,7 +270,7 @@ class ServiceNowOAuth {
|
|
|
265
270
|
}
|
|
266
271
|
});
|
|
267
272
|
server.listen(port, () => {
|
|
268
|
-
console.log(`🌐 OAuth callback server started on http
|
|
273
|
+
console.log(`🌐 OAuth callback server started on http://${snow_flow_config_js_1.snowFlowConfig.servicenow.oauth.redirectHost}:${port}`);
|
|
269
274
|
console.log('🚀 Please open the authorization URL in your browser...');
|
|
270
275
|
console.log('⏳ Waiting for OAuth callback...');
|
|
271
276
|
// Auto-open browser if possible
|
|
@@ -343,7 +348,7 @@ class ServiceNowOAuth {
|
|
|
343
348
|
*/
|
|
344
349
|
async saveTokens(tokenData) {
|
|
345
350
|
try {
|
|
346
|
-
const configDir = (0, path_1.join)(
|
|
351
|
+
const configDir = process.env.SNOW_FLOW_HOME || (0, path_1.join)(os_1.default.homedir(), '.snow-flow');
|
|
347
352
|
await fs_1.promises.mkdir(configDir, { recursive: true });
|
|
348
353
|
const expiresAt = new Date();
|
|
349
354
|
expiresAt.setSeconds(expiresAt.getSeconds() + tokenData.expiresIn);
|
|
@@ -586,7 +591,7 @@ class ServiceNowOAuth {
|
|
|
586
591
|
console.error('');
|
|
587
592
|
console.error('💡 To get OAuth credentials:');
|
|
588
593
|
console.error(' • ServiceNow: System OAuth > Application Registry > New OAuth Application');
|
|
589
|
-
console.error(
|
|
594
|
+
console.error(` • Redirect URI: http://${snow_flow_config_js_1.snowFlowConfig.servicenow.oauth.redirectHost}:${snow_flow_config_js_1.snowFlowConfig.servicenow.oauth.redirectPort}${snow_flow_config_js_1.snowFlowConfig.servicenow.oauth.redirectPath}`);
|
|
590
595
|
console.error(' • Scopes: useraccount write admin');
|
|
591
596
|
console.error('');
|
|
592
597
|
return null;
|