snow-flow 1.1.69 → 1.1.71

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.
@@ -1825,12 +1825,40 @@ class ServiceNowIntelligentMCP {
1825
1825
  performance_metrics: {},
1826
1826
  test_data_used: test_data
1827
1827
  };
1828
- // Get flow details first
1829
- const flowDetails = await this.client.get(`/api/now/table/wf_workflow/${flow_sys_id}`, {
1830
- sysparm_fields: 'name,description,active,table'
1831
- });
1832
- if (!flowDetails.result) {
1833
- throw new Error(`Flow not found: ${flow_sys_id}`);
1828
+ // Try modern Flow Designer API first
1829
+ let flowDetails;
1830
+ let flowType = 'flow_designer';
1831
+ try {
1832
+ // First try sys_hub_flow (modern Flow Designer)
1833
+ flowDetails = await this.client.get(`/api/now/table/sys_hub_flow/${flow_sys_id}`, {
1834
+ sysparm_fields: 'name,description,active,type,status,sys_id,latest_snapshot'
1835
+ });
1836
+ if (!flowDetails.result) {
1837
+ throw new Error('Not found in sys_hub_flow');
1838
+ }
1839
+ }
1840
+ catch (error) {
1841
+ // Fallback to legacy workflow if not found
1842
+ try {
1843
+ flowDetails = await this.client.get(`/api/now/table/wf_workflow/${flow_sys_id}`, {
1844
+ sysparm_fields: 'name,description,active,table'
1845
+ });
1846
+ flowType = 'legacy_workflow';
1847
+ if (!flowDetails.result) {
1848
+ throw new Error('Not found in wf_workflow');
1849
+ }
1850
+ }
1851
+ catch (fallbackError) {
1852
+ // Try searching by name if sys_id fails
1853
+ const searchResults = await this.findFlowByNameOrSysId(flow_sys_id);
1854
+ if (searchResults) {
1855
+ flowDetails = { result: searchResults };
1856
+ flowType = searchResults.sys_class_name === 'sys_hub_flow' ? 'flow_designer' : 'legacy_workflow';
1857
+ }
1858
+ else {
1859
+ throw new Error(`Flow not found with identifier: ${flow_sys_id}`);
1860
+ }
1861
+ }
1834
1862
  }
1835
1863
  executionResults.flow_info = flowDetails.result;
1836
1864
  // For flows that can be triggered programmatically
@@ -1838,11 +1866,39 @@ class ServiceNowIntelligentMCP {
1838
1866
  try {
1839
1867
  // Attempt to trigger the flow (this depends on the flow type and trigger conditions)
1840
1868
  // For now, we'll simulate testing by checking flow structure and providing recommendations
1841
- const flowActivities = await this.client.get('/api/now/table/wf_activity', {
1842
- sysparm_query: `workflow=${flow_sys_id}`,
1843
- sysparm_fields: 'name,order,active,script',
1844
- sysparm_orderby: 'order'
1845
- });
1869
+ let flowActivities;
1870
+ if (flowType === 'flow_designer') {
1871
+ // For modern flows, get activities from flow definition
1872
+ const flowData = flowDetails.result;
1873
+ if (flowData.latest_snapshot) {
1874
+ try {
1875
+ const snapshot = JSON.parse(flowData.latest_snapshot);
1876
+ flowActivities = {
1877
+ result: (snapshot.activities || snapshot.steps || []).map((activity, index) => ({
1878
+ name: activity.name || activity.label || `Activity ${index + 1}`,
1879
+ order: index * 100,
1880
+ active: true,
1881
+ type: activity.activity_type || activity.type,
1882
+ script: activity.script || ''
1883
+ }))
1884
+ };
1885
+ }
1886
+ catch (parseError) {
1887
+ flowActivities = { result: [] };
1888
+ }
1889
+ }
1890
+ else {
1891
+ flowActivities = { result: [] };
1892
+ }
1893
+ }
1894
+ else {
1895
+ // Legacy workflow activities
1896
+ flowActivities = await this.client.get('/api/now/table/wf_activity', {
1897
+ sysparm_query: `workflow=${flow_sys_id}`,
1898
+ sysparm_fields: 'name,order,active,script',
1899
+ sysparm_orderby: 'order'
1900
+ });
1901
+ }
1846
1902
  executionResults.execution_steps = flowActivities.result || [];
1847
1903
  executionResults.total_steps = executionResults.execution_steps.length;
1848
1904
  // Simulated execution analysis
@@ -1852,12 +1908,28 @@ class ServiceNowIntelligentMCP {
1852
1908
  estimated_execution_time_ms: executionResults.total_steps * 500, // Rough estimate
1853
1909
  complexity_score: this.calculateFlowComplexity(executionResults.execution_steps)
1854
1910
  };
1855
- // Provide testing recommendations
1911
+ // Provide testing recommendations based on flow type
1856
1912
  executionResults.testing_recommendations = [
1857
- 'Create test records in the target table before execution',
1858
- 'Monitor the execution context for proper variable passing',
1859
- 'Verify all conditions and approval steps work as expected',
1860
- 'Test error handling and rollback scenarios'
1913
+ `Flow Type: ${flowType === 'flow_designer' ? 'Modern Flow Designer' : 'Legacy Workflow'}`,
1914
+ `Flow Sys ID: ${flowDetails.result.sys_id}`,
1915
+ `Flow Name: ${flowDetails.result.name}`,
1916
+ '',
1917
+ '📋 Testing Steps:',
1918
+ '1. Use snow_test_flow_with_mock for mock data testing (recommended)',
1919
+ '2. Create test records in the target table before execution',
1920
+ '3. Monitor execution via sys_flow_context (Flow Designer) or wf_context (Legacy)',
1921
+ '4. Verify all conditions and approval steps work as expected',
1922
+ '5. Test error handling and rollback scenarios',
1923
+ '',
1924
+ '💡 Alternative Testing Tools:',
1925
+ '- snow_test_flow_with_mock: Test with mock users and data (always works)',
1926
+ '- snow_comprehensive_flow_test: Advanced testing with edge cases',
1927
+ '- Direct execution: Trigger via actual record creation/update',
1928
+ '',
1929
+ '🔍 Sys ID Tracking:',
1930
+ `- Flow Sys ID: ${flowDetails.result.sys_id}`,
1931
+ `- Table: ${flowType === 'flow_designer' ? 'sys_hub_flow' : 'wf_workflow'}`,
1932
+ `- URL: ${process.env.SNOW_INSTANCE ? `https://${process.env.SNOW_INSTANCE.replace(/\/$/, '')}.service-now.com` : ''}/${flowType === 'flow_designer' ? 'nav_to.do?uri=sys_hub_flow.do?sys_id=' : 'workflow_ide.do?sysparm_nostack=true&sysparm_sys_id='}${flowDetails.result.sys_id}`
1861
1933
  ];
1862
1934
  if (monitor_execution) {
1863
1935
  executionResults.monitoring_notes = 'Full monitoring requires Flow Designer integration';
@@ -1870,10 +1942,25 @@ class ServiceNowIntelligentMCP {
1870
1942
  return { content: [{ type: 'text', text: JSON.stringify(executionResults, null, 2) }] };
1871
1943
  }
1872
1944
  catch (error) {
1873
- return { content: [{
1874
- type: 'text',
1875
- text: `❌ Flow Testing Failed: ${error instanceof Error ? error.message : 'Unknown error'}`
1876
- }] };
1945
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
1946
+ let helpText = `❌ Flow Testing Failed: ${errorMessage}\n\n`;
1947
+ if (errorMessage.includes('not found')) {
1948
+ helpText += `🔍 Flow Discovery Tips:\n`;
1949
+ helpText += `- Provided identifier: "${flow_sys_id}"\n`;
1950
+ helpText += `- This could be a sys_id OR a flow name\n`;
1951
+ helpText += `- Checked tables: sys_hub_flow (modern), wf_workflow (legacy)\n\n`;
1952
+ helpText += `💡 Try these alternatives:\n`;
1953
+ helpText += `1. Use snow_find_artifact to search for the flow:\n`;
1954
+ helpText += ` snow_find_artifact({ query: "${flow_sys_id}", type: "flow" })\n\n`;
1955
+ helpText += `2. Use snow_test_flow_with_mock for testing without sys_id:\n`;
1956
+ helpText += ` snow_test_flow_with_mock({ flow_id: "${flow_sys_id}" })\n\n`;
1957
+ helpText += `3. Search by partial name:\n`;
1958
+ helpText += ` snow_discover_existing_flows({ flow_purpose: "${flow_sys_id}" })\n\n`;
1959
+ helpText += `4. Get exact sys_id from ServiceNow UI:\n`;
1960
+ helpText += ` - Flow Designer → Flows → Copy sys_id from list\n`;
1961
+ helpText += ` - Or right-click flow → Copy sys_id\n`;
1962
+ }
1963
+ return { content: [{ type: 'text', text: helpText }] };
1877
1964
  }
1878
1965
  }
1879
1966
  async batchDeploymentValidator(args) {
@@ -2437,10 +2524,13 @@ class ServiceNowIntelligentMCP {
2437
2524
  orchestration_id: `orchestration_${Date.now()}`,
2438
2525
  started_at: new Date().toISOString(),
2439
2526
  status: 'initializing',
2527
+ mode: auto_deploy ? '🚀 DEPLOYMENT MODE (WILL CREATE REAL ARTIFACTS)' : '📋 PLANNING MODE (ANALYSIS ONLY)',
2528
+ warning: auto_deploy ? '⚠️ WARNING: This will create REAL artifacts in ServiceNow!' : '✅ SAFE: This is planning only, no artifacts will be created',
2440
2529
  agents_spawned: [],
2441
2530
  shared_memory_enabled: shared_memory,
2442
2531
  progress_monitor: {},
2443
- execution_plan: {}
2532
+ execution_plan: {},
2533
+ actual_deployments: []
2444
2534
  };
2445
2535
  // Step 1: Analyze requirements
2446
2536
  if (smart_discovery) {
@@ -2512,13 +2602,98 @@ class ServiceNowIntelligentMCP {
2512
2602
  completion_notifications: true
2513
2603
  };
2514
2604
  }
2515
- orchestration.status = 'ready_for_execution';
2516
- orchestration.next_steps = [
2517
- 'Execute snow_resilient_deployment to begin artifact development',
2518
- 'Monitor progress using progress_monitor configuration',
2519
- 'Use snow_comprehensive_flow_test for validation phase',
2520
- 'Deploy using automatic deployment if auto_deploy is enabled'
2521
- ];
2605
+ // Step 6: Execute actual deployment if auto_deploy is enabled
2606
+ if (auto_deploy) {
2607
+ orchestration.status = 'executing_deployment';
2608
+ // Attempt to create real artifacts based on the objective
2609
+ try {
2610
+ const artifactAnalysis = await this.analyzeArtifactRequirements(objective);
2611
+ for (const artifact of artifactAnalysis.recommended_artifacts) {
2612
+ try {
2613
+ let deploymentResult;
2614
+ if (artifact.type === 'flow') {
2615
+ // Use flow composer to create real flow
2616
+ deploymentResult = await this.client.post('/api/now/table/sys_hub_flow', {
2617
+ name: artifact.name,
2618
+ description: artifact.description,
2619
+ active: true,
2620
+ type: 'flow'
2621
+ });
2622
+ }
2623
+ else if (artifact.type === 'widget') {
2624
+ // Create real widget
2625
+ deploymentResult = await this.client.post('/api/now/table/sp_widget', {
2626
+ name: artifact.name,
2627
+ title: artifact.name,
2628
+ description: artifact.description,
2629
+ template: artifact.template || '<div>{{data.message || "Widget created"}}</div>',
2630
+ css: artifact.css || '',
2631
+ client_script: artifact.client_script || '',
2632
+ server_script: artifact.server_script || '(function() { data.message = "Successfully deployed!"; })()',
2633
+ public: true,
2634
+ has_preview: true
2635
+ });
2636
+ }
2637
+ if (deploymentResult?.result) {
2638
+ orchestration.actual_deployments.push({
2639
+ type: artifact.type,
2640
+ name: artifact.name,
2641
+ sys_id: deploymentResult.result.sys_id,
2642
+ status: 'deployed',
2643
+ url: `https://${process.env.SNOW_INSTANCE ? process.env.SNOW_INSTANCE.replace(/\/$/, '') : 'instance'}.service-now.com/nav_to.do?uri=${artifact.type === 'flow' ? 'sys_hub_flow' : 'sp_widget'}.do?sys_id=${deploymentResult.result.sys_id}`
2644
+ });
2645
+ }
2646
+ }
2647
+ catch (deployError) {
2648
+ orchestration.actual_deployments.push({
2649
+ type: artifact.type,
2650
+ name: artifact.name,
2651
+ status: 'failed',
2652
+ error: deployError instanceof Error ? deployError.message : String(deployError)
2653
+ });
2654
+ }
2655
+ }
2656
+ orchestration.status = 'deployment_complete';
2657
+ orchestration.completed_at = new Date().toISOString();
2658
+ }
2659
+ catch (error) {
2660
+ orchestration.status = 'deployment_failed';
2661
+ orchestration.deployment_error = error instanceof Error ? error.message : String(error);
2662
+ }
2663
+ }
2664
+ else {
2665
+ orchestration.status = 'planning_complete';
2666
+ orchestration.completed_at = new Date().toISOString();
2667
+ }
2668
+ // Set appropriate next steps based on mode
2669
+ if (auto_deploy) {
2670
+ if (orchestration.actual_deployments.length > 0) {
2671
+ orchestration.next_steps = [
2672
+ '✅ DEPLOYMENT COMPLETE: Real artifacts have been created in ServiceNow',
2673
+ `📊 Created ${orchestration.actual_deployments.filter((d) => d.status === 'deployed').length} artifacts successfully`,
2674
+ 'Use snow_test_flow_execution or snow_widget_test to validate deployments',
2675
+ 'Check ServiceNow instance to verify artifacts are working correctly'
2676
+ ];
2677
+ }
2678
+ else {
2679
+ orchestration.next_steps = [
2680
+ '❌ DEPLOYMENT FAILED: No artifacts were created',
2681
+ 'Check deployment errors in actual_deployments array',
2682
+ 'Verify ServiceNow permissions and authentication',
2683
+ 'Consider running in planning mode first (auto_deploy: false)'
2684
+ ];
2685
+ }
2686
+ }
2687
+ else {
2688
+ orchestration.next_steps = [
2689
+ '📋 PLANNING COMPLETE: This was analysis only - no artifacts created',
2690
+ '🚀 To deploy: Re-run with auto_deploy: true',
2691
+ 'Execute specific MCP tools manually:',
2692
+ ' - snow_create_flow for flow creation',
2693
+ ' - snow_deploy_widget for widget deployment',
2694
+ ' - snow_resilient_deployment for batch deployment'
2695
+ ];
2696
+ }
2522
2697
  return { content: [{ type: 'text', text: JSON.stringify(orchestration, null, 2) }] };
2523
2698
  }
2524
2699
  catch (error) {
@@ -2664,10 +2839,40 @@ class ServiceNowIntelligentMCP {
2664
2839
  overall_status: 'running',
2665
2840
  recommendations: []
2666
2841
  };
2667
- // Get flow details
2668
- const flowDetails = await this.client.get(`/api/now/table/wf_workflow/${flow_sys_id}`);
2669
- if (!flowDetails.result) {
2670
- throw new Error(`Flow not found: ${flow_sys_id}`);
2842
+ // Get flow details using improved discovery
2843
+ let flowDetails;
2844
+ let flowType = 'flow_designer';
2845
+ try {
2846
+ // First try sys_hub_flow (modern Flow Designer)
2847
+ flowDetails = await this.client.get(`/api/now/table/sys_hub_flow/${flow_sys_id}`, {
2848
+ sysparm_fields: 'name,description,active,type,status,sys_id,latest_snapshot'
2849
+ });
2850
+ if (!flowDetails.result) {
2851
+ throw new Error('Not found in sys_hub_flow');
2852
+ }
2853
+ }
2854
+ catch (error) {
2855
+ // Fallback to legacy workflow if not found
2856
+ try {
2857
+ flowDetails = await this.client.get(`/api/now/table/wf_workflow/${flow_sys_id}`, {
2858
+ sysparm_fields: 'name,description,active,table'
2859
+ });
2860
+ flowType = 'legacy_workflow';
2861
+ if (!flowDetails.result) {
2862
+ throw new Error('Not found in wf_workflow');
2863
+ }
2864
+ }
2865
+ catch (fallbackError) {
2866
+ // Try searching by name if sys_id fails
2867
+ const searchResults = await this.findFlowByNameOrSysId(flow_sys_id);
2868
+ if (searchResults) {
2869
+ flowDetails = { result: searchResults };
2870
+ flowType = searchResults.sys_class_name === 'sys_hub_flow' ? 'flow_designer' : 'legacy_workflow';
2871
+ }
2872
+ else {
2873
+ throw new Error(`Flow not found with identifier: ${flow_sys_id}`);
2874
+ }
2875
+ }
2671
2876
  }
2672
2877
  testResults.flow_info = flowDetails.result;
2673
2878
  // Generate test data automatically
@@ -3132,6 +3337,53 @@ try {
3132
3337
  details: 'Custom scenario executed successfully'
3133
3338
  };
3134
3339
  }
3340
+ async analyzeArtifactRequirements(objective) {
3341
+ const artifactAnalysis = {
3342
+ objective,
3343
+ recommended_artifacts: []
3344
+ };
3345
+ const lowerObjective = objective.toLowerCase();
3346
+ // Simple keyword-based analysis for artifact type detection
3347
+ if (lowerObjective.includes('flow') || lowerObjective.includes('workflow') || lowerObjective.includes('automation')) {
3348
+ artifactAnalysis.recommended_artifacts.push({
3349
+ type: 'flow',
3350
+ name: `Flow for ${objective.substring(0, 50)}`,
3351
+ description: `Automated flow created for: ${objective}`,
3352
+ priority: 'high'
3353
+ });
3354
+ }
3355
+ if (lowerObjective.includes('widget') || lowerObjective.includes('dashboard') || lowerObjective.includes('display')) {
3356
+ artifactAnalysis.recommended_artifacts.push({
3357
+ type: 'widget',
3358
+ name: `Widget for ${objective.substring(0, 50)}`,
3359
+ description: `Service Portal widget for: ${objective}`,
3360
+ template: '<div class="panel panel-default"><div class="panel-body">{{data.message || "Widget deployed successfully"}}<br><small>Created for: ' + objective + '</small></div></div>',
3361
+ css: '.panel { margin: 10px; }',
3362
+ client_script: 'function() { console.log("Widget loaded"); }',
3363
+ server_script: '(function() { data.message = "Successfully deployed for: ' + objective.replace(/"/g, '\\"') + '"; })()',
3364
+ priority: 'medium'
3365
+ });
3366
+ }
3367
+ if (lowerObjective.includes('script') || lowerObjective.includes('function') || lowerObjective.includes('utility')) {
3368
+ artifactAnalysis.recommended_artifacts.push({
3369
+ type: 'script_include',
3370
+ name: `Script for ${objective.substring(0, 50)}`,
3371
+ description: `Script include for: ${objective}`,
3372
+ script: `// Script created for: ${objective}\nvar ScriptUtility = Class.create();\nScriptUtility.prototype = {\n initialize: function() {},\n execute: function() {\n gs.info('Script executed for: ${objective}');\n return true;\n },\n type: 'ScriptUtility'\n};\n`,
3373
+ priority: 'low'
3374
+ });
3375
+ }
3376
+ // If no specific artifacts detected, create a default flow
3377
+ if (artifactAnalysis.recommended_artifacts.length === 0) {
3378
+ artifactAnalysis.recommended_artifacts.push({
3379
+ type: 'flow',
3380
+ name: `General Flow for ${objective.substring(0, 40)}`,
3381
+ description: `General purpose flow for: ${objective}`,
3382
+ priority: 'medium'
3383
+ });
3384
+ }
3385
+ return artifactAnalysis;
3386
+ }
3135
3387
  generateTestRecommendations(testResults) {
3136
3388
  const recommendations = [];
3137
3389
  if (testResults.test_summary.success_rate < 90) {
@@ -3141,6 +3393,62 @@ try {
3141
3393
  recommendations.push('📊 Set up performance baselines for future comparisons');
3142
3394
  return recommendations;
3143
3395
  }
3396
+ async findFlowByNameOrSysId(identifier) {
3397
+ try {
3398
+ // First try as sys_id in sys_hub_flow
3399
+ let result = await this.client.get(`/api/now/table/sys_hub_flow/${identifier}`);
3400
+ if (result.result) {
3401
+ result.result.sys_class_name = 'sys_hub_flow';
3402
+ return result.result;
3403
+ }
3404
+ }
3405
+ catch (error) {
3406
+ // Not a sys_id in sys_hub_flow
3407
+ }
3408
+ try {
3409
+ // Try as sys_id in wf_workflow
3410
+ let result = await this.client.get(`/api/now/table/wf_workflow/${identifier}`);
3411
+ if (result.result) {
3412
+ result.result.sys_class_name = 'wf_workflow';
3413
+ return result.result;
3414
+ }
3415
+ }
3416
+ catch (error) {
3417
+ // Not a sys_id in wf_workflow
3418
+ }
3419
+ // Search by name in both tables
3420
+ try {
3421
+ // Search in sys_hub_flow
3422
+ const modernFlows = await this.client.get('/api/now/table/sys_hub_flow', {
3423
+ sysparm_query: `name=${identifier}^ORnameSTARTSWITH${identifier}`,
3424
+ sysparm_limit: 1,
3425
+ sysparm_fields: 'name,description,active,type,status,sys_id,latest_snapshot'
3426
+ });
3427
+ if (modernFlows.result && modernFlows.result.length > 0) {
3428
+ modernFlows.result[0].sys_class_name = 'sys_hub_flow';
3429
+ return modernFlows.result[0];
3430
+ }
3431
+ }
3432
+ catch (error) {
3433
+ // Continue to legacy search
3434
+ }
3435
+ try {
3436
+ // Search in wf_workflow
3437
+ const legacyFlows = await this.client.get('/api/now/table/wf_workflow', {
3438
+ sysparm_query: `name=${identifier}^ORnameSTARTSWITH${identifier}`,
3439
+ sysparm_limit: 1,
3440
+ sysparm_fields: 'name,description,active,table,sys_id'
3441
+ });
3442
+ if (legacyFlows.result && legacyFlows.result.length > 0) {
3443
+ legacyFlows.result[0].sys_class_name = 'wf_workflow';
3444
+ return legacyFlows.result[0];
3445
+ }
3446
+ }
3447
+ catch (error) {
3448
+ // No results found
3449
+ }
3450
+ return null;
3451
+ }
3144
3452
  async start() {
3145
3453
  const transport = new stdio_js_1.StdioServerTransport();
3146
3454
  await this.server.connect(transport);