snow-flow 10.0.1-dev.486 → 10.0.1-dev.488
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
|
@@ -1917,6 +1917,27 @@ async function addFlowLogicViaGraphQL(
|
|
|
1917
1917
|
): Promise<{ success: boolean; logicId?: string; uiUniqueIdentifier?: string; steps?: any; error?: string }> {
|
|
1918
1918
|
const steps: any = {};
|
|
1919
1919
|
|
|
1920
|
+
// Normalize common aliases to actual ServiceNow flow logic type values
|
|
1921
|
+
var LOGIC_TYPE_ALIASES: Record<string, string> = {
|
|
1922
|
+
'FOR_EACH': 'FOREACH',
|
|
1923
|
+
'DO_UNTIL': 'DOUNTIL',
|
|
1924
|
+
'ELSE_IF': 'ELSEIF',
|
|
1925
|
+
'SKIP_ITERATION': 'CONTINUE',
|
|
1926
|
+
'EXIT_LOOP': 'BREAK',
|
|
1927
|
+
'GO_BACK_TO': 'GOBACKTO',
|
|
1928
|
+
'DYNAMIC_FLOW': 'DYNAMICFLOW',
|
|
1929
|
+
'END_FLOW': 'END',
|
|
1930
|
+
'GET_FLOW_OUTPUT': 'GETFLOWOUTPUT',
|
|
1931
|
+
'GET_FLOW_OUTPUTS': 'GETFLOWOUTPUT',
|
|
1932
|
+
'SET_FLOW_VARIABLES': 'SETFLOWVARIABLES',
|
|
1933
|
+
'APPEND_FLOW_VARIABLES': 'APPENDFLOWVARIABLES',
|
|
1934
|
+
};
|
|
1935
|
+
var normalizedType = LOGIC_TYPE_ALIASES[logicType.toUpperCase()] || logicType;
|
|
1936
|
+
if (normalizedType !== logicType) {
|
|
1937
|
+
steps.type_normalized = { from: logicType, to: normalizedType };
|
|
1938
|
+
logicType = normalizedType;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1920
1941
|
// Dynamically look up flow logic definition in sys_hub_flow_logic_definition
|
|
1921
1942
|
// Fetch extra fields needed for the flowLogicDefinition object in the mutation
|
|
1922
1943
|
const defFields = 'sys_id,type,name,description,order,attributes,compilation_class,quiescence,visible,category,connected_to';
|
|
@@ -1924,7 +1945,7 @@ async function addFlowLogicViaGraphQL(
|
|
|
1924
1945
|
let defName = '';
|
|
1925
1946
|
let defType = logicType;
|
|
1926
1947
|
let defRecord: any = {};
|
|
1927
|
-
// Try exact match on type (IF, ELSE,
|
|
1948
|
+
// Try exact match on type (IF, ELSE, FOREACH, DOUNTIL, etc.), then name
|
|
1928
1949
|
for (const field of ['type', 'name']) {
|
|
1929
1950
|
if (defId) break;
|
|
1930
1951
|
try {
|
|
@@ -2506,9 +2527,10 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
2506
2527
|
'add_action', 'update_action', 'delete_action',
|
|
2507
2528
|
'add_flow_logic', 'update_flow_logic', 'delete_flow_logic',
|
|
2508
2529
|
'add_subflow', 'update_subflow', 'delete_subflow',
|
|
2509
|
-
'close_flow'
|
|
2530
|
+
'open_flow', 'close_flow'
|
|
2510
2531
|
],
|
|
2511
|
-
description: 'Action to perform.
|
|
2532
|
+
description: 'Action to perform. EDITING WORKFLOW: create_flow keeps the editing lock open — you can immediately call add_action, add_flow_logic, etc. without open_flow. For editing EXISTING flows: call open_flow first to acquire the lock. Always call close_flow as the LAST step to release the lock so users can edit in the UI. ' +
|
|
2533
|
+
'add_*/update_*/delete_* for triggers, actions, flow_logic, subflows. update_trigger replaces the trigger type. delete_* removes elements by element_id.'
|
|
2512
2534
|
},
|
|
2513
2535
|
|
|
2514
2536
|
flow_id: {
|
|
@@ -2596,17 +2618,18 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
2596
2618
|
},
|
|
2597
2619
|
logic_type: {
|
|
2598
2620
|
type: 'string',
|
|
2599
|
-
description: 'Flow logic type for add_flow_logic. Looked up dynamically in sys_hub_flow_logic_definition.
|
|
2621
|
+
description: 'Flow logic type for add_flow_logic. Looked up dynamically in sys_hub_flow_logic_definition. ' +
|
|
2622
|
+
'Common aliases (FOR_EACH, DO_UNTIL, etc.) are auto-normalized to ServiceNow types. Available types: ' +
|
|
2600
2623
|
'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. ' +
|
|
2601
|
-
'FOR_EACH, DO_UNTIL — loops.
|
|
2624
|
+
'FOREACH (or FOR_EACH), DOUNTIL (or DO_UNTIL) — loops. CONTINUE (skip iteration) and BREAK (exit loop) can be used inside loops. ' +
|
|
2602
2625
|
'PARALLEL — execute branches in parallel. ' +
|
|
2603
2626
|
'DECISION — switch/decision table. ' +
|
|
2604
2627
|
'TRY — error handling (try/catch). ' +
|
|
2605
2628
|
'END — End Flow (stops execution). Always add END as the last element when the flow should terminate cleanly. ' +
|
|
2606
2629
|
'TIMER — Wait for a duration of time. ' +
|
|
2607
|
-
'GO_BACK_TO — jump back to a previous step. ' +
|
|
2608
|
-
'
|
|
2609
|
-
'WORKFLOW — call a legacy workflow.
|
|
2630
|
+
'GOBACKTO (or GO_BACK_TO) — jump back to a previous step. ' +
|
|
2631
|
+
'SETFLOWVARIABLES, APPENDFLOWVARIABLES, GETFLOWOUTPUT — flow variable management. ' +
|
|
2632
|
+
'WORKFLOW — call a legacy workflow. DYNAMICFLOW — dynamically invoke a flow. ' +
|
|
2610
2633
|
'Best practice: add an END element at the end of your flow for clean termination.'
|
|
2611
2634
|
},
|
|
2612
2635
|
logic_inputs: {
|
|
@@ -3094,11 +3117,8 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
3094
3117
|
}
|
|
3095
3118
|
}
|
|
3096
3119
|
|
|
3097
|
-
//
|
|
3098
|
-
|
|
3099
|
-
var lockReleased = await releaseFlowEditingLock(client, flowSysId);
|
|
3100
|
-
diagnostics.editing_lock_released = lockReleased;
|
|
3101
|
-
}
|
|
3120
|
+
// NOTE: Do NOT release the editing lock here. The agent may need to add more elements
|
|
3121
|
+
// (flow logic, actions, etc.) after creation. The agent must call close_flow when done.
|
|
3102
3122
|
|
|
3103
3123
|
return createSuccessResult({
|
|
3104
3124
|
created: true,
|
|
@@ -3706,6 +3726,26 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
3706
3726
|
: createErrorResult(delResult.error || 'Failed to delete element');
|
|
3707
3727
|
}
|
|
3708
3728
|
|
|
3729
|
+
// ────────────────────────────────────────────────────────────────
|
|
3730
|
+
// OPEN_FLOW — acquire Flow Designer editing lock (processflow GET)
|
|
3731
|
+
// ────────────────────────────────────────────────────────────────
|
|
3732
|
+
case 'open_flow': {
|
|
3733
|
+
if (!args.flow_id) throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'flow_id is required for open_flow');
|
|
3734
|
+
var openFlowId = await resolveFlowId(client, args.flow_id);
|
|
3735
|
+
var openSummary = summary();
|
|
3736
|
+
try {
|
|
3737
|
+
// The processflow GET is what the Flow Designer UI calls when opening a flow for editing.
|
|
3738
|
+
// This acquires the editing lock so subsequent GraphQL mutations can work.
|
|
3739
|
+
await client.get('/api/now/processflow/flow/' + openFlowId);
|
|
3740
|
+
openSummary.success('Flow opened for editing').field('Flow', openFlowId)
|
|
3741
|
+
.line('You can now use add_action, add_flow_logic, etc. Call close_flow when done.');
|
|
3742
|
+
return createSuccessResult({ action: 'open_flow', flow_id: openFlowId, editing_session: true }, {}, openSummary.build());
|
|
3743
|
+
} catch (e: any) {
|
|
3744
|
+
openSummary.error('Failed to open flow for editing: ' + (e.message || 'unknown')).field('Flow', openFlowId);
|
|
3745
|
+
return createErrorResult('Failed to open flow for editing: ' + (e.message || 'unknown'));
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3709
3749
|
// ────────────────────────────────────────────────────────────────
|
|
3710
3750
|
// CLOSE_FLOW — release Flow Designer editing lock (safeEdit)
|
|
3711
3751
|
// ────────────────────────────────────────────────────────────────
|