snow-flow-test 10.0.1-test.199 → 10.0.1-test.200

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.1-test.199",
3
+ "version": "10.0.1-test.200",
4
4
  "name": "snow-flow-test",
5
5
  "description": "Snow-Flow Test - ServiceNow Multi-Agent Development Framework",
6
6
  "license": "Elastic-2.0",
@@ -110,6 +110,21 @@ async function executeFlowPatchMutation(
110
110
  return resp.data?.data?.global?.snFlowDesigner?.flow || resp.data;
111
111
  }
112
112
 
113
+ /**
114
+ * Release the Flow Designer editing lock on a flow.
115
+ * The UI calls safeEdit(delete: flowId) when closing the editor.
116
+ * Without this, the flow remains locked to the API user forever.
117
+ */
118
+ async function releaseFlowEditingLock(client: any, flowId: string): Promise<boolean> {
119
+ try {
120
+ var mutation = 'mutation { global { snFlowDesigner { safeEdit(safeEditInput: {delete: "' + flowId + '"}) { deleteResult { deleteSuccess id __typename } __typename } __typename } __typename } }';
121
+ var resp = await client.post('/api/now/graphql', { variables: {}, query: mutation });
122
+ return resp.data?.data?.global?.snFlowDesigner?.safeEdit?.deleteResult?.deleteSuccess === true;
123
+ } catch (_) {
124
+ return false;
125
+ }
126
+ }
127
+
113
128
  /** Safely extract a string from a ServiceNow Table API value (handles reference objects like {value, link}). */
114
129
  const str = (val: any): string =>
115
130
  typeof val === 'object' && val !== null ? (val.display_value || val.value || '') : (val || '');
@@ -1662,7 +1677,7 @@ async function transformActionInputsForRecordAction(
1662
1677
  resolvedInputs: Record<string, string>,
1663
1678
  actionParams: any[],
1664
1679
  uuid: string
1665
- ): Promise<{ inputs: any[]; labelCacheEntries: any[]; steps: any }> {
1680
+ ): Promise<{ inputs: any[]; labelCacheUpdates: any[]; labelCacheInserts: any[]; steps: any }> {
1666
1681
  var steps: any = {};
1667
1682
 
1668
1683
  // Detect if this is a record action: must have both `record` and `table_name` parameters
@@ -1673,7 +1688,7 @@ async function transformActionInputsForRecordAction(
1673
1688
 
1674
1689
  if (!hasRecord || !hasTableName) {
1675
1690
  steps.record_action = false;
1676
- return { inputs: actionInputs, labelCacheEntries: [], steps };
1691
+ return { inputs: actionInputs, labelCacheUpdates: [], labelCacheInserts: [], steps };
1677
1692
  }
1678
1693
  steps.record_action = true;
1679
1694
 
@@ -2580,7 +2595,18 @@ export const toolDefinition: MCPToolDefinition = {
2580
2595
  },
2581
2596
  logic_type: {
2582
2597
  type: 'string',
2583
- description: 'Flow logic type for add_flow_logic. Looked up dynamically in sys_hub_flow_logic_definition. Common values: IF, ELSE, FOR_EACH, DO_UNTIL, SWITCH. IMPORTANT: ELSE blocks require connected_to set to the If block\'s uiUniqueIdentifier. IF does NOT require an Else block — only add Else if explicitly requested.'
2598
+ description: 'Flow logic type for add_flow_logic. Looked up dynamically in sys_hub_flow_logic_definition. Available types: ' +
2599
+ 'IF, ELSEIF, ELSE — conditional branching. Use ELSEIF (not nested ELSE+IF) for else-if branches. ELSE and ELSEIF require connected_to set to the If block\'s uiUniqueIdentifier. ' +
2600
+ 'FOR_EACH, DO_UNTIL — loops. SKIP_ITERATION and EXIT_LOOP can be used inside loops. ' +
2601
+ 'PARALLEL — execute branches in parallel. ' +
2602
+ 'DECISION — switch/decision table. ' +
2603
+ 'TRY — error handling (try/catch). ' +
2604
+ 'END — End Flow (stops execution). Always add END as the last element when the flow should terminate cleanly. ' +
2605
+ 'TIMER — Wait for a duration of time. ' +
2606
+ 'GO_BACK_TO — jump back to a previous step. ' +
2607
+ 'SET_FLOW_VARIABLES, APPEND_FLOW_VARIABLES, GET_FLOW_OUTPUT — flow variable management. ' +
2608
+ 'WORKFLOW — call a legacy workflow. DYNAMIC_FLOW — dynamically invoke a flow. ' +
2609
+ 'Best practice: add an END element at the end of your flow for clean termination.'
2584
2610
  },
2585
2611
  logic_inputs: {
2586
2612
  type: 'object',
@@ -3067,6 +3093,12 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3067
3093
  }
3068
3094
  }
3069
3095
 
3096
+ // Release Flow Designer editing lock (safeEdit delete) so users can edit the flow in the UI
3097
+ if (flowSysId) {
3098
+ var lockReleased = await releaseFlowEditingLock(client, flowSysId);
3099
+ diagnostics.editing_lock_released = lockReleased;
3100
+ }
3101
+
3070
3102
  return createSuccessResult({
3071
3103
  created: true,
3072
3104
  method: usedMethod,
@@ -3448,6 +3480,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3448
3480
  addTrigSummary.error('Failed to add trigger: ' + (addTrigResult.error || 'unknown'));
3449
3481
  }
3450
3482
 
3483
+ await releaseFlowEditingLock(client, addTrigFlowId);
3451
3484
  return addTrigResult.success
3452
3485
  ? createSuccessResult({ action: 'add_trigger', ...addTrigResult }, {}, addTrigSummary.build())
3453
3486
  : createErrorResult(addTrigResult.error || 'Failed to add trigger');
@@ -3511,6 +3544,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3511
3544
  updTrigSummary.error('Failed to update trigger: ' + (updTrigResult.error || 'unknown'));
3512
3545
  }
3513
3546
 
3547
+ await releaseFlowEditingLock(client, updTrigFlowId);
3514
3548
  return updTrigResult.success
3515
3549
  ? createSuccessResult({ action: 'update_trigger', steps: updTrigSteps }, {}, updTrigSummary.build())
3516
3550
  : createErrorResult(updTrigResult.error || 'Failed to update trigger');
@@ -3542,6 +3576,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3542
3576
  addActSummary.error('Failed to add action: ' + (addActResult.error || 'unknown'));
3543
3577
  }
3544
3578
 
3579
+ await releaseFlowEditingLock(client, addActFlowId);
3545
3580
  return addActResult.success
3546
3581
  ? createSuccessResult({ action: 'add_action', ...addActResult }, {}, addActSummary.build())
3547
3582
  : createErrorResult(addActResult.error || 'Failed to add action');
@@ -3555,7 +3590,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3555
3590
  throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'flow_id is required for add_flow_logic');
3556
3591
  }
3557
3592
  if (!args.logic_type) {
3558
- throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'logic_type is required for add_flow_logic (e.g. IF, FOR_EACH, DO_UNTIL, SWITCH)');
3593
+ throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'logic_type is required for add_flow_logic (e.g. IF, ELSEIF, ELSE, FOR_EACH, DO_UNTIL, PARALLEL, DECISION, TRY, END, TIMER, SET_FLOW_VARIABLES)');
3559
3594
  }
3560
3595
  var addLogicFlowId = await resolveFlowId(client, args.flow_id);
3561
3596
  var addLogicType = args.logic_type;
@@ -3578,6 +3613,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3578
3613
  addLogicSummary.error('Failed to add flow logic: ' + (addLogicResult.error || 'unknown'));
3579
3614
  }
3580
3615
 
3616
+ await releaseFlowEditingLock(client, addLogicFlowId);
3581
3617
  return addLogicResult.success
3582
3618
  ? createSuccessResult({ action: 'add_flow_logic', ...addLogicResult }, {}, addLogicSummary.build())
3583
3619
  : createErrorResult(addLogicResult.error || 'Failed to add flow logic');
@@ -3612,6 +3648,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3612
3648
  addSubSummary.error('Failed to add subflow call: ' + (addSubResult.error || 'unknown'));
3613
3649
  }
3614
3650
 
3651
+ await releaseFlowEditingLock(client, addSubFlowId);
3615
3652
  return addSubResult.success
3616
3653
  ? createSuccessResult({ action: 'add_subflow', ...addSubResult }, {}, addSubSummary.build())
3617
3654
  : createErrorResult(addSubResult.error || 'Failed to add subflow call');
@@ -3637,6 +3674,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3637
3674
  } else {
3638
3675
  updElemSummary.error('Failed to update element: ' + (updElemResult.error || 'unknown'));
3639
3676
  }
3677
+ await releaseFlowEditingLock(client, updElemFlowId);
3640
3678
  return updElemResult.success
3641
3679
  ? createSuccessResult({ action, ...updElemResult }, {}, updElemSummary.build())
3642
3680
  : createErrorResult(updElemResult.error || 'Failed to update element');
@@ -3668,6 +3706,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
3668
3706
  } else {
3669
3707
  delSummary.error('Failed to delete element: ' + (delResult.error || 'unknown'));
3670
3708
  }
3709
+ await releaseFlowEditingLock(client, delElemFlowId);
3671
3710
  return delResult.success
3672
3711
  ? createSuccessResult({ action, ...delResult }, {}, delSummary.build())
3673
3712
  : createErrorResult(delResult.error || 'Failed to delete element');