snow-flow 10.0.1-dev.478 → 10.0.1-dev.480

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-dev.478",
3
+ "version": "10.0.1-dev.480",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -1512,17 +1512,16 @@ async function buildConditionLabelCache(
1512
1512
  tableLabel: string,
1513
1513
  logicUiId: string,
1514
1514
  explicitFields?: string[]
1515
- ): Promise<{ inserts: any[]; updates: any[] }> {
1516
- var empty = { inserts: [], updates: [] };
1517
- if (!dataPillBase) return empty;
1515
+ ): Promise<any[]> {
1516
+ if (!dataPillBase) return [];
1518
1517
 
1519
1518
  // Collect unique field names — either from explicit list or by parsing encoded query
1520
1519
  if (!explicitFields) {
1521
1520
  var clauses = parseEncodedQuery(conditionValue);
1522
- if (clauses.length === 0) return empty;
1521
+ if (clauses.length === 0) return [];
1523
1522
  explicitFields = clauses.map(function (c) { return c.field; }).filter(function (f) { return !!f; });
1524
1523
  }
1525
- if (explicitFields.length === 0) return empty;
1524
+ if (explicitFields.length === 0) return [];
1526
1525
 
1527
1526
  // De-duplicate field names
1528
1527
  var uniqueFields: string[] = [];
@@ -1536,51 +1535,16 @@ async function buildConditionLabelCache(
1536
1535
  }
1537
1536
  if (uniqueFields.length === 0) return [];
1538
1537
 
1539
- // Batch-query sys_dictionary for field metadata (type, label)
1540
- var fieldMeta: Record<string, { type: string; label: string }> = {};
1541
- try {
1542
- var dictResp = await client.get('/api/now/table/sys_dictionary', {
1543
- params: {
1544
- sysparm_query: 'name=' + table + '^elementIN' + uniqueFields.join(','),
1545
- sysparm_fields: 'element,column_label,internal_type',
1546
- sysparm_display_value: 'false',
1547
- sysparm_limit: uniqueFields.length + 5
1548
- }
1549
- });
1550
- var dictResults = dictResp.data.result || [];
1551
- for (var d = 0; d < dictResults.length; d++) {
1552
- var rec = dictResults[d];
1553
- var elName = str(rec.element);
1554
- var intType = str(rec.internal_type?.value || rec.internal_type || 'string');
1555
- var colLabel = str(rec.column_label);
1556
- if (elName) fieldMeta[elName] = { type: intType, label: colLabel };
1557
- }
1558
- } catch (_) {
1559
- // Fallback: use "string" type and generated labels if dictionary lookup fails
1560
- }
1561
-
1562
- // Build labelCache entries for condition pills, split into INSERT and UPDATE:
1563
- // - INSERT: record-level pill (must exist for actions; format from processflow XML)
1564
- // - UPDATE: field-level pills (minimal: name + usedInstances — matching the UI's exact mutation format)
1538
+ // Build labelCache UPDATE entries for condition pills.
1539
+ // Matches the UI's exact mutation format (from if-statement-update.txt):
1540
+ // labelCache: { update: [{ name: "Created or Updated_1.current.category", usedInstances: [...] }] }
1565
1541
  //
1566
- // The UI uses labelCache.update for condition pills (captured mutation shows only name + usedInstances).
1567
- // The record-level pill is INSERTed to ensure it exists (our trigger is created via code, not UI).
1568
- var inserts: any[] = [];
1542
+ // The record-level pill (e.g. "Created or Updated_1.current") is NOT included here because:
1543
+ // - The ServiceNow backend automatically creates it when the trigger is saved (INSERT UPDATE)
1544
+ // - Sending a duplicate labelCache.insert for it can cause the entire labelCache block to fail
1545
+ // - The UI's condition mutation never sends a record-level pill insert (confirmed via network capture)
1569
1546
  var updates: any[] = [];
1570
1547
 
1571
- // Record-level pill entry → INSERT with full metadata (processflow XML format)
1572
- inserts.push({
1573
- name: dataPillBase,
1574
- label: 'Trigger - Record ' + triggerName + '\u279b' + tableLabel + ' Record',
1575
- reference: table,
1576
- reference_display: tableLabel,
1577
- type: 'reference',
1578
- base_type: 'reference',
1579
- attributes: {},
1580
- usedInstances: []
1581
- });
1582
-
1583
- // Field-level pill entries → UPDATE with minimal fields (matching UI mutation)
1584
1548
  for (var j = 0; j < uniqueFields.length; j++) {
1585
1549
  var f = uniqueFields[j];
1586
1550
  var pillName = dataPillBase + '.' + f;
@@ -1591,7 +1555,7 @@ async function buildConditionLabelCache(
1591
1555
  });
1592
1556
  }
1593
1557
 
1594
- return { inserts, updates };
1558
+ return updates;
1595
1559
  }
1596
1560
 
1597
1561
  // ── DATA PILL SUPPORT FOR RECORD ACTIONS (Update/Create Record) ──────
@@ -1922,6 +1886,29 @@ async function addFlowLogicViaGraphQL(
1922
1886
  var needsConditionUpdate = false;
1923
1887
  var conditionTriggerInfo: any = null;
1924
1888
 
1889
+ // Pre-process: detect JS-style dot notation conditions and convert to shorthand pill format.
1890
+ // Users may write conditions like:
1891
+ // "trigger.current.category = software" (single =)
1892
+ // "trigger.current.category == 'software'" (JS equality)
1893
+ // "current.priority = 1" (short prefix)
1894
+ // These are converted to pill shorthand format that the existing logic can handle:
1895
+ // "{{trigger.current.category}}=software"
1896
+ var DOT_NOTATION_RE = /((?:trigger\.)?current)\.(\w+)\s*(===?|!==?|>=|<=|>|<|=)\s*(?:'([^']*)'|"([^"]*)"|(\S+))/g;
1897
+ if (DOT_NOTATION_RE.test(rawCondition)) {
1898
+ DOT_NOTATION_RE.lastIndex = 0;
1899
+ var dotOriginal = rawCondition;
1900
+ rawCondition = rawCondition.replace(DOT_NOTATION_RE, function (_m: string, prefix: string, field: string, op: string, qv1: string, qv2: string, uv: string) {
1901
+ var snOp = op;
1902
+ if (op === '==' || op === '===') snOp = '=';
1903
+ else if (op === '!=' || op === '!==') snOp = '!=';
1904
+ var val = qv1 !== undefined ? qv1 : (qv2 !== undefined ? qv2 : uv);
1905
+ return '{{' + prefix + '.' + field + '}}' + snOp + val;
1906
+ });
1907
+ // Replace JS && with ServiceNow ^ (AND separator)
1908
+ rawCondition = rawCondition.replace(/\s*&&\s*/g, '^');
1909
+ steps.dot_notation_rewrite = { original: dotOriginal, rewritten: rawCondition };
1910
+ }
1911
+
1925
1912
  // Shorthand patterns that need rewriting to the real data pill base
1926
1913
  // e.g. {{trigger.current.category}} → {{Created or Updated_1.current.category}}
1927
1914
  var PILL_SHORTHANDS = ['trigger.current', 'current', 'trigger_record', 'trigger.record'];
@@ -2042,19 +2029,15 @@ async function addFlowLogicViaGraphQL(
2042
2029
  }
2043
2030
 
2044
2031
  steps.condition_transform = { original: rawCondition, transformed: transformedCondition };
2045
- steps.label_cache = {
2046
- inserts: labelCacheResult.inserts.map(function (e: any) { return e.name; }),
2047
- updates: labelCacheResult.updates.map(function (e: any) { return e.name; })
2048
- };
2032
+ steps.label_cache = labelCacheResult.map(function (e: any) { return e.name; });
2049
2033
 
2050
2034
  try {
2051
- // Match the UI's exact format for condition UPDATE (from captured network tab mutation):
2035
+ // Match the UI's exact format for condition UPDATE (from if-statement-update.txt):
2036
+ // - labelCache.update: field-level pills with minimal name + usedInstances
2037
+ // - NO labelCache.insert (record-level pill is auto-created by backend during trigger save)
2052
2038
  // - condition input: only name + value (NO displayValue, NO flowLogicDefinition)
2053
- // - labelCache.insert: record-level pill with full metadata (ensures it exists)
2054
- // - labelCache.update: field-level pills with minimal name + usedInstances (matching UI)
2055
2039
  var updatePatch: any = {
2056
2040
  flowId: flowId,
2057
- labelCache: {} as any,
2058
2041
  flowLogics: {
2059
2042
  update: [{
2060
2043
  uiUniqueIdentifier: returnedUuid,
@@ -2066,11 +2049,8 @@ async function addFlowLogicViaGraphQL(
2066
2049
  }]
2067
2050
  }
2068
2051
  };
2069
- if (labelCacheResult.inserts.length > 0) {
2070
- updatePatch.labelCache.insert = labelCacheResult.inserts;
2071
- }
2072
- if (labelCacheResult.updates.length > 0) {
2073
- updatePatch.labelCache.update = labelCacheResult.updates;
2052
+ if (labelCacheResult.length > 0) {
2053
+ updatePatch.labelCache = { update: labelCacheResult };
2074
2054
  }
2075
2055
  // Log the exact GraphQL mutation for debugging
2076
2056
  steps.condition_update_mutation = jsToGraphQL(updatePatch);