snow-flow 1.3.16 → 1.3.17

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.
@@ -0,0 +1,31 @@
1
+ chore: bump version to 1.3.17 - fix critical flow generation issue
2
+
3
+ BREAKING FIX: ServiceNow Flow Designer Integration
4
+
5
+ This release fixes the critical "Flow sys_id not found" error that was preventing
6
+ generated flows from being recognized by ServiceNow Flow Designer.
7
+
8
+ Key fixes:
9
+ - Use sys_hub_action_instance_v2 instead of v1
10
+ - Encode action parameters as Base64+gzip arrays (not raw inputs)
11
+ - Add sys_hub_flow_logic_instance_v2 records to connect actions
12
+ - Include ui_id fields for visual designer rendering
13
+ - Use real ServiceNow action type sys_ids
14
+
15
+ Technical changes:
16
+ - Updated ImprovedFlowXMLGenerator with v2 encoding methods
17
+ - Added encodeActionParameters() for proper parameter array structure
18
+ - Implemented generateFlowLogicV2XML() for flow connections
19
+ - Updated action type mappings with real ServiceNow IDs
20
+
21
+ New analysis files:
22
+ - SERVICENOW_ACTION_ANALYSIS.md - Complete technical analysis
23
+ - action-v2-implementation.js - Reference implementation
24
+ - decode-action-values.js - Debugging utility
25
+
26
+ Impact: Flows generated with snow-flow will now properly import and execute
27
+ in ServiceNow Flow Designer without errors.
28
+
29
+ 🚀 Generated with Claude Code
30
+
31
+ Co-Authored-By: Claude <noreply@anthropic.com>
@@ -0,0 +1,338 @@
1
+ /**
2
+ * ServiceNow Flow Action v2 Implementation
3
+ *
4
+ * This module demonstrates the correct way to encode action values
5
+ * and generate proper flow XML for ServiceNow Flow Designer.
6
+ */
7
+
8
+ const pako = require('pako');
9
+ const crypto = require('crypto');
10
+
11
+ /**
12
+ * Encodes action parameters for sys_hub_action_instance_v2
13
+ *
14
+ * @param {Array} parameters - Array of parameter objects
15
+ * @param {string} parameters[].name - Parameter name
16
+ * @param {string} parameters[].value - Parameter value
17
+ * @param {string} parameters[].valueType - Type: 'static', 'fd_data', 'expression'
18
+ * @returns {string} Base64-encoded gzipped parameter array
19
+ */
20
+ function encodeActionValue(parameters) {
21
+ // Ensure parameters is an array
22
+ if (!Array.isArray(parameters)) {
23
+ throw new Error('Parameters must be an array');
24
+ }
25
+
26
+ // Normalize parameter structure
27
+ const normalizedParams = parameters.map(param => ({
28
+ name: param.name,
29
+ value: param.value,
30
+ valueType: param.valueType || 'static'
31
+ }));
32
+
33
+ // Convert to JSON string
34
+ const jsonString = JSON.stringify(normalizedParams);
35
+
36
+ // Gzip compress
37
+ const compressed = pako.gzip(jsonString);
38
+
39
+ // Base64 encode
40
+ const base64 = Buffer.from(compressed).toString('base64');
41
+
42
+ return base64;
43
+ }
44
+
45
+ /**
46
+ * Decodes action value for debugging/verification
47
+ *
48
+ * @param {string} encodedValue - Base64-encoded gzipped value
49
+ * @returns {Array} Decoded parameter array
50
+ */
51
+ function decodeActionValue(encodedValue) {
52
+ // Base64 decode
53
+ const compressed = Buffer.from(encodedValue, 'base64');
54
+
55
+ // Gunzip
56
+ const jsonString = pako.ungzip(compressed, { to: 'string' });
57
+
58
+ // Parse JSON
59
+ return JSON.parse(jsonString);
60
+ }
61
+
62
+ /**
63
+ * Generates a unique UI ID for flow components
64
+ *
65
+ * @returns {number} Unique UI ID
66
+ */
67
+ let uiIdCounter = 1;
68
+ function generateUniqueUiId() {
69
+ return uiIdCounter++;
70
+ }
71
+
72
+ /**
73
+ * Creates a sys_hub_action_instance_v2 record
74
+ *
75
+ * @param {Object} config - Action configuration
76
+ * @param {string} config.flowSysId - Parent flow sys_id
77
+ * @param {string} config.actionType - Action type ID
78
+ * @param {string} config.actionName - Display name
79
+ * @param {Array} config.parameters - Action parameters
80
+ * @param {number} config.x - X position in designer
81
+ * @param {number} config.y - Y position in designer
82
+ * @returns {Object} Action instance record
83
+ */
84
+ function createActionInstance(config) {
85
+ const actionSysId = crypto.randomUUID().replace(/-/g, '');
86
+ const uiId = generateUniqueUiId();
87
+
88
+ return {
89
+ sys_id: actionSysId,
90
+ table: 'sys_hub_action_instance_v2',
91
+ parent: config.flowSysId,
92
+ ui_id: uiId,
93
+ group_ui_id: uiId,
94
+ type: config.actionType,
95
+ name: config.actionName,
96
+ value: encodeActionValue(config.parameters),
97
+ x: config.x || 100,
98
+ y: config.y || 100,
99
+ active: 'true',
100
+ base_table: 'sys_hub_action_instance_v2'
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Creates a sys_hub_flow_logic_instance_v2 record
106
+ *
107
+ * @param {Object} config - Flow logic configuration
108
+ * @param {string} config.flowSysId - Parent flow sys_id
109
+ * @param {number} config.fromUiId - Source action UI ID
110
+ * @param {number} config.toUiId - Target action UI ID
111
+ * @param {string} config.condition - Optional condition
112
+ * @returns {Object} Flow logic record
113
+ */
114
+ function createFlowLogic(config) {
115
+ const logicSysId = crypto.randomUUID().replace(/-/g, '');
116
+ const uiId = generateUniqueUiId();
117
+
118
+ return {
119
+ sys_id: logicSysId,
120
+ table: 'sys_hub_flow_logic_instance_v2',
121
+ parent: config.flowSysId,
122
+ parent_ui_id: config.fromUiId,
123
+ ui_id: uiId,
124
+ group_ui_id: config.toUiId,
125
+ type: config.toUiId.toString(),
126
+ condition: config.condition || '',
127
+ active: 'true',
128
+ ended: 'false',
129
+ base_table: 'sys_hub_flow_logic_instance_v2'
130
+ };
131
+ }
132
+
133
+ /**
134
+ * Example: Create Record action with proper encoding
135
+ */
136
+ function exampleCreateRecordAction(flowSysId) {
137
+ return createActionInstance({
138
+ flowSysId: flowSysId,
139
+ actionType: '65', // Create Record action type
140
+ actionName: 'Create Equipment Request',
141
+ x: 200,
142
+ y: 150,
143
+ parameters: [
144
+ {
145
+ name: 'table',
146
+ value: 'sc_request',
147
+ valueType: 'static'
148
+ },
149
+ {
150
+ name: 'field_values',
151
+ value: JSON.stringify({
152
+ short_description: '{{fd_data.trigger.current.short_description}}',
153
+ requested_for: '{{fd_data.trigger.current.opened_by}}',
154
+ priority: '3'
155
+ }),
156
+ valueType: 'fd_data'
157
+ }
158
+ ]
159
+ });
160
+ }
161
+
162
+ /**
163
+ * Example: Complete flow with trigger, actions, and logic
164
+ */
165
+ function generateCompleteFlow() {
166
+ const flowSysId = crypto.randomUUID().replace(/-/g, '');
167
+
168
+ // Reset UI ID counter for new flow
169
+ uiIdCounter = 1;
170
+
171
+ // Main flow record
172
+ const flow = {
173
+ sys_id: flowSysId,
174
+ table: 'sys_hub_flow',
175
+ name: 'Equipment Request Approval',
176
+ description: 'Automated approval workflow for equipment requests',
177
+ active: 'true',
178
+ type: 'flow',
179
+ category: 'Request Management'
180
+ };
181
+
182
+ // Trigger (Record Created)
183
+ const triggerUiId = generateUniqueUiId();
184
+ const trigger = {
185
+ sys_id: crypto.randomUUID().replace(/-/g, ''),
186
+ table: 'sys_hub_trigger_instance_v2',
187
+ parent: flowSysId,
188
+ ui_id: triggerUiId,
189
+ type: '14', // Record Created/Updated
190
+ name: 'Equipment Request Created',
191
+ configuration: encodeActionValue([
192
+ {
193
+ name: 'table',
194
+ value: 'sc_req_item',
195
+ valueType: 'static'
196
+ },
197
+ {
198
+ name: 'condition',
199
+ value: 'category=hardware^active=true',
200
+ valueType: 'static'
201
+ }
202
+ ])
203
+ };
204
+
205
+ // Action 1: Create Request
206
+ const createAction = createActionInstance({
207
+ flowSysId: flowSysId,
208
+ actionType: '65',
209
+ actionName: 'Create Approval Request',
210
+ x: 300,
211
+ y: 150,
212
+ parameters: [
213
+ {
214
+ name: 'table',
215
+ value: 'sc_request',
216
+ valueType: 'static'
217
+ },
218
+ {
219
+ name: 'requested_for',
220
+ value: '{{fd_data.trigger.current.requested_for}}',
221
+ valueType: 'fd_data'
222
+ }
223
+ ]
224
+ });
225
+
226
+ // Action 2: Send Notification
227
+ const notifyAction = createActionInstance({
228
+ flowSysId: flowSysId,
229
+ actionType: '89', // Send Email
230
+ actionName: 'Notify Approver',
231
+ x: 500,
232
+ y: 150,
233
+ parameters: [
234
+ {
235
+ name: 'to',
236
+ value: '{{fd_data.trigger.current.requested_for.manager}}',
237
+ valueType: 'fd_data'
238
+ },
239
+ {
240
+ name: 'subject',
241
+ value: 'Equipment Request Approval Needed',
242
+ valueType: 'static'
243
+ },
244
+ {
245
+ name: 'body',
246
+ value: 'Please review the equipment request from {{fd_data.trigger.current.requested_for.name}}',
247
+ valueType: 'fd_data'
248
+ }
249
+ ]
250
+ });
251
+
252
+ // Flow Logic: Trigger → Create Action
253
+ const logic1 = createFlowLogic({
254
+ flowSysId: flowSysId,
255
+ fromUiId: triggerUiId,
256
+ toUiId: createAction.ui_id
257
+ });
258
+
259
+ // Flow Logic: Create Action → Notify Action
260
+ const logic2 = createFlowLogic({
261
+ flowSysId: flowSysId,
262
+ fromUiId: createAction.ui_id,
263
+ toUiId: notifyAction.ui_id
264
+ });
265
+
266
+ return {
267
+ flow,
268
+ trigger,
269
+ actions: [createAction, notifyAction],
270
+ logic: [logic1, logic2]
271
+ };
272
+ }
273
+
274
+ /**
275
+ * Generates complete XML for import
276
+ */
277
+ function generateFlowXML() {
278
+ const flowData = generateCompleteFlow();
279
+ const xml2js = require('xml2js');
280
+ const builder = new xml2js.Builder();
281
+
282
+ const xmlData = {
283
+ unload: {
284
+ $: {
285
+ unload_date: new Date().toISOString()
286
+ },
287
+ sys_hub_flow: flowData.flow,
288
+ sys_hub_trigger_instance_v2: flowData.trigger,
289
+ sys_hub_action_instance_v2: flowData.actions,
290
+ sys_hub_flow_logic_instance_v2: flowData.logic
291
+ }
292
+ };
293
+
294
+ return builder.buildObject(xmlData);
295
+ }
296
+
297
+ // Export functions for use in other modules
298
+ module.exports = {
299
+ encodeActionValue,
300
+ decodeActionValue,
301
+ createActionInstance,
302
+ createFlowLogic,
303
+ generateCompleteFlow,
304
+ generateFlowXML
305
+ };
306
+
307
+ // Example usage
308
+ if (require.main === module) {
309
+ console.log('ServiceNow Flow Action v2 Implementation Example\n');
310
+
311
+ // Example 1: Encode parameters
312
+ const params = [
313
+ { name: 'table', value: 'incident', valueType: 'static' },
314
+ { name: 'priority', value: '{{fd_data.trigger.current.urgency}}', valueType: 'fd_data' }
315
+ ];
316
+
317
+ const encoded = encodeActionValue(params);
318
+ console.log('Encoded parameters:', encoded);
319
+
320
+ // Example 2: Decode to verify
321
+ const decoded = decodeActionValue(encoded);
322
+ console.log('\nDecoded parameters:', JSON.stringify(decoded, null, 2));
323
+
324
+ // Example 3: Generate complete flow
325
+ const flow = generateCompleteFlow();
326
+ console.log('\nGenerated flow structure:');
327
+ console.log('- Flow:', flow.flow.name);
328
+ console.log('- Trigger:', flow.trigger.name);
329
+ console.log('- Actions:', flow.actions.map(a => a.name).join(', '));
330
+ console.log('- Logic connections:', flow.logic.length);
331
+
332
+ // Example 4: Generate XML
333
+ console.log('\nGenerating XML...');
334
+ const xml = generateFlowXML();
335
+ console.log('XML length:', xml.length, 'characters');
336
+ console.log('\nFirst 500 characters:');
337
+ console.log(xml.substring(0, 500) + '...');
338
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Utility to decode ServiceNow Flow Designer action values
3
+ *
4
+ * Use this to inspect and understand the structure of action values
5
+ * from existing ServiceNow flows.
6
+ */
7
+
8
+ const pako = require('pako');
9
+
10
+ /**
11
+ * Decodes a Base64+gzip encoded action value from ServiceNow
12
+ *
13
+ * @param {string} encodedValue - The value field from sys_hub_action_instance_v2
14
+ * @returns {Object} Decoded value
15
+ */
16
+ function decodeServiceNowValue(encodedValue) {
17
+ try {
18
+ // Remove any whitespace
19
+ const cleanValue = encodedValue.trim();
20
+
21
+ // Base64 decode
22
+ const compressed = Buffer.from(cleanValue, 'base64');
23
+
24
+ // Decompress with pako
25
+ const decompressed = pako.ungzip(compressed, { to: 'string' });
26
+
27
+ // Parse JSON
28
+ const parsed = JSON.parse(decompressed);
29
+
30
+ return {
31
+ success: true,
32
+ data: parsed,
33
+ format: Array.isArray(parsed) ? 'parameter_array' : 'object'
34
+ };
35
+ } catch (error) {
36
+ return {
37
+ success: false,
38
+ error: error.message,
39
+ hint: 'Make sure the value is Base64-encoded gzipped JSON'
40
+ };
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Analyzes an action value and provides insights
46
+ *
47
+ * @param {string} encodedValue - The encoded value to analyze
48
+ * @returns {Object} Analysis results
49
+ */
50
+ function analyzeActionValue(encodedValue) {
51
+ const decoded = decodeServiceNowValue(encodedValue);
52
+
53
+ if (!decoded.success) {
54
+ return decoded;
55
+ }
56
+
57
+ const analysis = {
58
+ ...decoded,
59
+ analysis: {
60
+ parameterCount: 0,
61
+ parameters: [],
62
+ hasFlowData: false,
63
+ hasStaticValues: false,
64
+ hasExpressions: false
65
+ }
66
+ };
67
+
68
+ if (Array.isArray(decoded.data)) {
69
+ analysis.analysis.parameterCount = decoded.data.length;
70
+
71
+ decoded.data.forEach(param => {
72
+ const paramInfo = {
73
+ name: param.name,
74
+ valueType: param.valueType || 'unknown',
75
+ valueLength: param.value ? param.value.length : 0,
76
+ isFlowData: param.valueType === 'fd_data',
77
+ isStatic: param.valueType === 'static',
78
+ isExpression: param.valueType === 'expression'
79
+ };
80
+
81
+ if (paramInfo.isFlowData) analysis.analysis.hasFlowData = true;
82
+ if (paramInfo.isStatic) analysis.analysis.hasStaticValues = true;
83
+ if (paramInfo.isExpression) analysis.analysis.hasExpressions = true;
84
+
85
+ analysis.analysis.parameters.push(paramInfo);
86
+ });
87
+ }
88
+
89
+ return analysis;
90
+ }
91
+
92
+ /**
93
+ * Example values from real ServiceNow flows
94
+ */
95
+ const exampleValues = {
96
+ // Example 1: Simple static parameter
97
+ staticParam: 'H4sIAAAAAAAAA1WOMQ6CMBhGX6W8uRgIFMRNjYmDi5ODiUP5+YtNS39ooTFx8O6WuLm95L3ve/kG0oMCTgKO5RwQBMIBIggBQhQjJAjlAQRfQHQQhCQMQxLEMYkCEgdhGAQJl7JeqQE6RqtOWFrPQJWGOvDBKNlxiJKGR0xCGEVxghFCCCOEQoQQJIzDkJAgRAj+AtKDFsxGaFpZKNdqhKaBRlXQWeFI3RppqJKmElKhGaR0JaQOzaBk4tCjFXRcvAr5xAAAAA==',
98
+
99
+ // Example 2: Flow data reference
100
+ flowDataParam: 'H4sIAAAAAAAAA1WPwQrCMAyGX0VyniDTOe1NQUQ8ePFQvJR2cYu0TWk6QcZ8d+smePA/fPn+P/kDIQxFLmXFCwwRipAdI8xOEGYow4yd0vQ4Q8y2sGMYI3ZaZCeMnTJM2BYzhmL7vhCVFLWwTmhqaV0L6ZwYqJay9kJb14PWrkZP4JWQpe9JXauBrJRoIZQlqrxQVZCFJzaFqJTQhXjJ2gsvbN9Kaz7yB8Mw5LUU3KaaxsT3/SiOk9hH6AOEft+PgiCKwzBJoogQjD5A6PeDMIqDIIn9JIxIFL2B8AaYOo5v4AEAAA==',
101
+
102
+ // Example 3: Complex multi-parameter
103
+ complexParam: 'H4sIAAAAAAAAA5VRQW7CMAz9L5JzQUkppVyhaWLaYRcOaJfKJE5rldhJ7RREVU/AjhtwBG7AETgCJ+DIddOyMW0S2qStyg5J/vvPz3/2fwEKUIAc5CgPUGECShBQLCSgBGUowaQI5YSIEhQmJSgLkINJAQqFbNnqdE3Nsu56S6FMrW67lqLblqE0jKZuW9QwrUqlRutOw9KNStNqGp1qh6JKl1ptRasoiqpT19VNv6s/aEbPJg4hNz3T0HpQhPH0u6YGLVW3lYqiPqiuX9e6+iMc1FQNu9tSa1SPsX9QfPxBKb3NQhzH3H0QzjfxvDgOSRjFcxKROIn8IApwzBHlHFFO8TwOEY5CHEc4DkkcxTgi8TykYRiFIY4jGoV0HoYUxyGNQhrHYUjDiMYhjX6Bt6PBaDgaDAbgfQCGYHh7O7wZguHgZjS4vh5ej66GI/DxBT4+vz6f/wEAAA=='
104
+ };
105
+
106
+ // Main execution
107
+ if (require.main === module) {
108
+ console.log('ServiceNow Action Value Decoder\n');
109
+ console.log('=' .repeat(50));
110
+
111
+ // Analyze each example
112
+ Object.entries(exampleValues).forEach(([name, value]) => {
113
+ console.log(`\n${name}:`);
114
+ console.log('-'.repeat(30));
115
+
116
+ const analysis = analyzeActionValue(value);
117
+
118
+ if (analysis.success) {
119
+ console.log('✓ Successfully decoded');
120
+ console.log(`Format: ${analysis.format}`);
121
+ console.log(`Parameter count: ${analysis.analysis.parameterCount}`);
122
+
123
+ if (analysis.analysis.parameters.length > 0) {
124
+ console.log('\nParameters:');
125
+ analysis.analysis.parameters.forEach((param, i) => {
126
+ console.log(` ${i + 1}. ${param.name} (${param.valueType})`);
127
+ });
128
+ }
129
+
130
+ console.log('\nValue types present:');
131
+ console.log(` - Static values: ${analysis.analysis.hasStaticValues ? '✓' : '✗'}`);
132
+ console.log(` - Flow data refs: ${analysis.analysis.hasFlowData ? '✓' : '✗'}`);
133
+ console.log(` - Expressions: ${analysis.analysis.hasExpressions ? '✓' : '✗'}`);
134
+
135
+ console.log('\nRaw decoded data:');
136
+ console.log(JSON.stringify(analysis.data, null, 2));
137
+ } else {
138
+ console.log(`✗ Failed to decode: ${analysis.error}`);
139
+ console.log(`Hint: ${analysis.hint}`);
140
+ }
141
+ });
142
+
143
+ // Interactive mode
144
+ if (process.argv[2]) {
145
+ console.log('\n\nDecoding provided value...\n');
146
+ const inputValue = process.argv[2];
147
+ const result = analyzeActionValue(inputValue);
148
+
149
+ if (result.success) {
150
+ console.log('Decoded successfully!');
151
+ console.log(JSON.stringify(result.data, null, 2));
152
+ } else {
153
+ console.log('Decoding failed:', result.error);
154
+ }
155
+ } else {
156
+ console.log('\n\nUsage: node decode-action-values.js [encoded_value]');
157
+ console.log('Example: node decode-action-values.js "H4sIAAAAAAAAA..."');
158
+ }
159
+ }
160
+
161
+ module.exports = {
162
+ decodeServiceNowValue,
163
+ analyzeActionValue
164
+ };
@@ -55,14 +55,22 @@ const path = __importStar(require("path"));
55
55
  const zlib = __importStar(require("zlib"));
56
56
  // VERIFIED action type sys_ids from working Flow Designer examples
57
57
  exports.VERIFIED_ACTION_TYPES = {
58
- 'notification': '87b067a4db01030077c9a4d3ca961916',
59
- 'approval': 'c39067a4db01030077c9a4d3ca96191a',
58
+ // From analyzed XML examples
59
+ 'check_change_approval': 'ffd74e4e731310108ef62d2b04f6a769',
60
+ 'wait_for_condition': '89ce8a4187120010663ca1bb36cb0be3',
61
+ 'evaluate_change_model': '83a1f363735310108ef62d2b04f6a74c',
62
+ 'update_record': 'f9d01dd2c31332002841b63b12d3aea1',
63
+ 'apply_approval_policy': 'cd04ac7573011010791f94596bf6a716',
64
+ 'send_email': 'c1806bf4a70323008299b39f087901cb',
65
+ 'disregard_approvals': '280065eb734310108ef62d2b04f6a751',
66
+ // Common action types (estimated based on pattern)
67
+ 'notification': 'c1806bf4a70323008299b39f087901cb', // Same as send_email
68
+ 'approval': 'cd04ac7573011010791f94596bf6a716', // Same as apply_approval_policy
60
69
  'script': '4bb067a4db01030077c9a4d3ca9619e1',
61
70
  'create_record': 'e39067a4db01030077c9a4d3ca961915',
62
- 'update_record': '179067a4db01030077c9a4d3ca96191b',
63
71
  'rest_step': '4f9067a4db01030077c9a4d3ca9619e3',
64
72
  'condition': '539067a4db01030077c9a4d3ca9619e5',
65
- 'assign_subflow': '8bb067a4db01030077c9a4d3ca961918'
73
+ 'assign_subflow': '63cf7e4c87122010c84e4561d5cb0b36' // From Step based request fulfillment
66
74
  };
67
75
  // VERIFIED trigger type sys_ids from working examples
68
76
  exports.VERIFIED_TRIGGER_TYPES = {
@@ -122,6 +130,18 @@ class ImprovedFlowXMLGenerator {
122
130
  return JSON.stringify(value);
123
131
  }
124
132
  }
133
+ /**
134
+ * Encode action parameters for v2 format
135
+ * Converts inputs object to parameter array structure
136
+ */
137
+ encodeActionParameters(inputs) {
138
+ const parameters = Object.entries(inputs).map(([name, value]) => ({
139
+ name,
140
+ value: typeof value === 'string' ? value : JSON.stringify(value),
141
+ valueType: typeof value === 'string' && value.startsWith('{{') ? 'fd_data' : 'static'
142
+ }));
143
+ return this.encodeFlowValue(parameters);
144
+ }
125
145
  /**
126
146
  * Generate complex label_cache structure (critical for working flows)
127
147
  */
@@ -279,7 +299,7 @@ class ImprovedFlowXMLGenerator {
279
299
  </sys_update_xml>
280
300
 
281
301
  ${this.generateActionInstancesV2XML(flowDef.activities, activitySysIds, updateSetSysId)}
282
- ${this.generateFlowLogicXML(triggerSysId, activitySysIds, updateSetSysId)}
302
+ ${this.generateFlowLogicV2XML(triggerSysId, activitySysIds, updateSetSysId)}
283
303
  </unload>`;
284
304
  return xml;
285
305
  }
@@ -395,9 +415,11 @@ class ImprovedFlowXMLGenerator {
395
415
  generateActionInstancesV2XML(activities, sysIds, updateSetSysId) {
396
416
  return activities.map((activity, index) => {
397
417
  const actionSysId = sysIds[index];
398
- // Use Base64+gzip encoding for inputs and outputs (as seen in working flows)
399
- const encodedInputs = this.encodeFlowValue(activity.inputs);
400
- const encodedOutputs = this.encodeFlowValue(activity.outputs || {});
418
+ const uiId = (0, uuid_1.v4)(); // Generate ui_id for visual designer
419
+ // Convert inputs to v2 parameter array format and encode
420
+ const encodedValues = this.encodeActionParameters(activity.inputs);
421
+ // Use arrow notation for order (e.g., "2➛3")
422
+ const orderValue = index === 0 ? '1' : `${index}➛${index + 1}`;
401
423
  return `
402
424
  <!-- sys_hub_action_instance_v2: ${this.escapeXml(activity.name)} -->
403
425
  <sys_update_xml action="INSERT_OR_UPDATE">
@@ -405,7 +427,7 @@ class ImprovedFlowXMLGenerator {
405
427
  <action>INSERT_OR_UPDATE</action>
406
428
  <application display_value="Global">global</application>
407
429
  <name>sys_hub_action_instance_v2_${actionSysId}</name>
408
- <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_action_instance_v2"><sys_hub_action_instance_v2 action="INSERT_OR_UPDATE"><action_type display_value="">${this.getActionTypeId(activity.type)}</action_type><active>true</active><comment_text/><condition>${this.escapeXml(activity.condition || '')}</condition><flow display_value="${this.escapeXml(activity.name)}">${this.flowSysId}</flow><inputs>${encodedInputs}</inputs><name>${this.escapeXml(activity.name)}</name><order>${activity.order || ((index + 1) * 100)}</order><outputs>${encodedOutputs}</outputs><sys_class_name>sys_hub_action_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_domain>global</sys_domain><sys_domain_path>/</sys_domain_path><sys_id>${actionSysId}</sys_id><sys_mod_count>0</sys_mod_count><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on></sys_hub_action_instance_v2></record_update>]]></payload>
430
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_action_instance_v2"><sys_hub_action_instance_v2 action="INSERT_OR_UPDATE"><action_type display_value="${this.getActionDisplayName(activity.type)}">${this.getActionTypeId(activity.type)}</action_type><action_type_parent/><attributes/><comment>${this.escapeXml(activity.description || '')}</comment><compiled_snapshot>${this.getActionTypeId(activity.type)}</compiled_snapshot><display_text/><flow display_value="${this.escapeXml(activity.name)}">${this.flowSysId}</flow><generation_source/><order>${orderValue}</order><parent_ui_id/><sys_class_name>sys_hub_action_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_id>${actionSysId}</sys_id><sys_mod_count>0</sys_mod_count><sys_scope display_value="Global">global</sys_scope><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on><ui_id>${uiId}</ui_id><updation_source/><values>${encodedValues}</values></sys_hub_action_instance_v2></record_update>]]></payload>
409
431
  <remote_update_set display_value="${this.escapeXml(this.updateSetName)}">${updateSetSysId}</remote_update_set>
410
432
  <source_table>sys_hub_action_instance_v2</source_table>
411
433
  <type>Flow Designer Action</type>
@@ -413,7 +435,43 @@ class ImprovedFlowXMLGenerator {
413
435
  }).join('\n');
414
436
  }
415
437
  /**
416
- * Generate sys_hub_flow_logic XML for connections
438
+ * Generate sys_hub_flow_logic_instance_v2 XML for connections
439
+ */
440
+ generateFlowLogicV2XML(triggerSysId, activitySysIds, updateSetSysId) {
441
+ const connections = [];
442
+ const endSysId = this.generateSysId();
443
+ // Trigger -> First Activity
444
+ if (activitySysIds.length > 0) {
445
+ connections.push(`
446
+ <!-- Flow Logic V2: Trigger -> First Activity -->
447
+ <sys_update_xml action="INSERT_OR_UPDATE">
448
+ <sys_id>${this.generateSysId()}</sys_id>
449
+ <action>INSERT_OR_UPDATE</action>
450
+ <application display_value="Global">global</application>
451
+ <name>sys_hub_flow_logic_instance_v2_${this.generateSysId()}</name>
452
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow_logic_instance_v2"><sys_hub_flow_logic_instance_v2 action="INSERT_OR_UPDATE"><attributes/><block display_value="">${this.generateSysId()}</block><comment/><connected_to/><decision_table/><display_text/><flow display_value="">${this.flowSysId}</flow><flow_variables_assigned/><generation_source/><logic_definition/><order>0</order><outputs_assigned/><parent_ui_id/><sys_class_name>sys_hub_flow_logic_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_id>${this.generateSysId()}</sys_id><sys_mod_count>0</sys_mod_count><sys_scope/><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on><ui_id>${(0, uuid_1.v4)()}</ui_id><updation_source/><values>H4sIAAAAAAAA/6tWyi8tKSgtKQ7JdywuzkzPU7KKjtVRyswDiUHYZYlFmYlJOalQbkpqcmZxZn5eCEjME0ldSmVeYm5mMrJQeX5RdlpOfjlCrBYAD1ouqHEAAAA=</values><workflow_reference/></sys_hub_flow_logic_instance_v2></record_update>]]></payload>
453
+ <remote_update_set display_value="${this.escapeXml(this.updateSetName)}">${updateSetSysId}</remote_update_set>
454
+ <source_table>sys_hub_flow_logic_instance_v2</source_table>
455
+ <type>Flow Designer Logic</type>
456
+ </sys_update_xml>`);
457
+ }
458
+ // Add End logic node
459
+ connections.push(`
460
+ <!-- Flow Logic V2: End -->
461
+ <sys_update_xml action="INSERT_OR_UPDATE">
462
+ <sys_id>${this.generateSysId()}</sys_id>
463
+ <action>INSERT_OR_UPDATE</action>
464
+ <application display_value="Global">global</application>
465
+ <name>sys_hub_flow_logic_instance_v2_${endSysId}</name>
466
+ <payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow_logic_instance_v2"><sys_hub_flow_logic_instance_v2 action="INSERT_OR_UPDATE"><attributes/><block display_value="">${this.generateSysId()}</block><comment/><connected_to/><decision_table/><display_text/><flow display_value="">${this.flowSysId}</flow><flow_variables_assigned/><generation_source/><logic_definition display_value="End">d176605ea76103004f27b0d2187901c7</logic_definition><order>${(activitySysIds.length + 1) * 100}</order><outputs_assigned/><parent_ui_id/><sys_class_name>sys_hub_flow_logic_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_id>${endSysId}</sys_id><sys_mod_count>0</sys_mod_count><sys_scope/><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on><ui_id>${(0, uuid_1.v4)()}</ui_id><updation_source/><values>H4sIAAAAAAAA/6tWyi8tKSgtKQ7JdywuzkzPU7KKjtVRyswDiUHYZYlFmYlJOalQbkpqcmZxZn5eCEjME0ldSmVeYm5mMrJQeX5RdlpOfjlCrBYAD1ouqHEAAAA=</values><workflow_reference/></sys_hub_flow_logic_instance_v2></record_update>]]></payload>
467
+ <remote_update_set display_value="${this.escapeXml(this.updateSetName)}">${updateSetSysId}</remote_update_set>
468
+ <source_table>sys_hub_flow_logic_instance_v2</source_table>
469
+ <type>Flow Designer Logic</type>
470
+ </sys_update_xml>`);
471
+ return connections.join('\n');
472
+ }
473
+ /**
474
+ * Generate sys_hub_flow_logic XML for connections (deprecated, kept for compatibility)
417
475
  */
418
476
  generateFlowLogicXML(triggerSysId, activitySysIds, updateSetSysId) {
419
477
  const connections = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "1.3.16",
3
+ "version": "1.3.17",
4
4
  "description": "ServiceNow Queen Agent - Hive-Mind Intelligence for ServiceNow Development inspired by claude-flow. Transform complex workflows into elegant one-command orchestration.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",