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.
- package/dist/cli.js +13 -2
- package/dist/cli.js.map +1 -1
- package/dist/mcp/servicenow-flow-composer-mcp.js +3 -1
- package/dist/mcp/servicenow-flow-composer-mcp.js.map +1 -1
- package/dist/mcp/servicenow-intelligent-mcp.js +340 -32
- package/dist/mcp/servicenow-intelligent-mcp.js.map +1 -1
- package/dist/version.d.ts +11 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +54 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
|
@@ -1825,12 +1825,40 @@ class ServiceNowIntelligentMCP {
|
|
|
1825
1825
|
performance_metrics: {},
|
|
1826
1826
|
test_data_used: test_data
|
|
1827
1827
|
};
|
|
1828
|
-
//
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
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
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
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
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
'
|
|
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
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
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
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
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
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
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);
|