snow-flow 1.3.16 → 1.3.18

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.
@@ -4,6 +4,39 @@
4
4
  * ServiceNow Flow Composer MCP Server
5
5
  * Natural language flow creation with multi-artifact orchestration
6
6
  */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
7
40
  Object.defineProperty(exports, "__esModule", { value: true });
8
41
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
9
42
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
@@ -11,7 +44,6 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
11
44
  const servicenow_client_js_1 = require("../utils/servicenow-client.js");
12
45
  const snow_oauth_js_1 = require("../utils/snow-oauth.js");
13
46
  const logger_js_1 = require("../utils/logger.js");
14
- const flow_structure_builder_js_1 = require("../utils/flow-structure-builder.js");
15
47
  class ServiceNowFlowComposerMCP {
16
48
  constructor() {
17
49
  this.server = new index_js_1.Server({
@@ -32,7 +64,7 @@ class ServiceNowFlowComposerMCP {
32
64
  tools: [
33
65
  {
34
66
  name: 'snow_create_flow',
35
- description: 'FULLY AUTONOMOUS flow creation - parses natural language, discovers artifacts, creates missing components, links everything, deploys automatically. ZERO MANUAL WORK!',
67
+ description: '🚀 PRIMARY FLOW TOOL - Create production-ready Flow Designer flows with XML-first approach and automatic deployment to ServiceNow. ZERO MANUAL STEPS!',
36
68
  inputSchema: {
37
69
  type: 'object',
38
70
  properties: {
@@ -297,30 +329,43 @@ class ServiceNowFlowComposerMCP {
297
329
  // 🧠 STEP 4: Generate complete flow definition
298
330
  const flowDefinition = await this.generateFlowDefinition(parsedIntent, templateMatch, artifacts);
299
331
  console.log('🧠 Generated flow definition:', JSON.stringify(flowDefinition, null, 2));
300
- // 🧠 STEP 5: Deploy if requested
332
+ // 🧠 STEP 5: Deploy using XML-first approach for maximum reliability
301
333
  let deploymentResult = null;
302
334
  if (args.deploy_immediately !== false) {
303
- console.log('🚀 DEPLOYING intelligent flow to ServiceNow...');
304
- // Use the conversion utility to ensure proper format
305
- const enhancedFlowDefinition = (0, flow_structure_builder_js_1.convertToFlowDefinition)({
306
- name: parsedIntent.flowName,
307
- description: parsedIntent.description,
308
- table: parsedIntent.table,
309
- trigger: parsedIntent.trigger,
310
- activities: flowDefinition.activities || [],
311
- variables: flowDefinition.variables || [],
312
- connections: flowDefinition.connections || [],
313
- error_handling: flowDefinition.error_handling || []
314
- });
315
- // Try enhanced method first, fallback to original if needed
335
+ console.log('🚀 DEPLOYING flow using XML-first approach...');
316
336
  try {
317
- deploymentResult = await this.client.createFlowWithStructureBuilder(enhancedFlowDefinition);
318
- console.log('🚀 Enhanced deployment result:', deploymentResult);
337
+ // Import the XML flow generator
338
+ const { generateProductionFlowXML } = await Promise.resolve().then(() => __importStar(require('../utils/xml-first-flow-generator.js')));
339
+ // Convert to XML flow definition format
340
+ const xmlFlowDef = {
341
+ name: parsedIntent.flowName,
342
+ description: parsedIntent.description,
343
+ table: parsedIntent.table,
344
+ trigger_type: this.mapTriggerTypeToXML(parsedIntent.trigger.type),
345
+ trigger_condition: parsedIntent.trigger.condition || '',
346
+ activities: this.convertActivitiesToXML(flowDefinition.activities || []),
347
+ run_as: 'user',
348
+ accessible_from: 'package_private'
349
+ };
350
+ // Generate production-ready XML
351
+ const xmlResult = generateProductionFlowXML(xmlFlowDef);
352
+ console.log('✅ XML generated:', xmlResult.filePath);
353
+ // Auto-deploy XML to ServiceNow
354
+ await this.deployXMLToServiceNow(xmlResult.filePath);
355
+ deploymentResult = {
356
+ success: true,
357
+ method: 'xml_first',
358
+ xml_file: xmlResult.filePath,
359
+ message: '✅ Flow deployed using XML-first approach!'
360
+ };
319
361
  }
320
- catch (enhancedError) {
321
- console.warn('⚠️ Enhanced deployment failed, falling back to original method:', enhancedError);
322
- deploymentResult = await this.client.createFlow(flowDefinition);
323
- console.log('🚀 Fallback deployment result:', deploymentResult);
362
+ catch (xmlError) {
363
+ console.warn('⚠️ XML deployment failed, providing manual instructions:', xmlError);
364
+ deploymentResult = {
365
+ success: false,
366
+ error: xmlError instanceof Error ? xmlError.message : String(xmlError),
367
+ fallback_instructions: 'Use snow-flow deploy-xml command for manual deployment'
368
+ };
324
369
  }
325
370
  }
326
371
  const credentials = await this.oauth.loadCredentials();
@@ -329,9 +374,9 @@ class ServiceNowFlowComposerMCP {
329
374
  content: [
330
375
  {
331
376
  type: 'text',
332
- text: `🎯 INTELLIGENT FLOW CREATED SUCCESSFULLY!
377
+ text: `🎯 FLOW CREATED WITH XML-FIRST APPROACH!
333
378
 
334
- ${args.deploy_immediately !== false ? `🚀 **LIVE DEPLOYMENT** - Real flow created in ServiceNow!` : `📋 **PLANNING MODE** - Flow structure generated`}
379
+ ${args.deploy_immediately !== false ? `🚀 **FULLY AUTOMATED DEPLOYMENT** - XML generated & deployed to ServiceNow!` : `📋 **PLANNING MODE** - Flow structure generated`}
335
380
 
336
381
  🧠 **Intelligent Analysis:**
337
382
  - **Flow Name**: ${parsedIntent.flowName}
@@ -347,26 +392,27 @@ ${args.deploy_immediately !== false ? `🚀 **LIVE DEPLOYMENT** - Real flow crea
347
392
  - **Error Handling**: ${flowDefinition.error_handling?.length || 0} safety measures
348
393
  - **Artifacts Used**: ${artifacts.existing.length} found, ${artifacts.created.length} created
349
394
 
350
- 🚀 **Deployment Status:**
351
- ${deploymentResult ? (deploymentResult.success ? '✅ Successfully deployed to ServiceNow!' : `❌ Deployment failed: ${deploymentResult.error}`) : '⏳ Ready for deployment'}
352
-
353
- ${deploymentResult?.success ? `🎯 **Live Flow Details:**
354
- - **System ID**: ${deploymentResult.data?.sys_id || 'Unknown'}
355
- - **Status**: ${deploymentResult.data?.status || 'Active'}
356
- - **URL**: ${deploymentResult.data?.url || flowUrl}` : ''}
395
+ 🚀 **XML-First Deployment:**
396
+ ${deploymentResult ? (deploymentResult.success ?
397
+ `✅ Successfully deployed using XML-first approach!
398
+ - **Method**: Production-ready Update Set XML
399
+ - **XML File**: ${deploymentResult.xml_file}
400
+ - **Status**: Imported → Previewed → Committed ✅` :
401
+ `❌ Auto-deployment failed: ${deploymentResult.error}
402
+ - **Fallback**: ${deploymentResult.fallback_instructions}`) : '⏳ Ready for deployment'}
357
403
 
358
404
  🔗 **ServiceNow Access:**
359
405
  - Flow Designer: ${flowUrl}
360
406
  - Flow Designer Home: https://${credentials?.instance}/flow-designer
361
407
 
362
- 🧠 **Intelligence Features:**
363
- - Natural language processing ✅
364
- - Template matching and adaptation ✅
365
- - Artifact discovery and reuse ✅
366
- - Complete flow definition generation ✅
367
- - Error handling and validation ✅
408
+ 🧠 **NEW Features (v1.3.17):**
409
+ - XML-first approach for maximum reliability ✅
410
+ - Automatic Update Set deployment ✅
411
+ - Zero manual steps required ✅
412
+ - Production-ready Flow Designer format ✅
413
+ - Intelligent error handling & fallbacks ✅
368
414
 
369
- Your flow is now intelligently crafted and ready for use! 🎉`,
415
+ Your flow is now live in ServiceNow Flow Designer! 🎉`,
370
416
  },
371
417
  ],
372
418
  };
@@ -1679,7 +1725,7 @@ ${flowInstruction.recommendations?.map((rec, index) => `${index + 1}. ${rec}`).j
1679
1725
 
1680
1726
  🚀 **Next Steps:**
1681
1727
  1. Use \`snow_template_matching\` to explore template options
1682
- 2. Run \`snow_create_flow\` to implement the recommended approach
1728
+ 2. Run \`snow_create_flow\` with deploy_immediately: true to implement the recommended approach
1683
1729
  3. Consider \`snow_scope_optimization\` for deployment strategy
1684
1730
 
1685
1731
  ✅ **Analysis Complete!** The instruction has been comprehensively analyzed with intelligent insights.`,
@@ -1841,7 +1887,7 @@ ${categoryFilteredResults.length === 0 ? `🔍 **No templates found matching you
1841
1887
  - **Recommended**: ${categoryFilteredResults[0]?.confidence >= 0.8 ? 'Yes - High confidence match' : 'Consider manual review'}
1842
1888
 
1843
1889
  🚀 **Next Steps:**
1844
- 1. Use \`snow_create_flow\` to implement the best matching template
1890
+ 1. Use \`snow_create_flow\` with deploy_immediately: true to implement the best matching template
1845
1891
  2. Review template customization options
1846
1892
  3. Consider \`snow_intelligent_flow_analysis\` for detailed analysis
1847
1893
  4. Modify instruction if no suitable templates found
@@ -1860,6 +1906,128 @@ ${categoryFilteredResults.length === 0 ? `🔍 **No templates found matching you
1860
1906
  await this.server.connect(transport);
1861
1907
  this.logger.info('ServiceNow Flow Composer MCP Server started');
1862
1908
  }
1909
+ /**
1910
+ * Map trigger type to XML format
1911
+ */
1912
+ mapTriggerTypeToXML(triggerType) {
1913
+ const mapping = {
1914
+ 'record_created': 'record_created',
1915
+ 'record_updated': 'record_updated',
1916
+ 'manual': 'manual',
1917
+ 'scheduled': 'scheduled',
1918
+ 'create': 'record_created',
1919
+ 'update': 'record_updated',
1920
+ 'on_create': 'record_created',
1921
+ 'on_update': 'record_updated'
1922
+ };
1923
+ return mapping[triggerType.toLowerCase()] || 'manual';
1924
+ }
1925
+ /**
1926
+ * Convert activities to XML format
1927
+ */
1928
+ convertActivitiesToXML(activities) {
1929
+ return activities.map((activity, index) => ({
1930
+ type: this.mapActivityTypeToXML(activity.type),
1931
+ name: activity.name || `Activity ${index + 1}`,
1932
+ inputs: activity.inputs || {},
1933
+ order: (index + 1) * 100,
1934
+ description: activity.description || activity.name
1935
+ }));
1936
+ }
1937
+ /**
1938
+ * Map activity type to XML format
1939
+ */
1940
+ mapActivityTypeToXML(activityType) {
1941
+ const mapping = {
1942
+ 'approval': 'approval',
1943
+ 'notification': 'notification',
1944
+ 'email': 'notification',
1945
+ 'script': 'script',
1946
+ 'create_record': 'create_record',
1947
+ 'update_record': 'update_record',
1948
+ 'rest_call': 'rest_step',
1949
+ 'condition': 'condition',
1950
+ 'subflow': 'assign_subflow'
1951
+ };
1952
+ return mapping[activityType.toLowerCase()] || 'script';
1953
+ }
1954
+ /**
1955
+ * Deploy XML file to ServiceNow automatically
1956
+ */
1957
+ async deployXMLToServiceNow(xmlFilePath) {
1958
+ // Check authentication
1959
+ const isAuth = await this.oauth.isAuthenticated();
1960
+ if (!isAuth) {
1961
+ throw new Error('Not authenticated with ServiceNow. Please run: snow-flow auth login');
1962
+ }
1963
+ // Initialize ServiceNow client
1964
+ const ServiceNowClient = (await Promise.resolve().then(() => __importStar(require('../utils/servicenow-client.js')))).ServiceNowClient;
1965
+ const client = new ServiceNowClient();
1966
+ // Read the XML file
1967
+ const fs = require('fs').promises;
1968
+ const xmlContent = await fs.readFile(xmlFilePath, 'utf-8');
1969
+ // Import XML as remote update set
1970
+ const importResponse = await client.makeRequest({
1971
+ method: 'POST',
1972
+ url: '/api/now/table/sys_remote_update_set',
1973
+ headers: {
1974
+ 'Content-Type': 'application/xml',
1975
+ 'Accept': 'application/json'
1976
+ },
1977
+ data: xmlContent
1978
+ });
1979
+ if (!importResponse.result || !importResponse.result.sys_id) {
1980
+ throw new Error('Failed to import XML update set');
1981
+ }
1982
+ const remoteUpdateSetId = importResponse.result.sys_id;
1983
+ this.logger.info(`✅ XML imported successfully (sys_id: ${remoteUpdateSetId})`);
1984
+ // Load the update set
1985
+ await client.makeRequest({
1986
+ method: 'PUT',
1987
+ url: `/api/now/table/sys_remote_update_set/${remoteUpdateSetId}`,
1988
+ data: {
1989
+ state: 'loaded'
1990
+ }
1991
+ });
1992
+ // Find the loaded update set
1993
+ const loadedResponse = await client.makeRequest({
1994
+ method: 'GET',
1995
+ url: '/api/now/table/sys_update_set',
1996
+ params: {
1997
+ sysparm_query: `remote_sys_id=${remoteUpdateSetId}`,
1998
+ sysparm_limit: 1
1999
+ }
2000
+ });
2001
+ if (!loadedResponse.result || loadedResponse.result.length === 0) {
2002
+ throw new Error('Failed to find loaded update set');
2003
+ }
2004
+ const updateSetId = loadedResponse.result[0].sys_id;
2005
+ const updateSetName = loadedResponse.result[0].name;
2006
+ // Preview the update set
2007
+ await client.makeRequest({
2008
+ method: 'POST',
2009
+ url: `/api/now/table/sys_update_set/${updateSetId}/preview`
2010
+ });
2011
+ // Check for preview problems
2012
+ const previewProblems = await client.makeRequest({
2013
+ method: 'GET',
2014
+ url: '/api/now/table/sys_update_preview_problem',
2015
+ params: {
2016
+ sysparm_query: `update_set=${updateSetId}`,
2017
+ sysparm_limit: 100
2018
+ }
2019
+ });
2020
+ if (previewProblems.result && previewProblems.result.length > 0) {
2021
+ const problemsList = previewProblems.result.map((p) => `- ${p.type}: ${p.description}`).join('\n');
2022
+ throw new Error(`Preview found problems:\n${problemsList}\n\nPlease review and resolve in ServiceNow UI`);
2023
+ }
2024
+ // Commit the update set
2025
+ await client.makeRequest({
2026
+ method: 'POST',
2027
+ url: `/api/now/table/sys_update_set/${updateSetId}/commit`
2028
+ });
2029
+ this.logger.info(`✅ Update set committed successfully: ${updateSetName}`);
2030
+ }
1863
2031
  }
1864
2032
  // Start the server
1865
2033
  const server = new ServiceNowFlowComposerMCP();
@@ -302,6 +302,24 @@ class ServiceNowPlatformDevelopmentMCP {
302
302
  async getTableInfo(tableName) {
303
303
  try {
304
304
  this.logger.debug(`Looking up table info for: ${tableName}`);
305
+ // First, check if this is a known standard table that may not appear in sys_db_object
306
+ const standardTables = {
307
+ 'incident': { label: 'Incident' },
308
+ 'problem': { label: 'Problem' },
309
+ 'change_request': { label: 'Change Request' },
310
+ 'sc_request': { label: 'Request' },
311
+ 'sc_req_item': { label: 'Requested Item' },
312
+ 'sc_task': { label: 'Catalog Task' },
313
+ 'task': { label: 'Task' }
314
+ };
315
+ if (standardTables[tableName]) {
316
+ this.logger.debug(`Using known standard table: ${tableName}`);
317
+ return {
318
+ name: tableName,
319
+ label: standardTables[tableName].label,
320
+ sys_id: `standard_table_${tableName}` // Placeholder sys_id for standard tables
321
+ };
322
+ }
305
323
  // Try direct lookup first
306
324
  const tableResponse = await this.client.searchRecords('sys_db_object', `name=${tableName}`, 1);
307
325
  if (tableResponse.success && tableResponse.data?.result?.length > 0) {
@@ -312,6 +330,8 @@ class ServiceNowPlatformDevelopmentMCP {
312
330
  sys_id: table.sys_id
313
331
  };
314
332
  }
333
+ // Log the actual response for debugging
334
+ this.logger.debug(`Table lookup response for ${tableName}: ${JSON.stringify(tableResponse)}`);
315
335
  // Try by sys_id
316
336
  const tableByIdResponse = await this.client.searchRecords('sys_db_object', `sys_id=${tableName}`, 1);
317
337
  if (tableByIdResponse.success && tableByIdResponse.data?.result?.length > 0) {
@@ -583,10 +603,15 @@ class ServiceNowPlatformDevelopmentMCP {
583
603
  this.logger.debug(`Found table info: ${JSON.stringify(tableInfo)}`);
584
604
  // Get detailed table metadata
585
605
  this.logger.debug(`Attempting to fetch table details for sys_id: ${tableInfo.sys_id}`);
586
- const tableDetailsResponse = await this.client.getRecord('sys_db_object', tableInfo.sys_id);
606
+ // Check if this is a standard table with placeholder sys_id
607
+ const isStandardTable = tableInfo.sys_id.startsWith('standard_table_');
608
+ let tableDetailsResponse = { success: false };
609
+ if (!isStandardTable) {
610
+ tableDetailsResponse = await this.client.getRecord('sys_db_object', tableInfo.sys_id);
611
+ }
587
612
  // Declare the variable once with proper type
588
613
  let tableDetails;
589
- if (!tableDetailsResponse.success) {
614
+ if (!tableDetailsResponse.success || isStandardTable) {
590
615
  const errorMessage = tableDetailsResponse.error ||
591
616
  JSON.stringify(tableDetailsResponse) ||
592
617
  'Unknown error occurred while fetching table details';
@@ -187,6 +187,10 @@ class ServiceNowUpdateSetMCP extends base_mcp_server_js_1.BaseMCPServer {
187
187
  url: '/api/now/table/sys_update_set',
188
188
  data: updateSetData
189
189
  });
190
+ // Validate response structure
191
+ if (!response || !response.result) {
192
+ throw new Error(`Invalid API response: ${JSON.stringify(response)}`);
193
+ }
190
194
  const updateSet = response.result;
191
195
  // Create session
192
196
  const session = {
@@ -276,6 +276,10 @@ class ServiceNowUpdateSetMCP {
276
276
  if (!response.success) {
277
277
  throw new Error(response.error || 'Failed to create Update Set');
278
278
  }
279
+ // Validate response structure
280
+ if (!response.data || !response.data.sys_id) {
281
+ throw new Error(`Invalid Update Set response: missing data or sys_id. Response: ${JSON.stringify(response)}`);
282
+ }
279
283
  // Auto-switch to Update Set if requested (default: true)
280
284
  const autoSwitch = args.auto_switch !== false;
281
285
  let switchedToUpdateSet = false;
@@ -41,6 +41,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.ServiceNowXMLFlowMCP = void 0;
42
42
  const base_mcp_server_1 = require("./base-mcp-server");
43
43
  const improved_flow_xml_generator_1 = __importStar(require("../utils/improved-flow-xml-generator"));
44
+ const xml_first_flow_generator_1 = require("../utils/xml-first-flow-generator"); // Keep for backward compatibility
44
45
  const natural_language_mapper_1 = require("../api/natural-language-mapper");
45
46
  const servicenow_id_generator_js_1 = require("../utils/servicenow-id-generator.js");
46
47
  const fs = __importStar(require("fs"));
@@ -118,7 +119,7 @@ class ServiceNowXMLFlowMCP extends base_mcp_server_1.BaseMCPServer {
118
119
  // Generate flow XML from natural language
119
120
  this.registerTool({
120
121
  name: 'snow_xml_flow_from_instruction',
121
- description: 'Generate flow Update Set XML from natural language instruction',
122
+ description: '⚠️ DEPRECATED - Use snow_create_flow instead. This tool is kept for backwards compatibility only.',
122
123
  inputSchema: {
123
124
  type: 'object',
124
125
  properties: {
@@ -130,6 +131,11 @@ class ServiceNowXMLFlowMCP extends base_mcp_server_1.BaseMCPServer {
130
131
  type: 'boolean',
131
132
  default: true,
132
133
  description: 'Save XML to file'
134
+ },
135
+ auto_deploy: {
136
+ type: 'boolean',
137
+ default: true,
138
+ description: 'Automatically deploy XML to ServiceNow after generation (RECOMMENDED)'
133
139
  }
134
140
  },
135
141
  required: ['instruction']
@@ -219,7 +225,7 @@ class ServiceNowXMLFlowMCP extends base_mcp_server_1.BaseMCPServer {
219
225
  */
220
226
  async generateFlowFromInstruction(args) {
221
227
  try {
222
- const { instruction } = args;
228
+ const { instruction, auto_deploy = true } = args;
223
229
  // Parse natural language to flow components
224
230
  const flowRequirements = await this.nlMapper.parseFlowRequirements(instruction);
225
231
  // Convert to IMPROVED flow definition
@@ -235,21 +241,128 @@ class ServiceNowXMLFlowMCP extends base_mcp_server_1.BaseMCPServer {
235
241
  tags: ['auto-generated'],
236
242
  activities: this.convertToImprovedActivities(flowRequirements)
237
243
  };
238
- // Use IMPROVED generator
239
- const result = (0, improved_flow_xml_generator_1.generateImprovedFlowXML)(flowDef);
244
+ // Use PRODUCTION-READY generator with proper Update Set structure
245
+ const result = (0, xml_first_flow_generator_1.generateProductionFlowXML)(flowDef);
246
+ let deploymentResult = null;
247
+ // 🚀 AUTO-DEPLOYMENT: Deploy immediately if requested
248
+ if (auto_deploy) {
249
+ try {
250
+ this.logger.info('🚀 AUTO-DEPLOYING XML to ServiceNow...');
251
+ // Check authentication
252
+ const isAuth = await this.oauth.isAuthenticated();
253
+ if (!isAuth) {
254
+ throw new Error('Not authenticated with ServiceNow. Please run: snow-flow auth login');
255
+ }
256
+ // Initialize ServiceNow client
257
+ const client = new ServiceNowClient();
258
+ // Read the XML file
259
+ const fs = require('fs').promises;
260
+ const xmlContent = await fs.readFile(result.filePath, 'utf-8');
261
+ // Import XML as remote update set
262
+ const importResponse = await client.makeRequest({
263
+ method: 'POST',
264
+ url: '/api/now/table/sys_remote_update_set',
265
+ headers: {
266
+ 'Content-Type': 'application/xml',
267
+ 'Accept': 'application/json'
268
+ },
269
+ data: xmlContent
270
+ });
271
+ if (!importResponse.result || !importResponse.result.sys_id) {
272
+ throw new Error('Failed to import XML update set');
273
+ }
274
+ const remoteUpdateSetId = importResponse.result.sys_id;
275
+ this.logger.info(`✅ XML imported successfully (sys_id: ${remoteUpdateSetId})`);
276
+ // Load the update set
277
+ await client.makeRequest({
278
+ method: 'PUT',
279
+ url: `/api/now/table/sys_remote_update_set/${remoteUpdateSetId}`,
280
+ data: {
281
+ state: 'loaded'
282
+ }
283
+ });
284
+ // Find the loaded update set
285
+ const loadedResponse = await client.makeRequest({
286
+ method: 'GET',
287
+ url: '/api/now/table/sys_update_set',
288
+ params: {
289
+ sysparm_query: `remote_sys_id=${remoteUpdateSetId}`,
290
+ sysparm_limit: 1
291
+ }
292
+ });
293
+ if (!loadedResponse.result || loadedResponse.result.length === 0) {
294
+ throw new Error('Failed to find loaded update set');
295
+ }
296
+ const updateSetId = loadedResponse.result[0].sys_id;
297
+ const updateSetName = loadedResponse.result[0].name;
298
+ // Preview the update set
299
+ await client.makeRequest({
300
+ method: 'POST',
301
+ url: `/api/now/table/sys_update_set/${updateSetId}/preview`
302
+ });
303
+ // Check for preview problems
304
+ const previewProblems = await client.makeRequest({
305
+ method: 'GET',
306
+ url: '/api/now/table/sys_update_preview_problem',
307
+ params: {
308
+ sysparm_query: `update_set=${updateSetId}`,
309
+ sysparm_limit: 100
310
+ }
311
+ });
312
+ if (previewProblems.result && previewProblems.result.length > 0) {
313
+ const problemsList = previewProblems.result.map((p) => `- ${p.type}: ${p.description}`).join('\n');
314
+ throw new Error(`Preview found problems:\n${problemsList}\n\nPlease review and resolve in ServiceNow UI`);
315
+ }
316
+ // Commit the update set
317
+ await client.makeRequest({
318
+ method: 'POST',
319
+ url: `/api/now/table/sys_update_set/${updateSetId}/commit`
320
+ });
321
+ deploymentResult = {
322
+ success: true,
323
+ message: '✅ XML automatically deployed to ServiceNow!',
324
+ update_set_id: updateSetId,
325
+ update_set_name: updateSetName,
326
+ steps_completed: [
327
+ '✅ XML imported as remote update set',
328
+ '✅ Update set loaded successfully',
329
+ '✅ Preview completed with no problems',
330
+ '✅ Update set committed successfully'
331
+ ]
332
+ };
333
+ this.logger.info('✅ Auto-deployment successful', deploymentResult);
334
+ }
335
+ catch (deployError) {
336
+ this.logger.warn('⚠️ Auto-deployment failed, providing manual instructions', deployError);
337
+ deploymentResult = {
338
+ success: false,
339
+ error: deployError instanceof Error ? deployError.message : String(deployError),
340
+ manual_command: `snow-flow deploy-xml ${result.filePath}`,
341
+ troubleshooting: [
342
+ '1. Check ServiceNow authentication: snow-flow auth status',
343
+ '2. Verify admin permissions in ServiceNow',
344
+ '3. Review XML file for format issues',
345
+ '4. Try manual deployment command above'
346
+ ]
347
+ };
348
+ }
349
+ }
240
350
  return {
241
351
  success: true,
242
352
  xml: args.save_to_file === false ? result.xml : undefined,
243
353
  file_path: result.filePath,
244
354
  flow_definition: flowDef,
245
- message: `✅ Generated IMPROVED flow XML from instruction: ${instruction}`,
355
+ deployment: deploymentResult,
356
+ message: `✅ Generated IMPROVED flow XML from instruction: ${instruction}${deploymentResult?.success ? ' + DEPLOYED!' : ''}`,
246
357
  improvements: [
247
358
  '✅ Production-ready Flow Designer format',
248
359
  '✅ Complete XML structure with all required fields',
249
360
  '✅ Base64+gzip encoded action values',
250
- '✅ Proper v2 table usage'
361
+ '✅ Proper v2 table usage',
362
+ ...(deploymentResult?.success ? ['✅ Automatically deployed to ServiceNow!'] : [])
251
363
  ],
252
- import_instructions: result.instructions
364
+ import_instructions: deploymentResult?.success ? 'Flow is already deployed and ready to use!' : result.instructions,
365
+ auto_deploy_command: deploymentResult?.manual_command || `snow-flow deploy-xml ${result.filePath}`
253
366
  };
254
367
  }
255
368
  catch (error) {
@@ -17,4 +17,3 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  // Re-export coordination framework types
19
19
  __exportStar(require("./snow-flow.types"), exports);
20
- __exportStar(require("../coordination/types"), exports);