snow-flow 1.3.24 â 1.3.27
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/config.json +33 -9
- package/.claude-flow/queen/queen-memory.db +0 -0
- package/.roo/README.md +56 -0
- package/.roo/workflows/basic-tdd.json +32 -0
- package/.roomodes +122 -0
- package/CLAUDE.md +140 -752
- package/claude-flow +30 -75
- package/dist/cli.js +250 -7
- package/dist/compliance/advanced-compliance-system.js +857 -0
- package/dist/compliance/index.js +8 -0
- package/dist/documentation/index.js +8 -0
- package/dist/documentation/self-documenting-system.js +1006 -0
- package/dist/healing/index.js +8 -0
- package/dist/healing/self-healing-system.js +1041 -0
- package/dist/intelligence/multi-pass-requirements-analyzer.js +477 -0
- package/dist/intelligence/performance-recommendations-engine.js +960 -0
- package/dist/managers/scope-manager.js +5 -2
- package/dist/mcp/servicenow-deployment-mcp.js +113 -15
- package/dist/mcp/servicenow-flow-composer-mcp.js +604 -15
- package/dist/mcp/servicenow-intelligent-mcp.js +350 -0
- package/dist/mcp/servicenow-operations-mcp.js +2 -2
- package/dist/memory/memory-system.js +146 -0
- package/dist/monitoring/enhanced-monitoring-system.js +1085 -0
- package/dist/optimization/cost-optimization-engine.js +771 -0
- package/dist/optimization/flow-performance-optimizer.js +723 -0
- package/dist/optimization/index.js +10 -0
- package/dist/orchestration/flow-update-orchestrator.js +648 -0
- package/dist/rollback/smart-rollback-system.js +462 -0
- package/dist/templates/flow-template-system.js +625 -0
- package/dist/testing/flow-testing-automation.js +641 -0
- package/dist/testing/integration-test-suite.js +890 -0
- package/dist/utils/flow-structure-builder.js +1 -1
- package/dist/utils/servicenow-client.js +50 -2
- package/dist/utils/snow-oauth.js +66 -8
- package/dist/utils/xml-first-flow-generator.js +35 -8
- package/dist/version.js +13 -1
- package/package.json +1 -1
|
@@ -64,7 +64,7 @@ function generateFlowComponents(flowDefinition, flowSysId) {
|
|
|
64
64
|
type: 'flow',
|
|
65
65
|
status: 'published',
|
|
66
66
|
active: true,
|
|
67
|
-
run_as: '
|
|
67
|
+
run_as: 'user', // đ SEC-001 FIX: Default to 'user' to prevent privilege escalation
|
|
68
68
|
sys_class_name: 'sys_hub_flow',
|
|
69
69
|
table: flowDefinition.table,
|
|
70
70
|
category: 'custom',
|
|
@@ -10,6 +10,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.ServiceNowClient = void 0;
|
|
12
12
|
const axios_1 = __importDefault(require("axios"));
|
|
13
|
+
const https_1 = __importDefault(require("https"));
|
|
13
14
|
const snow_oauth_1 = require("./snow-oauth");
|
|
14
15
|
const action_type_cache_1 = require("./action-type-cache");
|
|
15
16
|
const snow_flow_config_js_1 = require("../config/snow-flow-config.js");
|
|
@@ -25,12 +26,59 @@ class ServiceNowClient {
|
|
|
25
26
|
this.lastTokenRefresh = 0;
|
|
26
27
|
this.logger = new logger_1.Logger('ServiceNowClient');
|
|
27
28
|
this.oauth = new snow_oauth_1.ServiceNowOAuth();
|
|
29
|
+
// đ SSL/TLS Certificate Validation Fix: Add proper HTTPS agent with certificate validation
|
|
30
|
+
const httpsAgent = new https_1.default.Agent({
|
|
31
|
+
rejectUnauthorized: true, // Enforce certificate validation
|
|
32
|
+
checkServerIdentity: (hostname, cert) => {
|
|
33
|
+
// Custom certificate validation for ServiceNow instances
|
|
34
|
+
// Allow *.service-now.com and user-configured instances
|
|
35
|
+
const validHosts = [
|
|
36
|
+
/.*\.service-now\.com$/,
|
|
37
|
+
/.*\.servicenow\.com$/
|
|
38
|
+
];
|
|
39
|
+
// Get configured instance hostname
|
|
40
|
+
const instanceUrl = process.env.SNOW_INSTANCE;
|
|
41
|
+
if (instanceUrl) {
|
|
42
|
+
try {
|
|
43
|
+
const instanceHostname = new URL(instanceUrl.startsWith('http') ? instanceUrl : `https://${instanceUrl}`).hostname;
|
|
44
|
+
validHosts.push(new RegExp(`^${instanceHostname.replace(/\./g, '\\.')}$`));
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// Invalid URL format, rely on default validation
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Check if hostname matches allowed patterns
|
|
51
|
+
if (validHosts.some(pattern => pattern.test(hostname))) {
|
|
52
|
+
return undefined; // Valid hostname
|
|
53
|
+
}
|
|
54
|
+
// For development/testing environments, allow localhost/127.0.0.1
|
|
55
|
+
if (process.env.NODE_ENV === 'development' &&
|
|
56
|
+
(hostname === 'localhost' || hostname === '127.0.0.1' || hostname.startsWith('192.168.'))) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return new Error(`Certificate hostname mismatch: ${hostname} not allowed`);
|
|
60
|
+
},
|
|
61
|
+
secureProtocol: 'TLSv1_2_method', // Enforce TLS 1.2 minimum
|
|
62
|
+
ciphers: [
|
|
63
|
+
'ECDHE-RSA-AES128-GCM-SHA256',
|
|
64
|
+
'ECDHE-RSA-AES256-GCM-SHA384',
|
|
65
|
+
'ECDHE-RSA-AES128-SHA256',
|
|
66
|
+
'ECDHE-RSA-AES256-SHA384'
|
|
67
|
+
].join(':'), // Only allow secure ciphers
|
|
68
|
+
honorCipherOrder: true,
|
|
69
|
+
maxVersion: 'TLSv1.3',
|
|
70
|
+
minVersion: 'TLSv1.2'
|
|
71
|
+
});
|
|
28
72
|
this.client = axios_1.default.create({
|
|
29
73
|
timeout: snow_flow_config_js_1.snowFlowConfig.servicenow.timeout,
|
|
30
74
|
headers: {
|
|
31
75
|
'Content-Type': 'application/json',
|
|
32
76
|
'Accept': 'application/json'
|
|
33
|
-
}
|
|
77
|
+
},
|
|
78
|
+
httpsAgent, // Use secure HTTPS agent with certificate validation
|
|
79
|
+
// Additional security headers
|
|
80
|
+
maxRedirects: 5,
|
|
81
|
+
validateStatus: (status) => status < 400 // Reject 4xx and 5xx by default
|
|
34
82
|
});
|
|
35
83
|
// đ§ CRITICAL FIX: Add makeRequest method to Axios instance to fix phantom calls
|
|
36
84
|
// Some code expects makeRequest to exist on this.client (the Axios instance)
|
|
@@ -1328,7 +1376,7 @@ snow_create_flow({
|
|
|
1328
1376
|
active: true, // Always create as active
|
|
1329
1377
|
internal_name: this.sanitizeInternalName(flow.name),
|
|
1330
1378
|
category: flow.category || 'custom',
|
|
1331
|
-
run_as: flow.run_as || '
|
|
1379
|
+
run_as: flow.run_as || 'user', // đ SEC-001 FIX: Default to 'user' to prevent privilege escalation
|
|
1332
1380
|
status: 'published', // đ§ FIX: Ensure flow is published, not draft
|
|
1333
1381
|
validated: true, // đ§ FIX: Mark as validated to allow activation
|
|
1334
1382
|
// Include complete flow definition to prevent corruption
|
package/dist/utils/snow-oauth.js
CHANGED
|
@@ -21,10 +21,33 @@ const snow_flow_config_js_1 = require("../config/snow-flow-config.js");
|
|
|
21
21
|
const unified_auth_store_js_1 = require("./unified-auth-store.js");
|
|
22
22
|
class ServiceNowOAuth {
|
|
23
23
|
constructor() {
|
|
24
|
+
// đ SEC-002 FIX: Add rate limiting to prevent authentication bypass attacks
|
|
25
|
+
this.lastTokenRequest = 0;
|
|
26
|
+
this.tokenRequestCount = 0;
|
|
27
|
+
this.TOKEN_REQUEST_WINDOW_MS = 60000; // 1 minute window
|
|
28
|
+
this.MAX_TOKEN_REQUESTS_PER_WINDOW = 10; // Max 10 token requests per minute
|
|
24
29
|
// Store tokens in user's home directory
|
|
25
30
|
const configDir = process.env.SNOW_FLOW_HOME || (0, path_1.join)(os_1.default.homedir(), '.snow-flow');
|
|
26
31
|
this.tokenPath = (0, path_1.join)(configDir, 'auth.json');
|
|
27
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* đ SEC-002 FIX: Check rate limiting for token requests to prevent brute force attacks
|
|
35
|
+
*/
|
|
36
|
+
checkTokenRequestRateLimit() {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
// Reset counter if window has passed
|
|
39
|
+
if (now - this.lastTokenRequest > this.TOKEN_REQUEST_WINDOW_MS) {
|
|
40
|
+
this.tokenRequestCount = 0;
|
|
41
|
+
this.lastTokenRequest = now;
|
|
42
|
+
}
|
|
43
|
+
// Check if within rate limit
|
|
44
|
+
if (this.tokenRequestCount >= this.MAX_TOKEN_REQUESTS_PER_WINDOW) {
|
|
45
|
+
console.warn('đ Rate limit exceeded: Too many token requests. Please wait before retrying.');
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
this.tokenRequestCount++;
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
28
51
|
/**
|
|
29
52
|
* Generate a random state parameter for CSRF protection
|
|
30
53
|
*/
|
|
@@ -62,8 +85,27 @@ class ServiceNowOAuth {
|
|
|
62
85
|
/**
|
|
63
86
|
* Initialize OAuth flow - opens browser and handles callback
|
|
64
87
|
*/
|
|
88
|
+
/**
|
|
89
|
+
* đ§ CRIT-002 FIX: Normalize instance URL to prevent trailing slash 400 errors
|
|
90
|
+
*/
|
|
91
|
+
normalizeInstanceUrl(instance) {
|
|
92
|
+
// Remove any trailing slashes that cause 400 errors
|
|
93
|
+
let normalized = instance.replace(/\/+$/, '');
|
|
94
|
+
// Add https:// if missing
|
|
95
|
+
if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) {
|
|
96
|
+
normalized = `https://${normalized}`;
|
|
97
|
+
}
|
|
98
|
+
// Ensure .service-now.com suffix if it's just the instance name
|
|
99
|
+
if (!normalized.includes('.service-now.com') && !normalized.includes('localhost') && !normalized.includes('127.0.0.1')) {
|
|
100
|
+
const instanceName = normalized.replace('https://', '').replace('http://', '');
|
|
101
|
+
normalized = `https://${instanceName}.service-now.com`;
|
|
102
|
+
}
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
65
105
|
async authenticate(instance, clientId, clientSecret) {
|
|
66
106
|
try {
|
|
107
|
+
// đ§ CRIT-002 FIX: Apply URL normalization
|
|
108
|
+
const normalizedInstance = this.normalizeInstanceUrl(instance);
|
|
67
109
|
// Validate client secret format
|
|
68
110
|
const secretValidation = this.validateClientSecret(clientSecret);
|
|
69
111
|
if (!secretValidation.valid) {
|
|
@@ -94,15 +136,15 @@ class ServiceNowOAuth {
|
|
|
94
136
|
error: `Port ${port} is already in use. Please free up the port and try again.`
|
|
95
137
|
};
|
|
96
138
|
}
|
|
97
|
-
// Store credentials temporarily
|
|
139
|
+
// Store credentials temporarily with normalized instance
|
|
98
140
|
this.credentials = {
|
|
99
|
-
instance:
|
|
141
|
+
instance: normalizedInstance.replace('https://', '').replace('http://', ''),
|
|
100
142
|
clientId,
|
|
101
143
|
clientSecret,
|
|
102
144
|
redirectUri
|
|
103
145
|
};
|
|
104
146
|
console.log('đ Starting ServiceNow OAuth flow...');
|
|
105
|
-
console.log(`đ Instance: ${
|
|
147
|
+
console.log(`đ Instance: ${normalizedInstance}`);
|
|
106
148
|
console.log(`đ Client ID: ${clientId}`);
|
|
107
149
|
console.log(`đ Redirect URI: ${redirectUri}`);
|
|
108
150
|
// Generate state parameter for CSRF protection
|
|
@@ -110,18 +152,18 @@ class ServiceNowOAuth {
|
|
|
110
152
|
// Generate PKCE parameters
|
|
111
153
|
this.generatePKCE();
|
|
112
154
|
// Generate authorization URL
|
|
113
|
-
const authUrl = this.generateAuthUrl(instance, clientId, redirectUri);
|
|
155
|
+
const authUrl = this.generateAuthUrl(this.credentials.instance, clientId, redirectUri);
|
|
114
156
|
console.log('\nđ Authorization URL generated:');
|
|
115
157
|
console.log(`${authUrl}\n`);
|
|
116
158
|
// Start local server to handle callback
|
|
117
159
|
const authResult = await this.startCallbackServer(redirectUri, port);
|
|
118
160
|
if (authResult.success && authResult.accessToken) {
|
|
119
|
-
// Save tokens
|
|
161
|
+
// Save tokens with normalized instance
|
|
120
162
|
await this.saveTokens({
|
|
121
163
|
accessToken: authResult.accessToken,
|
|
122
164
|
refreshToken: authResult.refreshToken || '',
|
|
123
165
|
expiresIn: authResult.expiresIn || 3600,
|
|
124
|
-
instance: instance
|
|
166
|
+
instance: this.credentials.instance,
|
|
125
167
|
clientId,
|
|
126
168
|
clientSecret
|
|
127
169
|
});
|
|
@@ -303,6 +345,13 @@ class ServiceNowOAuth {
|
|
|
303
345
|
*/
|
|
304
346
|
async exchangeCodeForTokens(code) {
|
|
305
347
|
try {
|
|
348
|
+
// đ SEC-002 FIX: Apply rate limiting to prevent authentication bypass attacks
|
|
349
|
+
if (!this.checkTokenRequestRateLimit()) {
|
|
350
|
+
return {
|
|
351
|
+
success: false,
|
|
352
|
+
error: 'Rate limit exceeded. Too many token requests. Please wait 1 minute before retrying.'
|
|
353
|
+
};
|
|
354
|
+
}
|
|
306
355
|
const tokenUrl = `https://${this.credentials.instance}/oauth_token.do`;
|
|
307
356
|
const response = await axios_1.default.post(tokenUrl, new URLSearchParams({
|
|
308
357
|
grant_type: 'authorization_code',
|
|
@@ -314,7 +363,8 @@ class ServiceNowOAuth {
|
|
|
314
363
|
}), {
|
|
315
364
|
headers: {
|
|
316
365
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
317
|
-
}
|
|
366
|
+
},
|
|
367
|
+
timeout: 15000 // đ SEC-002 FIX: 15 second timeout to prevent hanging requests
|
|
318
368
|
});
|
|
319
369
|
const data = response.data;
|
|
320
370
|
if (data.access_token) {
|
|
@@ -434,6 +484,13 @@ class ServiceNowOAuth {
|
|
|
434
484
|
*/
|
|
435
485
|
async refreshAccessToken(tokens) {
|
|
436
486
|
try {
|
|
487
|
+
// đ SEC-002 FIX: Apply rate limiting to prevent authentication bypass attacks
|
|
488
|
+
if (!this.checkTokenRequestRateLimit()) {
|
|
489
|
+
return {
|
|
490
|
+
success: false,
|
|
491
|
+
error: 'Rate limit exceeded. Too many token requests. Please wait 1 minute before retrying.'
|
|
492
|
+
};
|
|
493
|
+
}
|
|
437
494
|
// If no tokens provided, load from file
|
|
438
495
|
if (!tokens) {
|
|
439
496
|
tokens = await this.loadTokens();
|
|
@@ -453,7 +510,8 @@ class ServiceNowOAuth {
|
|
|
453
510
|
}), {
|
|
454
511
|
headers: {
|
|
455
512
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
456
|
-
}
|
|
513
|
+
},
|
|
514
|
+
timeout: 15000 // đ SEC-002 FIX: 15 second timeout to prevent hanging requests
|
|
457
515
|
});
|
|
458
516
|
const data = response.data;
|
|
459
517
|
if (data.access_token) {
|
|
@@ -124,26 +124,47 @@ class XMLFirstFlowGenerator {
|
|
|
124
124
|
.replace(/\t/g, '	'); // Preserve tabs
|
|
125
125
|
return escaped;
|
|
126
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* đĄī¸ Apply security defaults to flow definition - BUG-004 FIX
|
|
129
|
+
*/
|
|
130
|
+
applySecurityDefaults(flowDef) {
|
|
131
|
+
// đ SECURITY GUARD: Never allow public access unless explicitly and safely configured
|
|
132
|
+
const secureFlowDef = {
|
|
133
|
+
...flowDef,
|
|
134
|
+
// Override with secure defaults - these CANNOT be accidentally public
|
|
135
|
+
accessible_from: 'package_private', // FORCE secure default
|
|
136
|
+
run_as: flowDef.run_as || 'user' // Default to user, not system
|
|
137
|
+
};
|
|
138
|
+
// đ¨ Log security override for audit trail
|
|
139
|
+
if (flowDef.accessible_from && flowDef.accessible_from !== 'package_private') {
|
|
140
|
+
console.log('đĄī¸ SECURITY OVERRIDE: Flow access forced to package_private for security');
|
|
141
|
+
console.log(` âĸ Original: ${flowDef.accessible_from}`);
|
|
142
|
+
console.log(` âĸ Applied: package_private (secure)`);
|
|
143
|
+
}
|
|
144
|
+
return secureFlowDef;
|
|
145
|
+
}
|
|
127
146
|
/**
|
|
128
147
|
* Generate complete Update Set XML for a flow
|
|
129
148
|
* Based on REAL ServiceNow XML structure research
|
|
130
149
|
*/
|
|
131
150
|
generateFlowUpdateSetXML(flowDef) {
|
|
151
|
+
// đ BUG-004 FIX: Apply security defaults FIRST
|
|
152
|
+
const secureFlowDef = this.applySecurityDefaults(flowDef);
|
|
132
153
|
this.flowSysId = this.generateSysId();
|
|
133
154
|
const timestamp = new Date().toISOString();
|
|
134
|
-
const internalName =
|
|
155
|
+
const internalName = secureFlowDef.internal_name || this.generateInternalName(secureFlowDef.name);
|
|
135
156
|
// Generate all component sys_ids upfront
|
|
136
157
|
const updateSetSysId = this.generateSysId();
|
|
137
158
|
const snapshotSysId = this.generateSysId();
|
|
138
159
|
const triggerSysId = this.generateSysId();
|
|
139
|
-
const activitySysIds =
|
|
160
|
+
const activitySysIds = secureFlowDef.activities.map(() => this.generateSysId());
|
|
140
161
|
const logicSysIds = []; // For flow logic connections
|
|
141
162
|
// Calculate logic chain sys_ids
|
|
142
163
|
for (let i = 0; i < activitySysIds.length + 2; i++) {
|
|
143
164
|
logicSysIds.push(this.generateSysId());
|
|
144
165
|
}
|
|
145
166
|
// Build the complete flow definition JSON for snapshot
|
|
146
|
-
const flowDefinitionJson = this.buildFlowDefinitionJson(
|
|
167
|
+
const flowDefinitionJson = this.buildFlowDefinitionJson(secureFlowDef, triggerSysId, activitySysIds);
|
|
147
168
|
// Generate XML - MUST use sys_remote_update_set for imports!
|
|
148
169
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
149
170
|
<unload unload_date="${timestamp}">
|
|
@@ -151,7 +172,7 @@ class XMLFirstFlowGenerator {
|
|
|
151
172
|
<sys_remote_update_set action="INSERT_OR_UPDATE">
|
|
152
173
|
<sys_id>${updateSetSysId}</sys_id>
|
|
153
174
|
<name>${this.escapeXml(this.updateSetName)}</name>
|
|
154
|
-
<description>Flow import: ${this.escapeXml(
|
|
175
|
+
<description>Flow import: ${this.escapeXml(secureFlowDef.name)}</description>
|
|
155
176
|
<remote_sys_id>${updateSetSysId}</remote_sys_id>
|
|
156
177
|
<state>loaded</state>
|
|
157
178
|
<application>global</application>
|
|
@@ -165,7 +186,7 @@ class XMLFirstFlowGenerator {
|
|
|
165
186
|
<action>INSERT_OR_UPDATE</action>
|
|
166
187
|
<application>global</application>
|
|
167
188
|
<name>sys_hub_flow_${this.flowSysId}</name>
|
|
168
|
-
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow"><sys_hub_flow action="INSERT_OR_UPDATE"><sys_id>${this.flowSysId}</sys_id><name>${this.escapeXml(
|
|
189
|
+
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow"><sys_hub_flow action="INSERT_OR_UPDATE"><sys_id>${this.flowSysId}</sys_id><name>${this.escapeXml(secureFlowDef.name)}</name><internal_name>${this.escapeXml(internalName)}</internal_name><description>${this.escapeXml(secureFlowDef.description)}</description><active>true</active><type>flow</type><category>custom</category><sys_scope display_value="Global">global</sys_scope><sys_app display_value="Global">global</sys_app><sys_package display_value="Global" source="global">global</sys_package><access>${secureFlowDef.accessible_from}</access><run_as>${secureFlowDef.run_as}</run_as><sys_class_name>sys_hub_flow</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${timestamp}</sys_created_on><sys_domain>global</sys_domain><sys_domain_path>/</sys_domain_path><sys_updated_by>admin</sys_updated_by><sys_updated_on>${timestamp}</sys_updated_on><latest_snapshot>${snapshotSysId}</latest_snapshot><master_snapshot>${snapshotSysId}</master_snapshot><natlang/><copied_from/><copied_from_name/><show_draft_actions>false</show_draft_actions><show_row_wfr_actions>false</show_row_wfr_actions><show_wf_actions>false</show_wf_actions><sys_overrides/><sys_policy/></sys_hub_flow></record_update>]]></payload>
|
|
169
190
|
<remote_update_set>${updateSetSysId}</remote_update_set>
|
|
170
191
|
<source_table>sys_hub_flow</source_table>
|
|
171
192
|
<sys_recorded_at>${timestamp}</sys_recorded_at>
|
|
@@ -179,7 +200,7 @@ class XMLFirstFlowGenerator {
|
|
|
179
200
|
<action>INSERT_OR_UPDATE</action>
|
|
180
201
|
<application>global</application>
|
|
181
202
|
<name>sys_hub_flow_snapshot_${snapshotSysId}</name>
|
|
182
|
-
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow_snapshot"><sys_hub_flow_snapshot action="INSERT_OR_UPDATE"><sys_id>${snapshotSysId}</sys_id><name>${this.escapeXml(
|
|
203
|
+
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow_snapshot"><sys_hub_flow_snapshot action="INSERT_OR_UPDATE"><sys_id>${snapshotSysId}</sys_id><name>${this.escapeXml(secureFlowDef.name)}</name><flow>${this.flowSysId}</flow><note>Initial version</note><snapshot>${this.escapeForXml(JSON.stringify(flowDefinitionJson, null, 2))}</snapshot><sys_created_by>admin</sys_created_by><sys_created_on>${timestamp}</sys_created_on></sys_hub_flow_snapshot></record_update>]]></payload>
|
|
183
204
|
<remote_update_set>${updateSetSysId}</remote_update_set>
|
|
184
205
|
<source_table>sys_hub_flow_snapshot</source_table>
|
|
185
206
|
<type>Flow Designer Snapshot</type>
|
|
@@ -191,13 +212,13 @@ class XMLFirstFlowGenerator {
|
|
|
191
212
|
<action>INSERT_OR_UPDATE</action>
|
|
192
213
|
<application>global</application>
|
|
193
214
|
<name>sys_hub_trigger_instance_${triggerSysId}</name>
|
|
194
|
-
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_trigger_instance"><sys_hub_trigger_instance action="INSERT_OR_UPDATE"><sys_id>${triggerSysId}</sys_id><flow>${this.flowSysId}</flow><trigger_type>${this.getTriggerTypeId(
|
|
215
|
+
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_trigger_instance"><sys_hub_trigger_instance action="INSERT_OR_UPDATE"><sys_id>${triggerSysId}</sys_id><flow>${this.flowSysId}</flow><trigger_type>${this.getTriggerTypeId(secureFlowDef.trigger_type)}</trigger_type><table>${secureFlowDef.table || ''}</table><condition>${this.escapeXml(secureFlowDef.trigger_condition || '')}</condition><order>100</order><active>true</active><sys_class_name>sys_hub_trigger_instance</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${timestamp}</sys_created_on><sys_domain>global</sys_domain><sys_domain_path>/</sys_domain_path></sys_hub_trigger_instance></record_update>]]></payload>
|
|
195
216
|
<remote_update_set>${updateSetSysId}</remote_update_set>
|
|
196
217
|
<source_table>sys_hub_trigger_instance</source_table>
|
|
197
218
|
<type>Flow Designer Trigger</type>
|
|
198
219
|
</sys_update_xml>
|
|
199
220
|
|
|
200
|
-
${this.generateActionInstancesXML(
|
|
221
|
+
${this.generateActionInstancesXML(secureFlowDef.activities, activitySysIds, timestamp, updateSetSysId)}
|
|
201
222
|
${this.generateFlowLogicXML(triggerSysId, activitySysIds, logicSysIds, timestamp, updateSetSysId)}
|
|
202
223
|
</unload>`;
|
|
203
224
|
return xml;
|
|
@@ -432,6 +453,12 @@ class XMLFirstFlowGenerator {
|
|
|
432
453
|
getActionTypeId(actionType) {
|
|
433
454
|
return exports.ACTION_TYPE_SYS_IDS[actionType] || exports.ACTION_TYPE_SYS_IDS['script'];
|
|
434
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Generate complete Flow XML - alias for backward compatibility
|
|
458
|
+
*/
|
|
459
|
+
generateCompleteFlowXML(flowDef) {
|
|
460
|
+
return this.generateFlowUpdateSetXML(flowDef);
|
|
461
|
+
}
|
|
435
462
|
/**
|
|
436
463
|
* Save XML to file
|
|
437
464
|
*/
|
package/dist/version.js
CHANGED
|
@@ -7,12 +7,24 @@ exports.VERSION_INFO = exports.VERSION = void 0;
|
|
|
7
7
|
exports.getVersionString = getVersionString;
|
|
8
8
|
exports.getLatestFeatures = getLatestFeatures;
|
|
9
9
|
exports.isLatestVersion = isLatestVersion;
|
|
10
|
-
exports.VERSION = '1.3.
|
|
10
|
+
exports.VERSION = '1.3.27';
|
|
11
11
|
exports.VERSION_INFO = {
|
|
12
12
|
version: exports.VERSION,
|
|
13
13
|
name: 'Snow-Flow',
|
|
14
14
|
description: 'ServiceNow Queen Agent - Hive-Mind Intelligence for ServiceNow Development',
|
|
15
15
|
features: {
|
|
16
|
+
'1.3.27': [
|
|
17
|
+
'đ¤ AUTONOMOUS SYSTEMS: All 4 autonomous systems now ENABLED BY DEFAULT in swarm command!',
|
|
18
|
+
'â
SELF-DOCUMENTING: Automatic documentation generation and updates (default: enabled)',
|
|
19
|
+
'đ° COST OPTIMIZATION: AI-driven cost management with auto-optimization (default: enabled)',
|
|
20
|
+
'đ COMPLIANCE MONITORING: Multi-framework compliance with auto-remediation (default: enabled)',
|
|
21
|
+
'đĨ SELF-HEALING: Predictive failure detection with automatic recovery (default: enabled)',
|
|
22
|
+
'âī¸ FLEXIBLE CONTROL: Use --no-autonomous-* flags to disable specific systems',
|
|
23
|
+
'đĢ GLOBAL DISABLE: Use --no-autonomous-all to disable all autonomous systems',
|
|
24
|
+
'đĒ FORCE OVERRIDE: Use --autonomous-all to force enable all (overrides --no- flags)',
|
|
25
|
+
'đ¯ PERFECT ORCHESTRATOR: True "ÊÊn command voor alles" - zero manual intervention needed!',
|
|
26
|
+
'Based on user request: "oke maar kunnen we het niet als standaard aanzetten dat al deze dingen beschikbaar zijn?"'
|
|
27
|
+
],
|
|
16
28
|
'1.3.16': [
|
|
17
29
|
'đ VERSION BUMP: Clean version update for npm publish',
|
|
18
30
|
'⨠INCLUDES: All improvements from v1.3.15',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.27",
|
|
4
4
|
"description": "ServiceNow Queen Agent - Hive-Mind Intelligence for ServiceNow Development inspired by claude-flow. Transform complex workflows into elegant one-command orchestration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|