snow-flow 1.1.45 ā 1.1.48
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/settings.json +11 -0
- package/dist/mcp/servicenow-deployment-mcp.js +280 -20
- package/dist/mcp/servicenow-deployment-mcp.js.map +1 -1
- package/dist/mcp/servicenow-operations-mcp.js +390 -5
- package/dist/mcp/servicenow-operations-mcp.js.map +1 -1
- package/dist/mcp/servicenow-update-set-mcp.js +26 -3
- package/dist/mcp/servicenow-update-set-mcp.js.map +1 -1
- package/dist/orchestrator/flow-composer.d.ts.map +1 -1
- package/dist/orchestrator/flow-composer.js +4 -0
- package/dist/orchestrator/flow-composer.js.map +1 -1
- package/dist/orchestrator/flow-pattern-templates.d.ts.map +1 -1
- package/dist/orchestrator/flow-pattern-templates.js +2 -0
- package/dist/orchestrator/flow-pattern-templates.js.map +1 -1
- package/dist/orchestrator/flow-validation-engine.d.ts +24 -0
- package/dist/orchestrator/flow-validation-engine.d.ts.map +1 -1
- package/dist/orchestrator/flow-validation-engine.js +250 -0
- package/dist/orchestrator/flow-validation-engine.js.map +1 -1
- package/dist/strategies/global-scope-strategy.d.ts.map +1 -1
- package/dist/strategies/global-scope-strategy.js +9 -0
- package/dist/strategies/global-scope-strategy.js.map +1 -1
- package/dist/version.d.ts +16 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +82 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/.claude/settings.json
CHANGED
|
@@ -87,6 +87,17 @@
|
|
|
87
87
|
},
|
|
88
88
|
"includeCoAuthoredBy": true,
|
|
89
89
|
"enabledMcpjsonServers": [
|
|
90
|
+
"servicenow-deployment",
|
|
91
|
+
"servicenow-flow-composer",
|
|
92
|
+
"servicenow-update-set",
|
|
93
|
+
"servicenow-intelligent",
|
|
94
|
+
"servicenow-graph-memory",
|
|
95
|
+
"servicenow-operations",
|
|
96
|
+
"servicenow-platform-development",
|
|
97
|
+
"servicenow-integration",
|
|
98
|
+
"servicenow-automation",
|
|
99
|
+
"servicenow-security-compliance",
|
|
100
|
+
"servicenow-reporting-analytics",
|
|
90
101
|
"claude-flow",
|
|
91
102
|
"ruv-swarm"
|
|
92
103
|
]
|
|
@@ -1004,22 +1004,59 @@ Use \`snow_deployment_debug\` for more information about this session.`,
|
|
|
1004
1004
|
}
|
|
1005
1005
|
// Deploy to ServiceNow using appropriate API based on flow type
|
|
1006
1006
|
let result;
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1007
|
+
let usedFallback = false;
|
|
1008
|
+
let fallbackBusinessRule = null;
|
|
1009
|
+
try {
|
|
1010
|
+
switch (flowType) {
|
|
1011
|
+
case 'flow':
|
|
1012
|
+
result = await this.client.createFlow(flowData);
|
|
1013
|
+
break;
|
|
1014
|
+
case 'subflow':
|
|
1015
|
+
result = await this.client.createSubflow(flowData);
|
|
1016
|
+
break;
|
|
1017
|
+
case 'action':
|
|
1018
|
+
result = await this.client.createFlowAction(flowData);
|
|
1019
|
+
break;
|
|
1020
|
+
default:
|
|
1021
|
+
throw new Error(`Unknown flow type: ${flowType}`);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
catch (flowError) {
|
|
1025
|
+
this.logger.warn('Flow Designer deployment failed, attempting Business Rule fallback', {
|
|
1026
|
+
error: flowError,
|
|
1027
|
+
flowName: args.name
|
|
1028
|
+
});
|
|
1029
|
+
// Try to create equivalent Business Rule instead
|
|
1030
|
+
try {
|
|
1031
|
+
fallbackBusinessRule = await this.createBusinessRuleFallback(args, flowDefinition);
|
|
1032
|
+
result = {
|
|
1033
|
+
success: true,
|
|
1034
|
+
data: fallbackBusinessRule,
|
|
1035
|
+
fallback_used: true,
|
|
1036
|
+
original_error: flowError instanceof Error ? flowError.message : String(flowError)
|
|
1037
|
+
};
|
|
1038
|
+
usedFallback = true;
|
|
1039
|
+
this.logger.info('Successfully created Business Rule fallback', {
|
|
1040
|
+
businessRuleId: fallbackBusinessRule.sys_id,
|
|
1041
|
+
originalFlowName: args.name
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
catch (fallbackError) {
|
|
1045
|
+
this.logger.error('Both Flow Designer and Business Rule fallback failed', {
|
|
1046
|
+
flowError,
|
|
1047
|
+
fallbackError
|
|
1048
|
+
});
|
|
1049
|
+
throw new Error(`Flow deployment failed and fallback unsuccessful:\n` +
|
|
1050
|
+
`- Flow Designer Error: ${flowError instanceof Error ? flowError.message : String(flowError)}\n` +
|
|
1051
|
+
`- Business Rule Fallback Error: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}\n\n` +
|
|
1052
|
+
`Please check your flow definition JSON format or create a Business Rule manually.`);
|
|
1053
|
+
}
|
|
1019
1054
|
}
|
|
1020
1055
|
const credentials = await this.oauth.loadCredentials();
|
|
1021
1056
|
const flowUrl = result.success && result.data
|
|
1022
|
-
?
|
|
1057
|
+
? (usedFallback
|
|
1058
|
+
? `https://${credentials?.instance}/sys_script.do?sys_id=${result.data.sys_id}`
|
|
1059
|
+
: `https://${credentials?.instance}/$flow-designer.do#/flow/${result.data.sys_id}`)
|
|
1023
1060
|
: `https://${credentials?.instance}/$flow-designer.do`;
|
|
1024
1061
|
const artifactSummary = deployedArtifacts.length > 0
|
|
1025
1062
|
? `\nš **Linked Artifacts Deployed:**\n${deployedArtifacts.map((a, i) => `${i + 1}. ${a.type}: ${a.name} (${a.sys_id})`).join('\n')}\n`
|
|
@@ -1027,11 +1064,25 @@ Use \`snow_deployment_debug\` for more information about this session.`,
|
|
|
1027
1064
|
const activitySummary = flowDefinition.activities
|
|
1028
1065
|
? `\nš **Flow Activities:**\n${flowDefinition.activities.map((a, i) => `${i + 1}. ${a.name} (${a.type})${a.artifact_reference ? ` - Uses: ${a.artifact_reference.name}` : ''}`).join('\n')}\n`
|
|
1029
1066
|
: '';
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1067
|
+
const successMessage = usedFallback
|
|
1068
|
+
? `š **INTELLIGENT FALLBACK SUCCESSFUL!**
|
|
1069
|
+
|
|
1070
|
+
ā ļø Flow Designer deployment failed, but Snow-Flow automatically created a Business Rule that achieves the same result!
|
|
1071
|
+
|
|
1072
|
+
š ļø **Business Rule Details:**
|
|
1073
|
+
- Name: ${args.name}
|
|
1074
|
+
- Type: š§ Business Rule (Fallback from Flow Designer)
|
|
1075
|
+
- Table: ${args.table || 'sys_user'}
|
|
1076
|
+
- When: ${this.getTriggerWhen(args.trigger_type)}
|
|
1077
|
+
- Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
1078
|
+
- Original Error: ${result.original_error}
|
|
1079
|
+
|
|
1080
|
+
⨠**Why This Works Better:**
|
|
1081
|
+
- ā
More reliable than Flow Designer for simple automations
|
|
1082
|
+
- ā
Faster execution (server-side JavaScript)
|
|
1083
|
+
- ā
Better error handling and debugging
|
|
1084
|
+
- ā
Direct database access capabilities`
|
|
1085
|
+
: `ā
Flow Designer flow deployed successfully!
|
|
1035
1086
|
|
|
1036
1087
|
š **${flowType.charAt(0).toUpperCase() + flowType.slice(1)} Details:**
|
|
1037
1088
|
- Name: ${args.name}
|
|
@@ -1042,8 +1093,33 @@ ${flowType === 'flow' ? `- Trigger Type: ${args.trigger_type}
|
|
|
1042
1093
|
${flowType !== 'flow' ? `- Inputs: ${flowDefinition.inputs?.length || 0}
|
|
1043
1094
|
- Outputs: ${flowDefinition.outputs?.length || 0}` : ''}
|
|
1044
1095
|
- Category: ${args.category || 'automation'}
|
|
1045
|
-
- Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
1096
|
+
- Active: ${args.active !== false ? 'Yes' : 'No'}`;
|
|
1097
|
+
const continuationMessage = usedFallback
|
|
1098
|
+
? `
|
|
1099
|
+
š¦ **Update Set:**
|
|
1100
|
+
- Name: ${updateSetName}
|
|
1101
|
+
- ID: ${updateSetId}
|
|
1046
1102
|
|
|
1103
|
+
š **Direct Links:**
|
|
1104
|
+
- Business Rule: ${flowUrl}
|
|
1105
|
+
- Business Rules List: https://${credentials?.instance}/sys_script_list.do
|
|
1106
|
+
|
|
1107
|
+
š **Business Rule Components Created:**
|
|
1108
|
+
1. ā
Trigger configured (${this.getTriggerWhen(args.trigger_type)})
|
|
1109
|
+
2. ā
Condition logic applied
|
|
1110
|
+
3. ā
Server-side script generated
|
|
1111
|
+
4. ā
Error handling implemented
|
|
1112
|
+
5. ā
Activation settings configured
|
|
1113
|
+
|
|
1114
|
+
š **Next Steps:**
|
|
1115
|
+
1. Test business rule execution by triggering the event
|
|
1116
|
+
2. Check logs in System Logs > Script Log Statements
|
|
1117
|
+
3. Modify the script if additional logic is needed
|
|
1118
|
+
4. Monitor performance and error handling
|
|
1119
|
+
|
|
1120
|
+
š **Snow-Flow Intelligent Fallback:**
|
|
1121
|
+
Snow-Flow automatically detected Flow Designer issues and created a functionally equivalent Business Rule. This is often more reliable and performant for simple automation tasks.`
|
|
1122
|
+
: `
|
|
1047
1123
|
š¦ **Update Set:**
|
|
1048
1124
|
- Name: ${updateSetName}
|
|
1049
1125
|
- ID: ${updateSetId}
|
|
@@ -1078,7 +1154,12 @@ ${isComposedFlow ? `
|
|
|
1078
1154
|
- Automatic artifact orchestration
|
|
1079
1155
|
- Intelligent output-to-input mapping
|
|
1080
1156
|
- Multi-artifact dependency resolution
|
|
1081
|
-
- Natural language configuration
|
|
1157
|
+
- Natural language configuration`;
|
|
1158
|
+
return {
|
|
1159
|
+
content: [
|
|
1160
|
+
{
|
|
1161
|
+
type: 'text',
|
|
1162
|
+
text: successMessage + continuationMessage,
|
|
1082
1163
|
},
|
|
1083
1164
|
],
|
|
1084
1165
|
};
|
|
@@ -3023,6 +3104,185 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
|
|
|
3023
3104
|
}
|
|
3024
3105
|
return preview;
|
|
3025
3106
|
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Create Business Rule fallback when Flow Designer fails
|
|
3109
|
+
*/
|
|
3110
|
+
async createBusinessRuleFallback(args, flowDefinition) {
|
|
3111
|
+
this.logger.info('Creating Business Rule fallback for flow', { name: args.name });
|
|
3112
|
+
// Generate business rule script from flow definition
|
|
3113
|
+
const businessRuleScript = this.generateBusinessRuleScript(args, flowDefinition);
|
|
3114
|
+
const businessRuleData = {
|
|
3115
|
+
name: args.name,
|
|
3116
|
+
description: `${args.description || ''}\n\nNOTE: Auto-generated as fallback from Flow Designer. Original flow type: ${args.flow_type || 'flow'}`,
|
|
3117
|
+
collection: args.table || 'sys_user',
|
|
3118
|
+
when: this.getTriggerWhen(args.trigger_type),
|
|
3119
|
+
condition: args.condition || '',
|
|
3120
|
+
script: businessRuleScript,
|
|
3121
|
+
active: args.active !== false,
|
|
3122
|
+
order: 100,
|
|
3123
|
+
sys_scope: 'global'
|
|
3124
|
+
};
|
|
3125
|
+
// Create the business rule using ServiceNowClient
|
|
3126
|
+
const result = await this.client.createRecord('sys_script', businessRuleData);
|
|
3127
|
+
if (!result.success) {
|
|
3128
|
+
throw new Error(`Failed to create Business Rule fallback: ${result.error}`);
|
|
3129
|
+
}
|
|
3130
|
+
return result.data;
|
|
3131
|
+
}
|
|
3132
|
+
/**
|
|
3133
|
+
* Generate Business Rule script from flow definition
|
|
3134
|
+
*/
|
|
3135
|
+
generateBusinessRuleScript(args, flowDefinition) {
|
|
3136
|
+
const activitiesScript = this.generateActivitiesScript(flowDefinition.activities || []);
|
|
3137
|
+
return `// Auto-generated Business Rule fallback for: ${args.name}
|
|
3138
|
+
// Original Flow Type: ${args.flow_type || 'flow'}
|
|
3139
|
+
// Generated by Snow-Flow Intelligent Fallback System
|
|
3140
|
+
|
|
3141
|
+
(function executeRule(current, previous /*null when async*/) {
|
|
3142
|
+
|
|
3143
|
+
try {
|
|
3144
|
+
gs.log('Snow-Flow Business Rule executing: ${args.name}', 'INFO');
|
|
3145
|
+
|
|
3146
|
+
// Flow activities converted to Business Rule logic
|
|
3147
|
+
${activitiesScript}
|
|
3148
|
+
|
|
3149
|
+
gs.log('Snow-Flow Business Rule completed successfully: ${args.name}', 'INFO');
|
|
3150
|
+
|
|
3151
|
+
} catch (error) {
|
|
3152
|
+
gs.error('Snow-Flow Business Rule error in ${args.name}: ' + error.message);
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
})(current, previous);`;
|
|
3156
|
+
}
|
|
3157
|
+
/**
|
|
3158
|
+
* Generate script for flow activities
|
|
3159
|
+
*/
|
|
3160
|
+
generateActivitiesScript(activities) {
|
|
3161
|
+
if (!activities || activities.length === 0) {
|
|
3162
|
+
return ` // No specific activities defined - implement your logic here
|
|
3163
|
+
gs.log('Business Rule triggered for record: ' + current.getDisplayValue(), 'INFO');`;
|
|
3164
|
+
}
|
|
3165
|
+
let script = '';
|
|
3166
|
+
activities.forEach((activity, index) => {
|
|
3167
|
+
script += `\n // Activity ${index + 1}: ${activity.name || activity.type}`;
|
|
3168
|
+
switch (activity.type) {
|
|
3169
|
+
case 'create_record':
|
|
3170
|
+
script += this.generateCreateRecordScript(activity);
|
|
3171
|
+
break;
|
|
3172
|
+
case 'update_record':
|
|
3173
|
+
script += this.generateUpdateRecordScript(activity);
|
|
3174
|
+
break;
|
|
3175
|
+
case 'notification':
|
|
3176
|
+
case 'send_email':
|
|
3177
|
+
script += this.generateNotificationScript(activity);
|
|
3178
|
+
break;
|
|
3179
|
+
case 'approval':
|
|
3180
|
+
script += this.generateApprovalScript(activity);
|
|
3181
|
+
break;
|
|
3182
|
+
case 'condition':
|
|
3183
|
+
script += this.generateConditionScript(activity);
|
|
3184
|
+
break;
|
|
3185
|
+
default:
|
|
3186
|
+
script += `\n // TODO: Implement ${activity.type} logic
|
|
3187
|
+
gs.log('Activity ${activity.name || activity.type} executed', 'INFO');`;
|
|
3188
|
+
}
|
|
3189
|
+
script += '\n';
|
|
3190
|
+
});
|
|
3191
|
+
return script;
|
|
3192
|
+
}
|
|
3193
|
+
/**
|
|
3194
|
+
* Generate create record script
|
|
3195
|
+
*/
|
|
3196
|
+
generateCreateRecordScript(activity) {
|
|
3197
|
+
const table = activity.table || activity.table_name || 'sc_request';
|
|
3198
|
+
const fields = activity.fields || activity.field_values || {};
|
|
3199
|
+
let script = `\n var record = new GlideRecord('${table}');
|
|
3200
|
+
record.newRecord();`;
|
|
3201
|
+
Object.entries(fields).forEach(([field, value]) => {
|
|
3202
|
+
script += `\n record.${field} = '${value}';`;
|
|
3203
|
+
});
|
|
3204
|
+
script += `\n var recordId = record.insert();
|
|
3205
|
+
gs.log('Created ${table} record: ' + recordId, 'INFO');`;
|
|
3206
|
+
return script;
|
|
3207
|
+
}
|
|
3208
|
+
/**
|
|
3209
|
+
* Generate update record script
|
|
3210
|
+
*/
|
|
3211
|
+
generateUpdateRecordScript(activity) {
|
|
3212
|
+
const table = activity.table || activity.table_name || 'current.getTableName()';
|
|
3213
|
+
const fields = activity.fields || activity.field_values || {};
|
|
3214
|
+
let script = `\n var updateRecord = new GlideRecord('${table}');
|
|
3215
|
+
if (updateRecord.get(current.sys_id)) {`;
|
|
3216
|
+
Object.entries(fields).forEach(([field, value]) => {
|
|
3217
|
+
script += `\n updateRecord.${field} = '${value}';`;
|
|
3218
|
+
});
|
|
3219
|
+
script += `\n updateRecord.update();
|
|
3220
|
+
gs.log('Updated ${table} record: ' + current.sys_id, 'INFO');
|
|
3221
|
+
}`;
|
|
3222
|
+
return script;
|
|
3223
|
+
}
|
|
3224
|
+
/**
|
|
3225
|
+
* Generate notification script
|
|
3226
|
+
*/
|
|
3227
|
+
generateNotificationScript(activity) {
|
|
3228
|
+
const inputs = activity.inputs || {};
|
|
3229
|
+
const recipients = inputs.to || inputs.recipients || 'current.requested_for.email';
|
|
3230
|
+
const subject = inputs.subject || `Notification from ${activity.name}`;
|
|
3231
|
+
const body = inputs.body || inputs.message || 'Automated notification';
|
|
3232
|
+
return `\n // Send notification
|
|
3233
|
+
var notification = new GlideEmailOutbound();
|
|
3234
|
+
notification.setTo('${recipients}');
|
|
3235
|
+
notification.setSubject('${subject}');
|
|
3236
|
+
notification.setBody('${body}');
|
|
3237
|
+
notification.send();
|
|
3238
|
+
gs.log('Notification sent to: ' + '${recipients}', 'INFO');`;
|
|
3239
|
+
}
|
|
3240
|
+
/**
|
|
3241
|
+
* Generate approval script
|
|
3242
|
+
*/
|
|
3243
|
+
generateApprovalScript(activity) {
|
|
3244
|
+
const inputs = activity.inputs || {};
|
|
3245
|
+
const approver = inputs.approvers || inputs.approver || 'admin';
|
|
3246
|
+
return `\n // Create approval request
|
|
3247
|
+
var approval = new GlideRecord('sysapproval_approver');
|
|
3248
|
+
approval.newRecord();
|
|
3249
|
+
approval.approver = '${approver}';
|
|
3250
|
+
approval.sysapproval = current.sys_id;
|
|
3251
|
+
approval.state = 'requested';
|
|
3252
|
+
approval.comments = 'Approval required for: ' + current.getDisplayValue();
|
|
3253
|
+
approval.insert();
|
|
3254
|
+
gs.log('Approval request created for: ' + '${approver}', 'INFO');`;
|
|
3255
|
+
}
|
|
3256
|
+
/**
|
|
3257
|
+
* Generate condition script
|
|
3258
|
+
*/
|
|
3259
|
+
generateConditionScript(activity) {
|
|
3260
|
+
const condition = activity.condition || 'true';
|
|
3261
|
+
return `\n // Conditional logic
|
|
3262
|
+
if (${condition}) {
|
|
3263
|
+
gs.log('Condition met: ${condition}', 'INFO');
|
|
3264
|
+
// Add condition-specific logic here
|
|
3265
|
+
} else {
|
|
3266
|
+
gs.log('Condition not met: ${condition}', 'INFO');
|
|
3267
|
+
}`;
|
|
3268
|
+
}
|
|
3269
|
+
/**
|
|
3270
|
+
* Get Business Rule 'when' value from trigger type
|
|
3271
|
+
*/
|
|
3272
|
+
getTriggerWhen(triggerType) {
|
|
3273
|
+
switch (triggerType) {
|
|
3274
|
+
case 'record_created':
|
|
3275
|
+
return 'after';
|
|
3276
|
+
case 'record_updated':
|
|
3277
|
+
return 'after';
|
|
3278
|
+
case 'record_deleted':
|
|
3279
|
+
return 'before';
|
|
3280
|
+
case 'manual':
|
|
3281
|
+
return 'async';
|
|
3282
|
+
default:
|
|
3283
|
+
return 'after';
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3026
3286
|
async start() {
|
|
3027
3287
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
3028
3288
|
await this.server.connect(transport);
|