snow-flow 10.0.1-dev.445 → 10.0.1-dev.447
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
|
@@ -38,6 +38,25 @@ function generateUUID(): string {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
async function getNextOrder(client: any, flowId: string): Promise<number> {
|
|
42
|
+
let maxOrder = 0;
|
|
43
|
+
// Query all element types that have an order field on this flow
|
|
44
|
+
for (const table of ['sys_hub_action_instance', 'sys_hub_flow_logic', 'sys_hub_sub_flow_instance']) {
|
|
45
|
+
try {
|
|
46
|
+
const resp = await client.get('/api/now/table/' + table, {
|
|
47
|
+
params: {
|
|
48
|
+
sysparm_query: 'flow=' + flowId + '^ORDERBYDESCorder',
|
|
49
|
+
sysparm_fields: 'order',
|
|
50
|
+
sysparm_limit: 1
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const order = parseInt(resp.data.result?.[0]?.order || '0', 10);
|
|
54
|
+
if (order > maxOrder) maxOrder = order;
|
|
55
|
+
} catch (_) {}
|
|
56
|
+
}
|
|
57
|
+
return maxOrder + 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
async function executeFlowPatchMutation(
|
|
42
61
|
client: any,
|
|
43
62
|
flowPatch: any,
|
|
@@ -183,6 +202,7 @@ async function addActionViaGraphQL(
|
|
|
183
202
|
actionType: string,
|
|
184
203
|
actionName: string,
|
|
185
204
|
inputs?: Record<string, string>,
|
|
205
|
+
parentUiId?: string,
|
|
186
206
|
order?: number
|
|
187
207
|
): Promise<{ success: boolean; actionId?: string; steps?: any; error?: string }> {
|
|
188
208
|
const steps: any = {};
|
|
@@ -265,6 +285,7 @@ async function addActionViaGraphQL(
|
|
|
265
285
|
}
|
|
266
286
|
|
|
267
287
|
const uuid = generateUUID();
|
|
288
|
+
const resolvedOrder = order || await getNextOrder(client, flowId);
|
|
268
289
|
const actionResponseFields = 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
269
290
|
try {
|
|
270
291
|
const result = await executeFlowPatchMutation(client, {
|
|
@@ -275,11 +296,11 @@ async function addActionViaGraphQL(
|
|
|
275
296
|
metadata: '{"predicates":[]}',
|
|
276
297
|
flowSysId: flowId,
|
|
277
298
|
generationSource: '',
|
|
278
|
-
order: String(
|
|
279
|
-
parent: '',
|
|
299
|
+
order: String(resolvedOrder),
|
|
300
|
+
parent: parentUiId || '',
|
|
280
301
|
uiUniqueIdentifier: uuid,
|
|
281
302
|
type: 'action',
|
|
282
|
-
parentUiId: '',
|
|
303
|
+
parentUiId: parentUiId || '',
|
|
283
304
|
inputs: []
|
|
284
305
|
}]
|
|
285
306
|
}
|
|
@@ -365,13 +386,14 @@ async function addFlowLogicViaGraphQL(
|
|
|
365
386
|
if (!defId) return { success: false, error: 'Flow logic definition not found for: ' + logicType, steps };
|
|
366
387
|
|
|
367
388
|
const uuid = generateUUID();
|
|
389
|
+
const resolvedOrder = order || await getNextOrder(client, flowId);
|
|
368
390
|
const logicResponseFields = 'flowLogics { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
369
391
|
try {
|
|
370
392
|
const result = await executeFlowPatchMutation(client, {
|
|
371
393
|
flowId: flowId,
|
|
372
394
|
flowLogics: {
|
|
373
395
|
insert: [{
|
|
374
|
-
order: String(
|
|
396
|
+
order: String(resolvedOrder),
|
|
375
397
|
uiUniqueIdentifier: uuid,
|
|
376
398
|
parent: '',
|
|
377
399
|
metadata: '{"predicates":[]}',
|
|
@@ -472,6 +494,7 @@ async function addSubflowCallViaGraphQL(
|
|
|
472
494
|
if (!subflowName) subflowName = subflowId;
|
|
473
495
|
|
|
474
496
|
const uuid = generateUUID();
|
|
497
|
+
const resolvedOrder = order || await getNextOrder(client, flowId);
|
|
475
498
|
const subflowResponseFields = 'subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
|
|
476
499
|
try {
|
|
477
500
|
const result = await executeFlowPatchMutation(client, {
|
|
@@ -482,7 +505,7 @@ async function addSubflowCallViaGraphQL(
|
|
|
482
505
|
flowSysId: flowId,
|
|
483
506
|
generationSource: '',
|
|
484
507
|
name: subflowName,
|
|
485
|
-
order: String(
|
|
508
|
+
order: String(resolvedOrder),
|
|
486
509
|
parent: parentUiId || '',
|
|
487
510
|
subflowSysId: subflowSysId,
|
|
488
511
|
uiUniqueIdentifier: uuid,
|
|
@@ -521,6 +544,61 @@ async function addSubflowCallViaGraphQL(
|
|
|
521
544
|
}
|
|
522
545
|
}
|
|
523
546
|
|
|
547
|
+
// ── GENERIC UPDATE/DELETE for any flow element ───────────────────────
|
|
548
|
+
|
|
549
|
+
const elementGraphQLMap: Record<string, { key: string; type: string; responseFields: string }> = {
|
|
550
|
+
action: { key: 'actions', type: 'action', responseFields: 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' },
|
|
551
|
+
trigger: { key: 'triggerInstances', type: 'trigger', responseFields: 'triggerInstances { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' },
|
|
552
|
+
flowlogic: { key: 'flowLogics', type: 'flowlogic', responseFields: 'flowLogics { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' },
|
|
553
|
+
subflow: { key: 'subflows', type: 'subflow', responseFields: 'subflows { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' },
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
async function updateElementViaGraphQL(
|
|
557
|
+
client: any,
|
|
558
|
+
flowId: string,
|
|
559
|
+
elementType: string,
|
|
560
|
+
elementId: string,
|
|
561
|
+
inputs: Record<string, string>
|
|
562
|
+
): Promise<{ success: boolean; steps?: any; error?: string }> {
|
|
563
|
+
const config = elementGraphQLMap[elementType];
|
|
564
|
+
if (!config) return { success: false, error: 'Unknown element type: ' + elementType };
|
|
565
|
+
|
|
566
|
+
const updateInputs = Object.entries(inputs).map(([name, value]) => ({
|
|
567
|
+
name,
|
|
568
|
+
value: { schemaless: false, schemalessValue: '', value: String(value) }
|
|
569
|
+
}));
|
|
570
|
+
|
|
571
|
+
try {
|
|
572
|
+
await executeFlowPatchMutation(client, {
|
|
573
|
+
flowId,
|
|
574
|
+
[config.key]: { update: [{ uiUniqueIdentifier: elementId, type: config.type, inputs: updateInputs }] }
|
|
575
|
+
}, config.responseFields);
|
|
576
|
+
return { success: true, steps: { element: elementId, type: elementType, inputs: updateInputs.map(i => i.name) } };
|
|
577
|
+
} catch (e: any) {
|
|
578
|
+
return { success: false, error: e.message, steps: { element: elementId, type: elementType } };
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
async function deleteElementViaGraphQL(
|
|
583
|
+
client: any,
|
|
584
|
+
flowId: string,
|
|
585
|
+
elementType: string,
|
|
586
|
+
elementIds: string[]
|
|
587
|
+
): Promise<{ success: boolean; steps?: any; error?: string }> {
|
|
588
|
+
const config = elementGraphQLMap[elementType];
|
|
589
|
+
if (!config) return { success: false, error: 'Unknown element type: ' + elementType };
|
|
590
|
+
|
|
591
|
+
try {
|
|
592
|
+
await executeFlowPatchMutation(client, {
|
|
593
|
+
flowId,
|
|
594
|
+
[config.key]: { delete: elementIds }
|
|
595
|
+
}, config.responseFields);
|
|
596
|
+
return { success: true, steps: { deleted: elementIds, type: elementType } };
|
|
597
|
+
} catch (e: any) {
|
|
598
|
+
return { success: false, error: e.message, steps: { elementIds, type: elementType } };
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
524
602
|
async function createFlowViaProcessFlowAPI(
|
|
525
603
|
client: any,
|
|
526
604
|
params: {
|
|
@@ -629,8 +707,14 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
629
707
|
properties: {
|
|
630
708
|
action: {
|
|
631
709
|
type: 'string',
|
|
632
|
-
enum: [
|
|
633
|
-
|
|
710
|
+
enum: [
|
|
711
|
+
'create', 'create_subflow', 'list', 'get', 'update', 'activate', 'deactivate', 'delete', 'publish',
|
|
712
|
+
'add_trigger', 'update_trigger', 'delete_trigger',
|
|
713
|
+
'add_action', 'update_action', 'delete_action',
|
|
714
|
+
'add_flow_logic', 'update_flow_logic', 'delete_flow_logic',
|
|
715
|
+
'add_subflow', 'update_subflow', 'delete_subflow'
|
|
716
|
+
],
|
|
717
|
+
description: 'Action to perform. add_*/update_*/delete_* for triggers, actions, flow_logic, subflows. update_trigger replaces the trigger type. update_action/update_flow_logic/update_subflow change input values. delete_* removes elements by element_id.'
|
|
634
718
|
},
|
|
635
719
|
|
|
636
720
|
flow_id: {
|
|
@@ -732,6 +816,14 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
732
816
|
type: 'string',
|
|
733
817
|
description: 'Subflow sys_id or name to call as a step (for add_subflow action). Looked up in sys_hub_flow where type=subflow.'
|
|
734
818
|
},
|
|
819
|
+
element_id: {
|
|
820
|
+
type: 'string',
|
|
821
|
+
description: 'Element sys_id or uiUniqueIdentifier for update_*/delete_* actions. For delete_* this can also be a comma-separated list of IDs.'
|
|
822
|
+
},
|
|
823
|
+
order: {
|
|
824
|
+
type: 'number',
|
|
825
|
+
description: 'Position/order of the element in the flow (for add_* actions). Auto-detected if not provided (appends after last element).'
|
|
826
|
+
},
|
|
735
827
|
type: {
|
|
736
828
|
type: 'string',
|
|
737
829
|
enum: ['flow', 'subflow', 'all'],
|
|
@@ -1651,7 +1743,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1651
1743
|
var addActName = args.action_name || args.name || addActType;
|
|
1652
1744
|
var addActInputs = args.action_inputs || args.inputs || {};
|
|
1653
1745
|
|
|
1654
|
-
var addActResult = await addActionViaGraphQL(client, addActFlowId, addActType, addActName, addActInputs);
|
|
1746
|
+
var addActResult = await addActionViaGraphQL(client, addActFlowId, addActType, addActName, addActInputs, args.parent_ui_id, args.order);
|
|
1655
1747
|
|
|
1656
1748
|
var addActSummary = summary();
|
|
1657
1749
|
if (addActResult.success) {
|
|
@@ -1738,6 +1830,62 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1738
1830
|
: createErrorResult(addSubResult.error || 'Failed to add subflow call');
|
|
1739
1831
|
}
|
|
1740
1832
|
|
|
1833
|
+
// ────────────────────────────────────────────────────────────────
|
|
1834
|
+
// UPDATE_ACTION / UPDATE_FLOW_LOGIC / UPDATE_SUBFLOW
|
|
1835
|
+
// ────────────────────────────────────────────────────────────────
|
|
1836
|
+
case 'update_action':
|
|
1837
|
+
case 'update_flow_logic':
|
|
1838
|
+
case 'update_subflow': {
|
|
1839
|
+
if (!args.flow_id) throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'flow_id is required');
|
|
1840
|
+
if (!args.element_id) throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'element_id is required (sys_id or uiUniqueIdentifier of the element)');
|
|
1841
|
+
var updElemFlowId = await resolveFlowId(client, args.flow_id);
|
|
1842
|
+
var updElemType = action === 'update_action' ? 'action' : action === 'update_flow_logic' ? 'flowlogic' : 'subflow';
|
|
1843
|
+
var updElemInputs = args.action_inputs || args.logic_inputs || args.inputs || {};
|
|
1844
|
+
|
|
1845
|
+
var updElemResult = await updateElementViaGraphQL(client, updElemFlowId, updElemType, args.element_id, updElemInputs);
|
|
1846
|
+
|
|
1847
|
+
var updElemSummary = summary();
|
|
1848
|
+
if (updElemResult.success) {
|
|
1849
|
+
updElemSummary.success('Element updated').field('Type', updElemType).field('Element', args.element_id);
|
|
1850
|
+
} else {
|
|
1851
|
+
updElemSummary.error('Failed to update element: ' + (updElemResult.error || 'unknown'));
|
|
1852
|
+
}
|
|
1853
|
+
return updElemResult.success
|
|
1854
|
+
? createSuccessResult({ action, ...updElemResult }, {}, updElemSummary.build())
|
|
1855
|
+
: createErrorResult(updElemResult.error || 'Failed to update element');
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
// ────────────────────────────────────────────────────────────────
|
|
1859
|
+
// DELETE_ACTION / DELETE_FLOW_LOGIC / DELETE_SUBFLOW / DELETE_TRIGGER
|
|
1860
|
+
// ────────────────────────────────────────────────────────────────
|
|
1861
|
+
case 'delete_action':
|
|
1862
|
+
case 'delete_flow_logic':
|
|
1863
|
+
case 'delete_subflow':
|
|
1864
|
+
case 'delete_trigger': {
|
|
1865
|
+
if (!args.flow_id) throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'flow_id is required');
|
|
1866
|
+
if (!args.element_id) throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'element_id is required (sys_id(s) to delete, comma-separated for multiple)');
|
|
1867
|
+
var delElemFlowId = await resolveFlowId(client, args.flow_id);
|
|
1868
|
+
var delElemType = action === 'delete_action' ? 'action'
|
|
1869
|
+
: action === 'delete_flow_logic' ? 'flowlogic'
|
|
1870
|
+
: action === 'delete_subflow' ? 'subflow'
|
|
1871
|
+
: 'trigger';
|
|
1872
|
+
var delElemIds = String(args.element_id).split(',').map((id: string) => id.trim());
|
|
1873
|
+
|
|
1874
|
+
// Map 'trigger' to the correct GraphQL key
|
|
1875
|
+
var delGraphQLType = delElemType === 'trigger' ? 'trigger' : delElemType;
|
|
1876
|
+
var delResult = await deleteElementViaGraphQL(client, delElemFlowId, delGraphQLType, delElemIds);
|
|
1877
|
+
|
|
1878
|
+
var delSummary = summary();
|
|
1879
|
+
if (delResult.success) {
|
|
1880
|
+
delSummary.success('Element(s) deleted').field('Type', delElemType).field('Deleted', delElemIds.join(', '));
|
|
1881
|
+
} else {
|
|
1882
|
+
delSummary.error('Failed to delete element: ' + (delResult.error || 'unknown'));
|
|
1883
|
+
}
|
|
1884
|
+
return delResult.success
|
|
1885
|
+
? createSuccessResult({ action, ...delResult }, {}, delSummary.build())
|
|
1886
|
+
: createErrorResult(delResult.error || 'Failed to delete element');
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1741
1889
|
default:
|
|
1742
1890
|
throw new SnowFlowError(ErrorType.VALIDATION_ERROR, 'Unknown action: ' + action);
|
|
1743
1891
|
}
|