snow-flow 3.0.14 → 3.0.15
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.
|
@@ -53,7 +53,7 @@ class ServiceNowDeploymentMCP {
|
|
|
53
53
|
inputSchema: {
|
|
54
54
|
type: 'object',
|
|
55
55
|
properties: {
|
|
56
|
-
type: { type: 'string', enum: ['widget', '
|
|
56
|
+
type: { type: 'string', enum: ['widget', 'application'] }, // removed 'workflow' - deprecated
|
|
57
57
|
artifact: { type: 'object', description: 'The artifact to validate' },
|
|
58
58
|
},
|
|
59
59
|
required: ['type', 'artifact'],
|
|
@@ -83,11 +83,11 @@ class ServiceNowDeploymentMCP {
|
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
name: 'snow_export_artifact',
|
|
86
|
-
description: 'Exports ServiceNow artifacts (widgets,
|
|
86
|
+
description: 'Exports ServiceNow artifacts (widgets, applications) to JSON/XML format for backup, version control, or migration purposes.', // removed workflows
|
|
87
87
|
inputSchema: {
|
|
88
88
|
type: 'object',
|
|
89
89
|
properties: {
|
|
90
|
-
type: { type: 'string', enum: ['widget', '
|
|
90
|
+
type: { type: 'string', enum: ['widget', 'application'] }, // removed 'workflow' - deprecated
|
|
91
91
|
sys_id: { type: 'string', description: 'Sys ID of the artifact' },
|
|
92
92
|
format: { type: 'string', enum: ['json', 'xml', 'update_set'], default: 'json' },
|
|
93
93
|
},
|
|
@@ -100,7 +100,7 @@ class ServiceNowDeploymentMCP {
|
|
|
100
100
|
inputSchema: {
|
|
101
101
|
type: 'object',
|
|
102
102
|
properties: {
|
|
103
|
-
type: { type: 'string', enum: ['widget', '
|
|
103
|
+
type: { type: 'string', enum: ['widget', 'application'] }, // removed 'workflow' - deprecated
|
|
104
104
|
file_path: { type: 'string', description: 'Path to the artifact file' },
|
|
105
105
|
format: { type: 'string', enum: ['json', 'xml', 'update_set'], default: 'json' },
|
|
106
106
|
},
|
|
@@ -115,7 +115,7 @@ class ServiceNowDeploymentMCP {
|
|
|
115
115
|
properties: {
|
|
116
116
|
source_instance: { type: 'string', description: 'Source instance URL' },
|
|
117
117
|
target_instance: { type: 'string', description: 'Target instance URL' },
|
|
118
|
-
type: { type: 'string', enum: ['widget', '
|
|
118
|
+
type: { type: 'string', enum: ['widget', 'application'] }, // removed 'workflow' - deprecated
|
|
119
119
|
sys_id: { type: 'string', description: 'Sys ID of the artifact to clone' },
|
|
120
120
|
},
|
|
121
121
|
required: ['source_instance', 'target_instance', 'type', 'sys_id'],
|
|
@@ -461,11 +461,11 @@ class ServiceNowDeploymentMCP {
|
|
|
461
461
|
*/
|
|
462
462
|
getTableForType(type) {
|
|
463
463
|
const tableMap = {
|
|
464
|
-
'flow': 'sys_hub_flow',
|
|
464
|
+
// 'flow': 'sys_hub_flow', // REMOVED - flows deprecated
|
|
465
465
|
'widget': 'sp_widget',
|
|
466
466
|
'script': 'sys_script_include',
|
|
467
467
|
'business_rule': 'sys_script',
|
|
468
|
-
'workflow': 'wf_workflow',
|
|
468
|
+
// 'workflow': 'wf_workflow', // REMOVED - workflows deprecated
|
|
469
469
|
'application': 'sys_app',
|
|
470
470
|
'ui_action': 'sys_ui_action',
|
|
471
471
|
'ui_page': 'sys_ui_page',
|
|
@@ -1675,435 +1675,474 @@ ${args.widgets && args.widgets.length > 0 ? args.widgets.map((w, i) => `
|
|
|
1675
1675
|
`;
|
|
1676
1676
|
return css;
|
|
1677
1677
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
validationText.includes('Auto-converted "actions" to "activities"') ||
|
|
1740
|
-
validationText.includes('Smart Auto-Corrections Applied')) {
|
|
1741
|
-
// Re-parse the corrected definition from the validation process
|
|
1742
|
-
const tempDef = typeof args.flow_definition === 'string' ? JSON.parse(args.flow_definition) : args.flow_definition;
|
|
1743
|
-
if (tempDef.steps && !tempDef.activities) {
|
|
1744
|
-
tempDef.activities = tempDef.steps;
|
|
1745
|
-
delete tempDef.steps;
|
|
1746
|
-
}
|
|
1747
|
-
else if (tempDef.actions && !tempDef.activities) {
|
|
1748
|
-
tempDef.activities = tempDef.actions;
|
|
1749
|
-
delete tempDef.actions;
|
|
1750
|
-
}
|
|
1751
|
-
validatedDefinition = JSON.stringify(tempDef);
|
|
1752
|
-
this.logger.info('Using auto-corrected flow definition for deployment');
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
// Ensure Update Set is active
|
|
1756
|
-
const { updateSetId, updateSetName } = await this.ensureUpdateSet('Flow', args.name);
|
|
1757
|
-
// Check if this is a master flow with linked artifacts
|
|
1758
|
-
const isComposedFlow = args.composed_flow || args.linked_artifacts;
|
|
1759
|
-
const linkedArtifacts = args.linked_artifacts || [];
|
|
1760
|
-
// Deploy linked artifacts first if this is a composed flow
|
|
1761
|
-
const deployedArtifacts = [];
|
|
1762
|
-
if (isComposedFlow && linkedArtifacts.length > 0) {
|
|
1763
|
-
this.logger.info('Deploying linked artifacts for composed flow', { count: linkedArtifacts.length });
|
|
1764
|
-
for (const artifact of linkedArtifacts) {
|
|
1765
|
-
try {
|
|
1766
|
-
const deployResult = await this.deployLinkedArtifact(artifact);
|
|
1767
|
-
deployedArtifacts.push(deployResult);
|
|
1768
|
-
}
|
|
1769
|
-
catch (error) {
|
|
1770
|
-
this.logger.error('Failed to deploy linked artifact', { artifact, error });
|
|
1771
|
-
throw new Error(`Failed to deploy linked artifact ${artifact.name}: ${error}`);
|
|
1772
|
-
}
|
|
1678
|
+
// DEPRECATED: Flow deployment is no longer supported - flows, workflows, and subflows have been removed
|
|
1679
|
+
/* private async deployFlow(args: any) {
|
|
1680
|
+
try {
|
|
1681
|
+
// Enhanced authentication check with token refresh for deployment
|
|
1682
|
+
const authResult = await this.deploymentAuthManager.ensureDeploymentAuth();
|
|
1683
|
+
if (!authResult.isValid) {
|
|
1684
|
+
this.logger.error('Deployment authentication failed:', authResult.error);
|
|
1685
|
+
|
|
1686
|
+
// If auth failed, try to refresh token
|
|
1687
|
+
const refreshResult = await this.deploymentAuthManager.forceTokenRefresh();
|
|
1688
|
+
if (!refreshResult.success) {
|
|
1689
|
+
return {
|
|
1690
|
+
content: [
|
|
1691
|
+
{
|
|
1692
|
+
type: 'text',
|
|
1693
|
+
text: `❌ Deployment authentication failed.\n\nError: ${authResult.error || 'Unable to authenticate'}\n\nRecommendations:\n${(authResult.recommendations || ['Run: snow-flow auth login']).map(r => `• ${r}`).join('\n')}\n\nNote: Deployment requires valid OAuth tokens with write permissions.`,
|
|
1694
|
+
},
|
|
1695
|
+
],
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
// Warn if token may lack write permissions
|
|
1701
|
+
if (!authResult.hasWriteScope) {
|
|
1702
|
+
this.logger.warn('⚠️ Token may lack write permissions, deployment might fail with 403');
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
// Ensure we have a flow definition
|
|
1706
|
+
if (!args.flow_definition) {
|
|
1707
|
+
return {
|
|
1708
|
+
content: [
|
|
1709
|
+
{
|
|
1710
|
+
type: 'text',
|
|
1711
|
+
text: '❌ Flow deployment failed: No flow_definition provided.\n\n💡 You need to provide a flow_definition with activities.\n\nExample:\n```json\n{\n "name": "approval_flow",\n "flow_definition": {\n "activities": [\n {\n "id": "activity_1",\n "name": "Check Condition",\n "type": "condition"\n }\n ]\n }\n}\n```\n\nOr use snow_create_flow with natural language for easier flow creation.',
|
|
1712
|
+
},
|
|
1713
|
+
],
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
const flowType = args.flow_type || 'flow';
|
|
1718
|
+
this.logger.info(`Deploying ${flowType} to ServiceNow`, { name: args.name, type: flowType });
|
|
1719
|
+
|
|
1720
|
+
// Validate flow definition first if requested
|
|
1721
|
+
let validatedDefinition = args.flow_definition;
|
|
1722
|
+
if (args.validate_before_deploy !== false) {
|
|
1723
|
+
const validationResult = await this.validateFlowDefinition({
|
|
1724
|
+
definition: args.flow_definition,
|
|
1725
|
+
flow_type: flowType,
|
|
1726
|
+
show_preview: false,
|
|
1727
|
+
test_mode: false,
|
|
1728
|
+
check_dependencies: true
|
|
1729
|
+
});
|
|
1730
|
+
|
|
1731
|
+
// Check if validation failed
|
|
1732
|
+
const validationText = validationResult.content?.[0]?.text || '';
|
|
1733
|
+
if (validationText.includes('❌') || validationText.includes('ERROR')) {
|
|
1734
|
+
return {
|
|
1735
|
+
content: [
|
|
1736
|
+
{
|
|
1737
|
+
type: 'text',
|
|
1738
|
+
text: `❌ Flow validation failed. Please fix the following issues:\n\n${validationText}\n\nUse snow_validate_flow_definition to preview and test your flow before deployment.`
|
|
1773
1739
|
}
|
|
1774
|
-
|
|
1775
|
-
// Parse flow definition to inject deployed artifact references
|
|
1776
|
-
// Use the validated and corrected definition
|
|
1777
|
-
let flowDefinition = validatedDefinition;
|
|
1778
|
-
if (typeof flowDefinition === 'string') {
|
|
1779
|
-
flowDefinition = JSON.parse(flowDefinition);
|
|
1780
|
-
}
|
|
1781
|
-
// Update flow activities with deployed artifact sys_ids
|
|
1782
|
-
if (flowDefinition.activities && deployedArtifacts.length > 0) {
|
|
1783
|
-
flowDefinition.activities = flowDefinition.activities.map((activity) => {
|
|
1784
|
-
if (activity.artifact_reference) {
|
|
1785
|
-
const deployed = deployedArtifacts.find(d => d.originalId === activity.artifact_reference.sys_id ||
|
|
1786
|
-
d.name === activity.artifact_reference.name);
|
|
1787
|
-
if (deployed) {
|
|
1788
|
-
activity.artifact_sys_id = deployed.sys_id;
|
|
1789
|
-
activity.artifact_api_name = deployed.api_name;
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
return activity;
|
|
1793
|
-
});
|
|
1794
|
-
}
|
|
1795
|
-
// Create flow data based on flow type
|
|
1796
|
-
const flowData = {
|
|
1797
|
-
name: args.name,
|
|
1798
|
-
description: args.description,
|
|
1799
|
-
active: args.active !== false,
|
|
1800
|
-
flow_definition: JSON.stringify(flowDefinition),
|
|
1801
|
-
category: args.category || 'automation',
|
|
1802
|
-
// Additional fields for composed flows
|
|
1803
|
-
is_composed: isComposedFlow,
|
|
1804
|
-
linked_artifact_count: linkedArtifacts.length,
|
|
1805
|
-
artifact_references: deployedArtifacts.map(a => a.sys_id).join(',')
|
|
1740
|
+
]
|
|
1806
1741
|
};
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// CRITICAL: Use the corrected definition from validation
|
|
1745
|
+
// The validateFlowDefinition method may have auto-corrected "steps" or "actions" to "activities"
|
|
1746
|
+
if (validationText.includes('Auto-converted "steps" to "activities"') ||
|
|
1747
|
+
validationText.includes('Auto-converted "actions" to "activities"') ||
|
|
1748
|
+
validationText.includes('Smart Auto-Corrections Applied')) {
|
|
1749
|
+
// Re-parse the corrected definition from the validation process
|
|
1750
|
+
const tempDef = typeof args.flow_definition === 'string' ? JSON.parse(args.flow_definition) : args.flow_definition;
|
|
1751
|
+
if (tempDef.steps && !tempDef.activities) {
|
|
1752
|
+
tempDef.activities = tempDef.steps;
|
|
1753
|
+
delete tempDef.steps;
|
|
1754
|
+
} else if (tempDef.actions && !tempDef.activities) {
|
|
1755
|
+
tempDef.activities = tempDef.actions;
|
|
1756
|
+
delete tempDef.actions;
|
|
1757
|
+
}
|
|
1758
|
+
validatedDefinition = JSON.stringify(tempDef);
|
|
1759
|
+
this.logger.info('Using auto-corrected flow definition for deployment');
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
// Ensure Update Set is active
|
|
1764
|
+
const { updateSetId, updateSetName } = await this.ensureUpdateSet('Flow', args.name);
|
|
1765
|
+
|
|
1766
|
+
// Check if this is a master flow with linked artifacts
|
|
1767
|
+
const isComposedFlow = args.composed_flow || args.linked_artifacts;
|
|
1768
|
+
const linkedArtifacts = args.linked_artifacts || [];
|
|
1769
|
+
|
|
1770
|
+
// Deploy linked artifacts first if this is a composed flow
|
|
1771
|
+
const deployedArtifacts: any[] = [];
|
|
1772
|
+
if (isComposedFlow && linkedArtifacts.length > 0) {
|
|
1773
|
+
this.logger.info('Deploying linked artifacts for composed flow', { count: linkedArtifacts.length });
|
|
1774
|
+
|
|
1775
|
+
for (const artifact of linkedArtifacts) {
|
|
1833
1776
|
try {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
name: flowData.name || `flow_${Date.now()}`,
|
|
1840
|
-
description: flowData.description || 'Created by Snow-Flow',
|
|
1841
|
-
table: flowData.table || 'incident',
|
|
1842
|
-
active: flowData.active !== false,
|
|
1843
|
-
condition: flowData.condition || '',
|
|
1844
|
-
script: flowData.script || '// Flow logic here',
|
|
1845
|
-
order: flowData.order || 100
|
|
1846
|
-
});
|
|
1847
|
-
break;
|
|
1848
|
-
case 'subflow':
|
|
1849
|
-
// Create subflow as a workflow activity
|
|
1850
|
-
result = await this.client.createRecord('wf_workflow', {
|
|
1851
|
-
name: flowData.name || `subflow_${Date.now()}`,
|
|
1852
|
-
description: `${flowData.description || 'Subflow created by Snow-Flow'} [SUBFLOW]`,
|
|
1853
|
-
table: flowData.table || 'incident',
|
|
1854
|
-
active: flowData.active !== false,
|
|
1855
|
-
condition: flowData.condition || '',
|
|
1856
|
-
script: flowData.script || '// Subflow logic here',
|
|
1857
|
-
order: flowData.order || 200
|
|
1858
|
-
});
|
|
1859
|
-
break;
|
|
1860
|
-
case 'action':
|
|
1861
|
-
// Create workflow activity/action
|
|
1862
|
-
if (!flowData.workflow_id) {
|
|
1863
|
-
throw new Error('workflow_id is required for flow actions');
|
|
1864
|
-
}
|
|
1865
|
-
result = await this.client.createRecord('wf_activity', {
|
|
1866
|
-
workflow: flowData.workflow_id,
|
|
1867
|
-
name: flowData.name || `action_${Date.now()}`,
|
|
1868
|
-
script: flowData.script || '// Action script here',
|
|
1869
|
-
condition: flowData.condition || '',
|
|
1870
|
-
order: flowData.order || 100,
|
|
1871
|
-
active: flowData.active !== false
|
|
1872
|
-
});
|
|
1873
|
-
break;
|
|
1874
|
-
default:
|
|
1875
|
-
throw new Error(`Unknown flow type: ${flowType}. Supported types: flow, subflow, action`);
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
catch (flowError) {
|
|
1879
|
-
this.logger.warn('Flow Designer deployment failed, attempting Business Rule fallback', {
|
|
1880
|
-
error: flowError,
|
|
1881
|
-
flowName: args.name
|
|
1882
|
-
});
|
|
1883
|
-
// Try to create equivalent Business Rule instead
|
|
1884
|
-
try {
|
|
1885
|
-
fallbackBusinessRule = await this.createBusinessRuleFallback(args, flowDefinition);
|
|
1886
|
-
result = {
|
|
1887
|
-
success: true,
|
|
1888
|
-
data: fallbackBusinessRule,
|
|
1889
|
-
fallback_used: true,
|
|
1890
|
-
original_error: flowError instanceof Error ? flowError.message : String(flowError)
|
|
1891
|
-
};
|
|
1892
|
-
usedFallback = true;
|
|
1893
|
-
this.logger.info('Successfully created Business Rule fallback', {
|
|
1894
|
-
businessRuleId: fallbackBusinessRule.sys_id,
|
|
1895
|
-
originalFlowName: args.name
|
|
1896
|
-
});
|
|
1897
|
-
}
|
|
1898
|
-
catch (fallbackError) {
|
|
1899
|
-
this.logger.error('Both Flow Designer and Business Rule fallback failed', {
|
|
1900
|
-
flowError,
|
|
1901
|
-
fallbackError
|
|
1902
|
-
});
|
|
1903
|
-
throw new Error(`🚨 Flow deployment failed and fallback unsuccessful:
|
|
1904
|
-
|
|
1905
|
-
📍 **Errors:**
|
|
1906
|
-
- Flow Designer Error: ${flowError instanceof Error ? flowError.message : String(flowError)}
|
|
1907
|
-
- Business Rule Fallback Error: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}
|
|
1908
|
-
|
|
1909
|
-
🔧 **Update Set Troubleshooting:**
|
|
1910
|
-
1. Check current Update Set: snow_smart_update_set with action="track"
|
|
1911
|
-
2. Verify Update Set is active for tracking
|
|
1912
|
-
3. Use mock testing: snow_test_flow_with_mock instead
|
|
1913
|
-
4. Check flow exists: snow_get_by_sysid
|
|
1914
|
-
|
|
1915
|
-
💡 **Alternative Solutions:**
|
|
1916
|
-
- Use snow_test_flow_with_mock for safe testing
|
|
1917
|
-
- Verify flow creation with snow_get_by_sysid
|
|
1918
|
-
- Check Update Set contains the flow artifact
|
|
1919
|
-
- Create Business Rule manually if needed
|
|
1920
|
-
|
|
1921
|
-
📚 Please check your flow definition JSON format or use manual deployment.`);
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
|
-
const credentials = await this.oauth.loadCredentials();
|
|
1925
|
-
const flowUrl = result.success && result.data
|
|
1926
|
-
? (usedFallback
|
|
1927
|
-
? `https://${credentials?.instance}/sys_script.do?sys_id=${result.data.sys_id}`
|
|
1928
|
-
: `https://${credentials?.instance}/nav_to.do?uri=sys_hub_flow.do?sys_id=${result.data.sys_id}`)
|
|
1929
|
-
: `https://${credentials?.instance}/flow-designer.do`;
|
|
1930
|
-
const artifactSummary = deployedArtifacts.length > 0
|
|
1931
|
-
? `\n🔗 **Linked Artifacts Deployed:**\n${deployedArtifacts.map((a, i) => `${i + 1}. ${a.type}: ${a.name} (${a.sys_id})`).join('\n')}\n`
|
|
1932
|
-
: '';
|
|
1933
|
-
const activitySummary = flowDefinition.activities
|
|
1934
|
-
? `\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`
|
|
1935
|
-
: '';
|
|
1936
|
-
const successMessage = usedFallback
|
|
1937
|
-
? `🔄 **INTELLIGENT FALLBACK SUCCESSFUL!**
|
|
1938
|
-
|
|
1939
|
-
⚠️ Flow Designer deployment failed, but Snow-Flow automatically created a Business Rule that achieves the same result!
|
|
1940
|
-
|
|
1941
|
-
🛠️ **Business Rule Details:**
|
|
1942
|
-
- Name: ${args.name}
|
|
1943
|
-
- Type: 🔧 Business Rule (Fallback from Flow Designer)
|
|
1944
|
-
- Table: ${args.table || 'sys_user'}
|
|
1945
|
-
- When: ${this.getTriggerWhen(args.trigger_type)}
|
|
1946
|
-
- Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
1947
|
-
- Original Error: ${result.original_error}
|
|
1948
|
-
|
|
1949
|
-
✨ **Why This Works Better:**
|
|
1950
|
-
- ✅ More reliable than Flow Designer for simple automations
|
|
1951
|
-
- ✅ Faster execution (server-side JavaScript)
|
|
1952
|
-
- ✅ Better error handling and debugging
|
|
1953
|
-
- ✅ Direct database access capabilities`
|
|
1954
|
-
: `✅ Flow Designer flow deployed successfully!
|
|
1955
|
-
|
|
1956
|
-
🔄 **${flowType.charAt(0).toUpperCase() + flowType.slice(1)} Details:**
|
|
1957
|
-
- Name: ${args.name}
|
|
1958
|
-
- Flow Type: ${flowType === 'flow' ? '📋 Flow' : flowType === 'subflow' ? '🔄 Subflow' : '⚡ Action'}
|
|
1959
|
-
- Composed: ${isComposedFlow ? '🧠 Yes - Intelligent Composed Flow' : '❌ No - Standard'}
|
|
1960
|
-
${flowType === 'flow' ? `- Trigger Type: ${args.trigger_type}
|
|
1961
|
-
- Table: ${args.table || 'N/A'}` : ''}
|
|
1962
|
-
${flowType !== 'flow' ? `- Inputs: ${flowDefinition.inputs?.length || 0}
|
|
1963
|
-
- Outputs: ${flowDefinition.outputs?.length || 0}` : ''}
|
|
1964
|
-
- Category: ${args.category || 'automation'}
|
|
1965
|
-
- Active: ${args.active !== false ? 'Yes' : 'No'}`;
|
|
1966
|
-
const continuationMessage = usedFallback
|
|
1967
|
-
? `
|
|
1968
|
-
📦 **Update Set:**
|
|
1969
|
-
- Name: ${updateSetName}
|
|
1970
|
-
- ID: ${updateSetId}
|
|
1971
|
-
|
|
1972
|
-
🔗 **Direct Links:**
|
|
1973
|
-
- Business Rule: ${flowUrl}
|
|
1974
|
-
- Business Rules List: https://${credentials?.instance}/sys_script_list.do
|
|
1975
|
-
|
|
1976
|
-
📝 **Business Rule Components Created:**
|
|
1977
|
-
1. ✅ Trigger configured (${this.getTriggerWhen(args.trigger_type)})
|
|
1978
|
-
2. ✅ Condition logic applied
|
|
1979
|
-
3. ✅ Server-side script generated
|
|
1980
|
-
4. ✅ Error handling implemented
|
|
1981
|
-
5. ✅ Activation settings configured
|
|
1982
|
-
|
|
1983
|
-
📋 **Next Steps:**
|
|
1984
|
-
1. Test business rule execution by triggering the event
|
|
1985
|
-
2. Check logs in System Logs > Script Log Statements
|
|
1986
|
-
3. Modify the script if additional logic is needed
|
|
1987
|
-
4. Monitor performance and error handling
|
|
1988
|
-
|
|
1989
|
-
🔄 **Snow-Flow Intelligent Fallback:**
|
|
1990
|
-
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.`
|
|
1991
|
-
: `
|
|
1992
|
-
📦 **Update Set:**
|
|
1993
|
-
- Name: ${updateSetName}
|
|
1994
|
-
- ID: ${updateSetId}
|
|
1995
|
-
${artifactSummary}${activitySummary}
|
|
1996
|
-
🔗 **Direct Links:**
|
|
1997
|
-
- Flow Designer: ${flowUrl}
|
|
1998
|
-
- Flow Designer Home: https://${credentials?.instance}/flow-designer.do?sysparm_nostack=true
|
|
1999
|
-
|
|
2000
|
-
📝 **Flow Components Created:**
|
|
2001
|
-
1. ✅ Trigger configured (${args.trigger_type})
|
|
2002
|
-
2. ✅ Condition logic applied
|
|
2003
|
-
3. ✅ Flow definition structured with ${flowDefinition.activities?.length || 0} activities
|
|
2004
|
-
4. ✅ ${linkedArtifacts.length} artifacts linked and deployed
|
|
2005
|
-
5. ✅ Activation settings configured
|
|
2006
|
-
|
|
2007
|
-
${isComposedFlow ? `
|
|
2008
|
-
🧠 **Intelligent Flow Features:**
|
|
2009
|
-
- ✅ Natural language instruction processed
|
|
2010
|
-
- ✅ Artifacts automatically discovered and linked
|
|
2011
|
-
- ✅ Dependencies resolved and deployed
|
|
2012
|
-
- ✅ Error handling configured
|
|
2013
|
-
- ✅ Variables and connections mapped
|
|
2014
|
-
` : ''}
|
|
2015
|
-
|
|
2016
|
-
📋 **Next Steps:**
|
|
2017
|
-
1. Test flow execution with sample data
|
|
2018
|
-
2. Monitor flow performance and logs
|
|
2019
|
-
3. Review artifact connections
|
|
2020
|
-
4. Customize error handling if needed
|
|
2021
|
-
|
|
2022
|
-
💡 **Composed Flow Capabilities:**
|
|
2023
|
-
- Automatic artifact orchestration
|
|
2024
|
-
- Intelligent output-to-input mapping
|
|
2025
|
-
- Multi-artifact dependency resolution
|
|
2026
|
-
- Natural language configuration`;
|
|
2027
|
-
// ENHANCED: Ensure artifact is tracked in Update Set
|
|
2028
|
-
if (result.success && result.data) {
|
|
2029
|
-
await this.ensureUpdateSetTracking({
|
|
2030
|
-
sys_id: result.data.sys_id,
|
|
2031
|
-
type: usedFallback ? 'Business Rule' : 'Flow',
|
|
2032
|
-
name: args.name,
|
|
2033
|
-
table: usedFallback ? 'sys_script' : 'sys_hub_flow'
|
|
2034
|
-
});
|
|
1777
|
+
const deployResult = await this.deployLinkedArtifact(artifact);
|
|
1778
|
+
deployedArtifacts.push(deployResult);
|
|
1779
|
+
} catch (error) {
|
|
1780
|
+
this.logger.error('Failed to deploy linked artifact', { artifact, error });
|
|
1781
|
+
throw new Error(`Failed to deploy linked artifact ${artifact.name}: ${error}`);
|
|
2035
1782
|
}
|
|
2036
|
-
|
|
2037
|
-
content: [
|
|
2038
|
-
{
|
|
2039
|
-
type: 'text',
|
|
2040
|
-
text: successMessage + continuationMessage,
|
|
2041
|
-
},
|
|
2042
|
-
],
|
|
2043
|
-
};
|
|
1783
|
+
}
|
|
2044
1784
|
}
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
1. Check authentication: snow_auth_diagnostics()
|
|
2052
|
-
2. Validate flow definition: snow_validate_flow_definition()
|
|
2053
|
-
3. Check Update Set: snow_update_set_current()
|
|
2054
|
-
4. Verify flow_designer role permissions
|
|
2055
|
-
|
|
2056
|
-
💡 Alternative Approaches:
|
|
2057
|
-
• Use snow_create_flow with natural language (recommended)
|
|
2058
|
-
• Test with snow_test_flow_with_mock() first
|
|
2059
|
-
• Use snow_flow_wizard for step-by-step creation
|
|
2060
|
-
• Try Business Rule fallback if flow creation fails
|
|
2061
|
-
|
|
2062
|
-
📚 Documentation: See CLAUDE.md for Flow Development Guidelines`;
|
|
2063
|
-
throw new Error(enhancedError);
|
|
1785
|
+
|
|
1786
|
+
// Parse flow definition to inject deployed artifact references
|
|
1787
|
+
// Use the validated and corrected definition
|
|
1788
|
+
let flowDefinition = validatedDefinition;
|
|
1789
|
+
if (typeof flowDefinition === 'string') {
|
|
1790
|
+
flowDefinition = JSON.parse(flowDefinition);
|
|
2064
1791
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
1792
|
+
|
|
1793
|
+
// Update flow activities with deployed artifact sys_ids
|
|
1794
|
+
if (flowDefinition.activities && deployedArtifacts.length > 0) {
|
|
1795
|
+
flowDefinition.activities = flowDefinition.activities.map((activity: any) => {
|
|
1796
|
+
if (activity.artifact_reference) {
|
|
1797
|
+
const deployed = deployedArtifacts.find(d =>
|
|
1798
|
+
d.originalId === activity.artifact_reference.sys_id ||
|
|
1799
|
+
d.name === activity.artifact_reference.name
|
|
1800
|
+
);
|
|
1801
|
+
if (deployed) {
|
|
1802
|
+
activity.artifact_sys_id = deployed.sys_id;
|
|
1803
|
+
activity.artifact_api_name = deployed.api_name;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
return activity;
|
|
1807
|
+
});
|
|
2080
1808
|
}
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
1809
|
+
|
|
1810
|
+
// Create flow data based on flow type
|
|
1811
|
+
const flowData: any = {
|
|
1812
|
+
name: args.name,
|
|
1813
|
+
description: args.description,
|
|
1814
|
+
active: args.active !== false,
|
|
1815
|
+
flow_definition: JSON.stringify(flowDefinition),
|
|
1816
|
+
category: args.category || 'automation',
|
|
1817
|
+
// Additional fields for composed flows
|
|
1818
|
+
is_composed: isComposedFlow,
|
|
1819
|
+
linked_artifact_count: linkedArtifacts.length,
|
|
1820
|
+
artifact_references: deployedArtifacts.map(a => a.sys_id).join(',')
|
|
2093
1821
|
};
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
1822
|
+
|
|
1823
|
+
// Configure based on flow type
|
|
1824
|
+
switch (flowType) {
|
|
1825
|
+
case 'flow':
|
|
1826
|
+
flowData.table = args.table || '';
|
|
1827
|
+
flowData.trigger_type = args.trigger_type;
|
|
1828
|
+
flowData.condition = args.condition || '';
|
|
1829
|
+
flowData.type = 'flow';
|
|
1830
|
+
break;
|
|
1831
|
+
case 'subflow':
|
|
1832
|
+
// Subflows don't have triggers, they're called by other flows
|
|
1833
|
+
flowData.type = 'subflow';
|
|
1834
|
+
flowData.inputs = flowDefinition.inputs || [];
|
|
1835
|
+
flowData.outputs = flowDefinition.outputs || [];
|
|
1836
|
+
break;
|
|
1837
|
+
case 'action':
|
|
1838
|
+
// Actions are reusable components
|
|
1839
|
+
flowData.type = 'action';
|
|
1840
|
+
flowData.action_type = args.action_type || 'custom';
|
|
1841
|
+
flowData.inputs = flowDefinition.inputs || [];
|
|
1842
|
+
flowData.outputs = flowDefinition.outputs || [];
|
|
1843
|
+
break;
|
|
2097
1844
|
}
|
|
2098
|
-
|
|
2099
|
-
|
|
1845
|
+
|
|
1846
|
+
// Deploy to ServiceNow using appropriate API based on flow type
|
|
1847
|
+
let result;
|
|
1848
|
+
let usedFallback = false;
|
|
1849
|
+
let fallbackBusinessRule = null;
|
|
1850
|
+
|
|
1851
|
+
try {
|
|
1852
|
+
// Real ServiceNow Flow deployment using proper API calls
|
|
1853
|
+
switch (flowType) {
|
|
1854
|
+
case 'flow':
|
|
1855
|
+
// Create workflow record in ServiceNow
|
|
1856
|
+
result = await (this.client as any).createRecord('wf_workflow', {
|
|
1857
|
+
name: flowData.name || `flow_${Date.now()}`,
|
|
1858
|
+
description: flowData.description || 'Created by Snow-Flow',
|
|
1859
|
+
table: flowData.table || 'incident',
|
|
1860
|
+
active: flowData.active !== false,
|
|
1861
|
+
condition: flowData.condition || '',
|
|
1862
|
+
script: flowData.script || '// Flow logic here',
|
|
1863
|
+
order: flowData.order || 100
|
|
1864
|
+
});
|
|
1865
|
+
break;
|
|
1866
|
+
case 'subflow':
|
|
1867
|
+
// Create subflow as a workflow activity
|
|
1868
|
+
result = await (this.client as any).createRecord('wf_workflow', {
|
|
1869
|
+
name: flowData.name || `subflow_${Date.now()}`,
|
|
1870
|
+
description: `${flowData.description || 'Subflow created by Snow-Flow'} [SUBFLOW]`,
|
|
1871
|
+
table: flowData.table || 'incident',
|
|
1872
|
+
active: flowData.active !== false,
|
|
1873
|
+
condition: flowData.condition || '',
|
|
1874
|
+
script: flowData.script || '// Subflow logic here',
|
|
1875
|
+
order: flowData.order || 200
|
|
1876
|
+
});
|
|
1877
|
+
break;
|
|
1878
|
+
case 'action':
|
|
1879
|
+
// Create workflow activity/action
|
|
1880
|
+
if (!flowData.workflow_id) {
|
|
1881
|
+
throw new Error('workflow_id is required for flow actions');
|
|
1882
|
+
}
|
|
1883
|
+
result = await (this.client as any).createRecord('wf_activity', {
|
|
1884
|
+
workflow: flowData.workflow_id,
|
|
1885
|
+
name: flowData.name || `action_${Date.now()}`,
|
|
1886
|
+
script: flowData.script || '// Action script here',
|
|
1887
|
+
condition: flowData.condition || '',
|
|
1888
|
+
order: flowData.order || 100,
|
|
1889
|
+
active: flowData.active !== false
|
|
1890
|
+
});
|
|
1891
|
+
break;
|
|
1892
|
+
default:
|
|
1893
|
+
throw new Error(`Unknown flow type: ${flowType}. Supported types: flow, subflow, action`);
|
|
1894
|
+
}
|
|
1895
|
+
} catch (flowError) {
|
|
1896
|
+
this.logger.warn('Flow Designer deployment failed, attempting Business Rule fallback', {
|
|
1897
|
+
error: flowError,
|
|
1898
|
+
flowName: args.name
|
|
1899
|
+
});
|
|
1900
|
+
|
|
1901
|
+
// Try to create equivalent Business Rule instead
|
|
1902
|
+
try {
|
|
1903
|
+
fallbackBusinessRule = await this.createBusinessRuleFallback(args, flowDefinition);
|
|
1904
|
+
result = {
|
|
1905
|
+
success: true,
|
|
1906
|
+
data: fallbackBusinessRule,
|
|
1907
|
+
fallback_used: true,
|
|
1908
|
+
original_error: flowError instanceof Error ? flowError.message : String(flowError)
|
|
1909
|
+
};
|
|
1910
|
+
usedFallback = true;
|
|
1911
|
+
|
|
1912
|
+
this.logger.info('Successfully created Business Rule fallback', {
|
|
1913
|
+
businessRuleId: fallbackBusinessRule.sys_id,
|
|
1914
|
+
originalFlowName: args.name
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1917
|
+
} catch (fallbackError) {
|
|
1918
|
+
this.logger.error('Both Flow Designer and Business Rule fallback failed', {
|
|
1919
|
+
flowError,
|
|
1920
|
+
fallbackError
|
|
1921
|
+
});
|
|
1922
|
+
throw new Error(
|
|
1923
|
+
`🚨 Flow deployment failed and fallback unsuccessful:
|
|
1924
|
+
|
|
1925
|
+
📍 **Errors:**
|
|
1926
|
+
- Flow Designer Error: ${flowError instanceof Error ? flowError.message : String(flowError)}
|
|
1927
|
+
- Business Rule Fallback Error: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}
|
|
1928
|
+
|
|
1929
|
+
🔧 **Update Set Troubleshooting:**
|
|
1930
|
+
1. Check current Update Set: snow_smart_update_set with action="track"
|
|
1931
|
+
2. Verify Update Set is active for tracking
|
|
1932
|
+
3. Use mock testing: snow_test_flow_with_mock instead
|
|
1933
|
+
4. Check flow exists: snow_get_by_sysid
|
|
1934
|
+
|
|
1935
|
+
💡 **Alternative Solutions:**
|
|
1936
|
+
- Use snow_test_flow_with_mock for safe testing
|
|
1937
|
+
- Verify flow creation with snow_get_by_sysid
|
|
1938
|
+
- Check Update Set contains the flow artifact
|
|
1939
|
+
- Create Business Rule manually if needed
|
|
1940
|
+
|
|
1941
|
+
📚 Please check your flow definition JSON format or use manual deployment.`
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
const credentials = await this.oauth.loadCredentials();
|
|
1947
|
+
const flowUrl = result.success && result.data
|
|
1948
|
+
? (usedFallback
|
|
1949
|
+
? `https://${credentials?.instance}/sys_script.do?sys_id=${result.data.sys_id}`
|
|
1950
|
+
: `https://${credentials?.instance}/nav_to.do?uri=sys_hub_flow.do?sys_id=${result.data.sys_id}`)
|
|
1951
|
+
: `https://${credentials?.instance}/flow-designer.do`;
|
|
1952
|
+
|
|
1953
|
+
const artifactSummary = deployedArtifacts.length > 0
|
|
1954
|
+
? `\n🔗 **Linked Artifacts Deployed:**\n${deployedArtifacts.map((a, i) =>
|
|
1955
|
+
`${i + 1}. ${a.type}: ${a.name} (${a.sys_id})`
|
|
1956
|
+
).join('\n')}\n`
|
|
1957
|
+
: '';
|
|
1958
|
+
|
|
1959
|
+
const activitySummary = flowDefinition.activities
|
|
1960
|
+
? `\n📊 **Flow Activities:**\n${flowDefinition.activities.map((a: any, i: number) =>
|
|
1961
|
+
`${i + 1}. ${a.name} (${a.type})${a.artifact_reference ? ` - Uses: ${a.artifact_reference.name}` : ''}`
|
|
1962
|
+
).join('\n')}\n`
|
|
1963
|
+
: '';
|
|
1964
|
+
|
|
1965
|
+
const successMessage = usedFallback
|
|
1966
|
+
? `🔄 **INTELLIGENT FALLBACK SUCCESSFUL!**
|
|
1967
|
+
|
|
1968
|
+
⚠️ Flow Designer deployment failed, but Snow-Flow automatically created a Business Rule that achieves the same result!
|
|
1969
|
+
|
|
1970
|
+
🛠️ **Business Rule Details:**
|
|
1971
|
+
- Name: ${args.name}
|
|
1972
|
+
- Type: 🔧 Business Rule (Fallback from Flow Designer)
|
|
1973
|
+
- Table: ${args.table || 'sys_user'}
|
|
1974
|
+
- When: ${this.getTriggerWhen(args.trigger_type)}
|
|
1975
|
+
- Active: ${args.active !== false ? 'Yes' : 'No'}
|
|
1976
|
+
- Original Error: ${result.original_error}
|
|
1977
|
+
|
|
1978
|
+
✨ **Why This Works Better:**
|
|
1979
|
+
- ✅ More reliable than Flow Designer for simple automations
|
|
1980
|
+
- ✅ Faster execution (server-side JavaScript)
|
|
1981
|
+
- ✅ Better error handling and debugging
|
|
1982
|
+
- ✅ Direct database access capabilities`
|
|
1983
|
+
: `✅ Flow Designer flow deployed successfully!
|
|
1984
|
+
|
|
1985
|
+
🔄 **${flowType.charAt(0).toUpperCase() + flowType.slice(1)} Details:**
|
|
1986
|
+
- Name: ${args.name}
|
|
1987
|
+
- Flow Type: ${flowType === 'flow' ? '📋 Flow' : flowType === 'subflow' ? '🔄 Subflow' : '⚡ Action'}
|
|
1988
|
+
- Composed: ${isComposedFlow ? '🧠 Yes - Intelligent Composed Flow' : '❌ No - Standard'}
|
|
1989
|
+
${flowType === 'flow' ? `- Trigger Type: ${args.trigger_type}
|
|
1990
|
+
- Table: ${args.table || 'N/A'}` : ''}
|
|
1991
|
+
${flowType !== 'flow' ? `- Inputs: ${flowDefinition.inputs?.length || 0}
|
|
1992
|
+
- Outputs: ${flowDefinition.outputs?.length || 0}` : ''}
|
|
1993
|
+
- Category: ${args.category || 'automation'}
|
|
1994
|
+
- Active: ${args.active !== false ? 'Yes' : 'No'}`;
|
|
1995
|
+
|
|
1996
|
+
const continuationMessage = usedFallback
|
|
1997
|
+
? `
|
|
1998
|
+
📦 **Update Set:**
|
|
1999
|
+
- Name: ${updateSetName}
|
|
2000
|
+
- ID: ${updateSetId}
|
|
2001
|
+
|
|
2002
|
+
🔗 **Direct Links:**
|
|
2003
|
+
- Business Rule: ${flowUrl}
|
|
2004
|
+
- Business Rules List: https://${credentials?.instance}/sys_script_list.do
|
|
2005
|
+
|
|
2006
|
+
📝 **Business Rule Components Created:**
|
|
2007
|
+
1. ✅ Trigger configured (${this.getTriggerWhen(args.trigger_type)})
|
|
2008
|
+
2. ✅ Condition logic applied
|
|
2009
|
+
3. ✅ Server-side script generated
|
|
2010
|
+
4. ✅ Error handling implemented
|
|
2011
|
+
5. ✅ Activation settings configured
|
|
2012
|
+
|
|
2013
|
+
📋 **Next Steps:**
|
|
2014
|
+
1. Test business rule execution by triggering the event
|
|
2015
|
+
2. Check logs in System Logs > Script Log Statements
|
|
2016
|
+
3. Modify the script if additional logic is needed
|
|
2017
|
+
4. Monitor performance and error handling
|
|
2018
|
+
|
|
2019
|
+
🔄 **Snow-Flow Intelligent Fallback:**
|
|
2020
|
+
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.`
|
|
2021
|
+
: `
|
|
2022
|
+
📦 **Update Set:**
|
|
2023
|
+
- Name: ${updateSetName}
|
|
2024
|
+
- ID: ${updateSetId}
|
|
2025
|
+
${artifactSummary}${activitySummary}
|
|
2026
|
+
🔗 **Direct Links:**
|
|
2027
|
+
- Flow Designer: ${flowUrl}
|
|
2028
|
+
- Flow Designer Home: https://${credentials?.instance}/flow-designer.do?sysparm_nostack=true
|
|
2029
|
+
|
|
2030
|
+
📝 **Flow Components Created:**
|
|
2031
|
+
1. ✅ Trigger configured (${args.trigger_type})
|
|
2032
|
+
2. ✅ Condition logic applied
|
|
2033
|
+
3. ✅ Flow definition structured with ${flowDefinition.activities?.length || 0} activities
|
|
2034
|
+
4. ✅ ${linkedArtifacts.length} artifacts linked and deployed
|
|
2035
|
+
5. ✅ Activation settings configured
|
|
2036
|
+
|
|
2037
|
+
${isComposedFlow ? `
|
|
2038
|
+
🧠 **Intelligent Flow Features:**
|
|
2039
|
+
- ✅ Natural language instruction processed
|
|
2040
|
+
- ✅ Artifacts automatically discovered and linked
|
|
2041
|
+
- ✅ Dependencies resolved and deployed
|
|
2042
|
+
- ✅ Error handling configured
|
|
2043
|
+
- ✅ Variables and connections mapped
|
|
2044
|
+
` : ''}
|
|
2045
|
+
|
|
2046
|
+
📋 **Next Steps:**
|
|
2047
|
+
1. Test flow execution with sample data
|
|
2048
|
+
2. Monitor flow performance and logs
|
|
2049
|
+
3. Review artifact connections
|
|
2050
|
+
4. Customize error handling if needed
|
|
2051
|
+
|
|
2052
|
+
💡 **Composed Flow Capabilities:**
|
|
2053
|
+
- Automatic artifact orchestration
|
|
2054
|
+
- Intelligent output-to-input mapping
|
|
2055
|
+
- Multi-artifact dependency resolution
|
|
2056
|
+
- Natural language configuration`;
|
|
2057
|
+
|
|
2058
|
+
// ENHANCED: Ensure artifact is tracked in Update Set
|
|
2059
|
+
if (result.success && result.data) {
|
|
2060
|
+
await this.ensureUpdateSetTracking({
|
|
2100
2061
|
sys_id: result.data.sys_id,
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2062
|
+
type: usedFallback ? 'Business Rule' : 'Flow',
|
|
2063
|
+
name: args.name,
|
|
2064
|
+
table: usedFallback ? 'sys_script' : 'sys_hub_flow'
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
return {
|
|
2069
|
+
content: [
|
|
2070
|
+
{
|
|
2071
|
+
type: 'text',
|
|
2072
|
+
text: successMessage + continuationMessage,
|
|
2073
|
+
},
|
|
2074
|
+
],
|
|
2105
2075
|
};
|
|
2076
|
+
} catch (error) {
|
|
2077
|
+
const enhancedError = `🚨 Flow Deployment Failed
|
|
2078
|
+
|
|
2079
|
+
📍 Error: ${error instanceof Error ? error.message : String(error)}
|
|
2080
|
+
|
|
2081
|
+
🔧 Troubleshooting Steps:
|
|
2082
|
+
1. Check authentication: snow_auth_diagnostics()
|
|
2083
|
+
2. Validate flow definition: snow_validate_flow_definition()
|
|
2084
|
+
3. Check Update Set: snow_update_set_current()
|
|
2085
|
+
4. Verify flow_designer role permissions
|
|
2086
|
+
|
|
2087
|
+
💡 Alternative Approaches:
|
|
2088
|
+
• Use snow_create_flow with natural language (recommended)
|
|
2089
|
+
• Test with snow_test_flow_with_mock() first
|
|
2090
|
+
• Use snow_flow_wizard for step-by-step creation
|
|
2091
|
+
• Try Business Rule fallback if flow creation fails
|
|
2092
|
+
|
|
2093
|
+
📚 Documentation: See CLAUDE.md for Flow Development Guidelines`;
|
|
2094
|
+
throw new Error(enhancedError);
|
|
2095
|
+
}
|
|
2096
|
+
} */
|
|
2097
|
+
/**
|
|
2098
|
+
* Deploy a linked artifact (script include, business rule, etc.) - DEPRECATED
|
|
2099
|
+
*/
|
|
2100
|
+
/* private async deployLinkedArtifact(artifact: any): Promise<any> {
|
|
2101
|
+
this.logger.info('Deploying linked artifact', { type: artifact.type, name: artifact.name });
|
|
2102
|
+
|
|
2103
|
+
switch (artifact.type) {
|
|
2104
|
+
case 'script_include':
|
|
2105
|
+
throw new Error('Script includes via flow deployment are deprecated. Use direct artifact creation instead.');
|
|
2106
|
+
|
|
2107
|
+
case 'business_rule':
|
|
2108
|
+
return await this.deployBusinessRule(artifact);
|
|
2109
|
+
|
|
2110
|
+
case 'table':
|
|
2111
|
+
return await this.deployTable(artifact);
|
|
2112
|
+
|
|
2113
|
+
default:
|
|
2114
|
+
throw new Error(`Unknown artifact type: ${artifact.type}`);
|
|
2115
|
+
}
|
|
2116
|
+
} */
|
|
2117
|
+
/**
|
|
2118
|
+
* Deploy a script include artifact - DEPRECATED
|
|
2119
|
+
*/
|
|
2120
|
+
/* private async deployScriptInclude(artifact: any): Promise<any> {
|
|
2121
|
+
const scriptIncludeData = {
|
|
2122
|
+
name: artifact.name,
|
|
2123
|
+
api_name: artifact.api_name || artifact.name,
|
|
2124
|
+
description: artifact.description || `Script include for ${artifact.purpose}`,
|
|
2125
|
+
script: artifact.script || artifact.fallback_script,
|
|
2126
|
+
active: true,
|
|
2127
|
+
access: 'public'
|
|
2128
|
+
};
|
|
2129
|
+
|
|
2130
|
+
const result = await this.client.createScriptInclude(scriptIncludeData);
|
|
2131
|
+
|
|
2132
|
+
if (!result.data?.sys_id) {
|
|
2133
|
+
throw new Error(`Script Include deployment failed: No sys_id returned from ServiceNow. Result: ${JSON.stringify(result)}`);
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
return {
|
|
2137
|
+
originalId: artifact.sys_id,
|
|
2138
|
+
sys_id: result.data.sys_id,
|
|
2139
|
+
name: artifact.name,
|
|
2140
|
+
api_name: scriptIncludeData.api_name,
|
|
2141
|
+
type: 'script_include',
|
|
2142
|
+
success: result.success
|
|
2143
|
+
};
|
|
2106
2144
|
}
|
|
2145
|
+
|
|
2107
2146
|
/**
|
|
2108
2147
|
* Deploy a business rule artifact
|
|
2109
2148
|
*/
|
|
@@ -5539,13 +5578,13 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
|
|
|
5539
5578
|
let result;
|
|
5540
5579
|
switch (artifact.type) {
|
|
5541
5580
|
case 'flow':
|
|
5542
|
-
|
|
5581
|
+
throw new Error('Flow deployment is deprecated. Flows, workflows, and subflows are no longer supported. Use widgets or applications instead.');
|
|
5543
5582
|
break;
|
|
5544
5583
|
case 'widget':
|
|
5545
5584
|
result = await this.deployWidget(artifact.create);
|
|
5546
5585
|
break;
|
|
5547
5586
|
case 'script_include':
|
|
5548
|
-
result = await this.
|
|
5587
|
+
result = await this.client.createScriptInclude(artifact.create);
|
|
5549
5588
|
break;
|
|
5550
5589
|
case 'business_rule':
|
|
5551
5590
|
result = await this.deployBusinessRule(artifact.create);
|
|
@@ -5861,12 +5900,7 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
|
|
|
5861
5900
|
};
|
|
5862
5901
|
}
|
|
5863
5902
|
case 'flow':
|
|
5864
|
-
|
|
5865
|
-
return {
|
|
5866
|
-
success: flowResult.content[0].text.includes('✅'),
|
|
5867
|
-
sys_id: flowResult.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
|
|
5868
|
-
message: 'Flow deployed'
|
|
5869
|
-
};
|
|
5903
|
+
throw new Error('Flow deployment is deprecated. Use widgets or applications instead.');
|
|
5870
5904
|
case 'script':
|
|
5871
5905
|
case 'script_include':
|
|
5872
5906
|
const scriptResult = await this.createRecordWithRetry('sys_script_include', config);
|
|
@@ -5961,7 +5995,7 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
|
|
|
5961
5995
|
async rollbackArtifact(artifact) {
|
|
5962
5996
|
const tableMap = {
|
|
5963
5997
|
'widget': 'sp_widget',
|
|
5964
|
-
'flow': 'sys_hub_flow',
|
|
5998
|
+
// 'flow': 'sys_hub_flow', // REMOVED - flows deprecated
|
|
5965
5999
|
'script': 'sys_script_include',
|
|
5966
6000
|
'script_include': 'sys_script_include',
|
|
5967
6001
|
'business_rule': 'sys_script',
|
|
@@ -7596,11 +7630,11 @@ Use individual deployment tools like \`snow_deploy_${args.type}\` with manual co
|
|
|
7596
7630
|
getTableForArtifactType(artifactType) {
|
|
7597
7631
|
const ARTIFACT_TABLES = {
|
|
7598
7632
|
'widget': 'sp_widget',
|
|
7599
|
-
'flow': 'sys_hub_flow',
|
|
7633
|
+
// 'flow': 'sys_hub_flow', // REMOVED - flows deprecated
|
|
7600
7634
|
'script': 'sys_script_include',
|
|
7601
7635
|
'script_include': 'sys_script_include',
|
|
7602
7636
|
'business_rule': 'sys_script',
|
|
7603
|
-
'workflow': 'wf_workflow',
|
|
7637
|
+
// 'workflow': 'wf_workflow', // REMOVED - workflows deprecated
|
|
7604
7638
|
'application': 'sys_app',
|
|
7605
7639
|
'ui_action': 'sys_ui_action',
|
|
7606
7640
|
'ui_page': 'sys_ui_page',
|