snow-flow 3.5.15 ā 3.5.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.
|
@@ -86,19 +86,13 @@ export declare class ArtifactLocalSync {
|
|
|
86
86
|
*/
|
|
87
87
|
private validateES5;
|
|
88
88
|
/**
|
|
89
|
-
*
|
|
89
|
+
* AGGRESSIVE STRIP FUNCTION: Remove ALL possible Snow-Flow wrapper variations
|
|
90
|
+
* FIXED: Handles multiple/nested wrappers and all patterns
|
|
90
91
|
*/
|
|
91
92
|
private stripAddedWrappers;
|
|
92
93
|
/**
|
|
93
|
-
*
|
|
94
|
-
|
|
95
|
-
private escapeRegexAndCreatePattern;
|
|
96
|
-
/**
|
|
97
|
-
* Fallback: Strip generic comments when no fieldMapping available
|
|
98
|
-
*/
|
|
99
|
-
private stripGenericComments;
|
|
100
|
-
/**
|
|
101
|
-
* INTELLIGENT WRAPPER DETECTION: Check if content actually needs wrappers
|
|
94
|
+
* CONSERVATIVE WRAPPER DETECTION: Only add wrappers if content is truly minimal
|
|
95
|
+
* FIXED: Now properly detects ALL types of existing wrappers/comments
|
|
102
96
|
*/
|
|
103
97
|
private needsWrappers;
|
|
104
98
|
/**
|
|
@@ -115,6 +109,7 @@ export declare class ArtifactLocalSync {
|
|
|
115
109
|
getSyncStatus(sys_id: string): string;
|
|
116
110
|
/**
|
|
117
111
|
* Pull any supported artifact type by detecting table from sys_id
|
|
112
|
+
* ENHANCED: Better error logging and more robust detection
|
|
118
113
|
*/
|
|
119
114
|
pullArtifactBySysId(sys_id: string): Promise<LocalArtifact>;
|
|
120
115
|
/**
|
|
@@ -127,7 +127,8 @@ class ArtifactLocalSync {
|
|
|
127
127
|
throw new Error(`Unsupported artifact type: ${tableName}. Supported types: ${Object.keys(artifact_registry_1.ARTIFACT_REGISTRY).join(', ')}`);
|
|
128
128
|
}
|
|
129
129
|
console.log(`\nš Pulling ${config.displayName} (${sys_id}) to local files...`);
|
|
130
|
-
console.log(`š Snow-Flow v3.5.
|
|
130
|
+
console.log(`š Snow-Flow v3.5.16 - ULTRA-CONSERVATIVE Wrapper System (No More Duplicates!)`);
|
|
131
|
+
console.log(`ā ļø CRITICAL FIX: Aggressive strip & minimal wrapper addition only`);
|
|
131
132
|
// Get timeout configuration
|
|
132
133
|
const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
|
|
133
134
|
// Use smart fetcher for known types, otherwise direct query
|
|
@@ -187,16 +188,21 @@ class ArtifactLocalSync {
|
|
|
187
188
|
.replace('{name}', sanitizedName)
|
|
188
189
|
.replace('{api_name}', artifactData.api_name || sanitizedName)
|
|
189
190
|
.replace('{short_description}', artifactData.short_description || sanitizedName);
|
|
190
|
-
//
|
|
191
|
+
// ULTRA-CONSERVATIVE WRAPPER SYSTEM: When in doubt, don't add wrappers
|
|
191
192
|
let header = '';
|
|
192
193
|
let footer = '';
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
194
|
+
// FAILSAFE: Only add wrappers if we're absolutely certain it's safe
|
|
195
|
+
if (mapping.wrapperHeader && mapping.wrapperFooter) {
|
|
196
|
+
const shouldAddWrappers = this.needsWrappers(processedContent, mapping);
|
|
197
|
+
if (shouldAddWrappers && processedContent.trim().length < 50) {
|
|
198
|
+
// EXTRA SAFETY: Only for very short content
|
|
199
|
+
header = this.replacePlaceholders(mapping.wrapperHeader, artifactData);
|
|
200
|
+
footer = this.replacePlaceholders(mapping.wrapperFooter, artifactData);
|
|
201
|
+
console.log(` š§ Adding wrappers for ${filename} (content is minimal: ${processedContent.trim().length} chars)`);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.log(` ā
Skipping wrappers for ${filename} (conservative approach)`);
|
|
205
|
+
}
|
|
200
206
|
}
|
|
201
207
|
const file = this.createLocalFile(artifactPath, `${filename}.${mapping.fileExtension}`, processedContent, mapping.serviceNowField, mapping.fileExtension, header, footer);
|
|
202
208
|
file.fieldMapping = mapping;
|
|
@@ -580,104 +586,97 @@ snow-flow sync status ${widget.sys_id}
|
|
|
580
586
|
return issues;
|
|
581
587
|
}
|
|
582
588
|
/**
|
|
583
|
-
*
|
|
589
|
+
* AGGRESSIVE STRIP FUNCTION: Remove ALL possible Snow-Flow wrapper variations
|
|
590
|
+
* FIXED: Handles multiple/nested wrappers and all patterns
|
|
584
591
|
*/
|
|
585
592
|
stripAddedWrappers(content, type, fieldMapping) {
|
|
586
|
-
if (!fieldMapping || !fieldMapping.wrapperHeader || !fieldMapping.wrapperFooter) {
|
|
587
|
-
// No wrappers defined, just remove generic comments
|
|
588
|
-
return this.stripGenericComments(content, type);
|
|
589
|
-
}
|
|
590
|
-
let cleaned = content;
|
|
591
|
-
// Get the actual wrappers that were added (without placeholders)
|
|
592
|
-
const header = fieldMapping.wrapperHeader;
|
|
593
|
-
const footer = fieldMapping.wrapperFooter;
|
|
594
|
-
// CRITICAL FIX: Use the EXACT wrappers from fieldMapping
|
|
595
|
-
if (header && footer) {
|
|
596
|
-
// Create regex patterns from the actual wrappers
|
|
597
|
-
const headerPattern = this.escapeRegexAndCreatePattern(header);
|
|
598
|
-
const footerPattern = this.escapeRegexAndCreatePattern(footer);
|
|
599
|
-
// Remove footer first (from end)
|
|
600
|
-
if (footerPattern) {
|
|
601
|
-
cleaned = cleaned.replace(new RegExp(footerPattern + '$'), '');
|
|
602
|
-
}
|
|
603
|
-
// Remove header (from start)
|
|
604
|
-
if (headerPattern) {
|
|
605
|
-
cleaned = cleaned.replace(new RegExp('^' + headerPattern), '');
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
return cleaned.trim();
|
|
609
|
-
}
|
|
610
|
-
/**
|
|
611
|
-
* Create regex pattern from wrapper text, handling placeholders
|
|
612
|
-
*/
|
|
613
|
-
escapeRegexAndCreatePattern(wrapper) {
|
|
614
|
-
// Replace placeholders with generic patterns
|
|
615
|
-
let pattern = wrapper
|
|
616
|
-
.replace(/\{name\}/g, '[^}]*') // Replace {name} with pattern to match any name
|
|
617
|
-
.replace(/\{[^}]+\}/g, '[^}]*'); // Replace any other {placeholder}
|
|
618
|
-
// Escape special regex characters
|
|
619
|
-
pattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
620
|
-
// Convert \n back to actual newlines in pattern
|
|
621
|
-
pattern = pattern.replace(/\\n/g, '\\s*\\n\\s*');
|
|
622
|
-
return pattern;
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Fallback: Strip generic comments when no fieldMapping available
|
|
626
|
-
*/
|
|
627
|
-
stripGenericComments(content, type) {
|
|
628
593
|
let cleaned = content;
|
|
594
|
+
// STEP 1: Remove ALL HTML comment variations (multiple times if needed)
|
|
595
|
+
if (type === 'html') {
|
|
596
|
+
let previousLength;
|
|
597
|
+
do {
|
|
598
|
+
previousLength = cleaned.length;
|
|
599
|
+
// Remove ServiceNow Widget Template comments (all variations)
|
|
600
|
+
cleaned = cleaned.replace(/^\s*<!--\s*ServiceNow\s+Widget\s+Template[\s\S]*?-->\s*\n?/gmi, '');
|
|
601
|
+
// Remove Angular bindings comments
|
|
602
|
+
cleaned = cleaned.replace(/^\s*<!--\s*Angular\s+bindings[\s\S]*?-->\s*\n?/gmi, '');
|
|
603
|
+
// Remove any other HTML comments at start
|
|
604
|
+
cleaned = cleaned.replace(/^\s*<!--[\s\S]*?-->\s*\n?/gm, '');
|
|
605
|
+
} while (cleaned.length !== previousLength); // Keep going until no more changes
|
|
606
|
+
}
|
|
607
|
+
// STEP 2: Remove ALL JS comment variations (multiple times if needed)
|
|
629
608
|
if (type === 'js') {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
609
|
+
let previousLength;
|
|
610
|
+
do {
|
|
611
|
+
previousLength = cleaned.length;
|
|
612
|
+
// Remove Server/Client script comment blocks
|
|
613
|
+
cleaned = cleaned.replace(/^\s*\/\*\*[\s\S]*?\*\/\s*\n?/gm, '');
|
|
614
|
+
// Remove function wrappers
|
|
615
|
+
cleaned = cleaned.replace(/^\s*\(function\s*\(\s*\)\s*\{\s*\n?/gm, '');
|
|
616
|
+
cleaned = cleaned.replace(/\s*\n?\s*\}\s*\)\s*\(\s*\)\s*;?\s*$/gm, '');
|
|
617
|
+
// Remove function( wrappers for client scripts
|
|
618
|
+
cleaned = cleaned.replace(/^\s*function\s*\(\s*$/gm, '');
|
|
619
|
+
cleaned = cleaned.replace(/^\s*\)\s*$/gm, '');
|
|
620
|
+
} while (cleaned.length !== previousLength);
|
|
621
|
+
}
|
|
622
|
+
// STEP 3: Remove ALL CSS comment variations
|
|
623
|
+
if (type === 'css') {
|
|
624
|
+
let previousLength;
|
|
625
|
+
do {
|
|
626
|
+
previousLength = cleaned.length;
|
|
627
|
+
// Remove widget style comments
|
|
628
|
+
cleaned = cleaned.replace(/^\s*\/\*[\s\S]*?\*\/\s*\n?/gm, '');
|
|
629
|
+
} while (cleaned.length !== previousLength);
|
|
630
|
+
}
|
|
631
|
+
// STEP 4: Clean up excessive whitespace
|
|
632
|
+
cleaned = cleaned.replace(/^\s*\n+/gm, ''); // Remove empty lines at start
|
|
633
|
+
cleaned = cleaned.replace(/\n\s*$/gm, ''); // Remove trailing whitespace
|
|
645
634
|
return cleaned.trim();
|
|
646
635
|
}
|
|
647
636
|
/**
|
|
648
|
-
*
|
|
637
|
+
* CONSERVATIVE WRAPPER DETECTION: Only add wrappers if content is truly minimal
|
|
638
|
+
* FIXED: Now properly detects ALL types of existing wrappers/comments
|
|
649
639
|
*/
|
|
650
640
|
needsWrappers(content, mapping) {
|
|
651
641
|
if (!content || !content.trim()) {
|
|
652
642
|
return false; // Empty content doesn't need wrappers
|
|
653
643
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
661
|
-
if (trimmed.match(/^\(function\(\)\s*\{[\s\S]*\}\)\(\)\s*;?$/)) {
|
|
662
|
-
return false; // Already has our specific wrapper
|
|
663
|
-
}
|
|
644
|
+
const trimmed = content.trim();
|
|
645
|
+
// CONSERVATIVE APPROACH: If content has ANY of these indicators, skip wrappers
|
|
646
|
+
// 1. Already has HTML comments (ANY HTML comments)
|
|
647
|
+
if (trimmed.includes('<!--')) {
|
|
648
|
+
console.log(` š Detected existing HTML comments - skipping wrappers`);
|
|
649
|
+
return false;
|
|
664
650
|
}
|
|
665
|
-
//
|
|
666
|
-
if (
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
651
|
+
// 2. Already has JS comments (ANY block comments)
|
|
652
|
+
if (trimmed.includes('/**') || trimmed.includes('/*')) {
|
|
653
|
+
console.log(` š Detected existing JS comments - skipping wrappers`);
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
// 3. Already has function wrappers (ANY function patterns)
|
|
657
|
+
if (trimmed.includes('(function') || trimmed.match(/^function\s*\(/)) {
|
|
658
|
+
console.log(` š Detected existing function patterns - skipping wrappers`);
|
|
659
|
+
return false;
|
|
671
660
|
}
|
|
672
|
-
//
|
|
673
|
-
if (
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
661
|
+
// 4. Content is substantial (more than just basic code)
|
|
662
|
+
if (trimmed.length > 200) {
|
|
663
|
+
console.log(` š Content is substantial (${trimmed.length} chars) - skipping wrappers`);
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
// 5. Contains ServiceNow-specific patterns
|
|
667
|
+
const serviceNowPatterns = [
|
|
668
|
+
'data.', 'input.', 'options.', '$scope.', 'c.server', 'gs.', '$sp.',
|
|
669
|
+
'ng-', 'angular', 'spModal', 'spUtil', '{{', 'glide'
|
|
670
|
+
];
|
|
671
|
+
for (const pattern of serviceNowPatterns) {
|
|
672
|
+
if (trimmed.toLowerCase().includes(pattern.toLowerCase())) {
|
|
673
|
+
console.log(` š Detected ServiceNow pattern '${pattern}' - skipping wrappers`);
|
|
674
|
+
return false;
|
|
678
675
|
}
|
|
679
676
|
}
|
|
680
|
-
|
|
677
|
+
// ONLY add wrappers for truly minimal/empty content
|
|
678
|
+
console.log(` ⨠Content is minimal and clean - adding wrappers`);
|
|
679
|
+
return true;
|
|
681
680
|
}
|
|
682
681
|
/**
|
|
683
682
|
* Sanitize filename for filesystem
|
|
@@ -704,26 +703,55 @@ snow-flow sync status ${widget.sys_id}
|
|
|
704
703
|
}
|
|
705
704
|
/**
|
|
706
705
|
* Pull any supported artifact type by detecting table from sys_id
|
|
706
|
+
* ENHANCED: Better error logging and more robust detection
|
|
707
707
|
*/
|
|
708
708
|
async pullArtifactBySysId(sys_id) {
|
|
709
|
-
|
|
710
|
-
|
|
709
|
+
console.log(`\nš Auto-detecting artifact type for sys_id: ${sys_id}`);
|
|
710
|
+
console.log(`š Checking ${Object.keys(artifact_registry_1.ARTIFACT_REGISTRY).length} supported tables...`);
|
|
711
|
+
// SMART ORDER: Check most common tables first for better performance
|
|
712
|
+
const allTables = Object.keys(artifact_registry_1.ARTIFACT_REGISTRY);
|
|
713
|
+
const commonTables = ['sp_widget', 'sys_script_include', 'sys_script', 'sys_ui_page'];
|
|
714
|
+
const otherTables = allTables.filter(t => !commonTables.includes(t));
|
|
715
|
+
const tables = [...commonTables, ...otherTables]; // Common tables first
|
|
711
716
|
const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
|
|
717
|
+
const errors = [];
|
|
712
718
|
for (const table of tables) {
|
|
713
719
|
try {
|
|
714
|
-
|
|
715
|
-
|
|
720
|
+
console.log(` š Checking table: ${table}...`);
|
|
721
|
+
// Increased timeout for better reliability
|
|
722
|
+
const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(table, `sys_id=${sys_id}`, 1), 8000, // 8 second timeout per table (was 3s)
|
|
716
723
|
`Detect table for ${sys_id}`);
|
|
717
724
|
if (response.result?.[0]) {
|
|
718
|
-
console.log(
|
|
725
|
+
console.log(` ā
Found in table: ${table}`);
|
|
726
|
+
console.log(`š Auto-detection successful! Proceeding with pull...`);
|
|
719
727
|
return this.pullArtifact(table, sys_id);
|
|
720
728
|
}
|
|
729
|
+
else {
|
|
730
|
+
console.log(` ā Not found in: ${table}`);
|
|
731
|
+
}
|
|
721
732
|
}
|
|
722
733
|
catch (error) {
|
|
723
|
-
|
|
734
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
735
|
+
console.log(` ā ļø Error checking ${table}: ${errorMsg}`);
|
|
736
|
+
errors.push({ table, error: errorMsg });
|
|
737
|
+
// Don't fail on permission errors, timeouts, etc. - keep trying other tables
|
|
724
738
|
}
|
|
725
739
|
}
|
|
726
|
-
|
|
740
|
+
// Generate detailed error message
|
|
741
|
+
console.log(`\nā Artifact detection failed!`);
|
|
742
|
+
console.log(`š Searched ${tables.length} tables for sys_id: ${sys_id}`);
|
|
743
|
+
if (errors.length > 0) {
|
|
744
|
+
console.log(`\nā ļø Errors encountered:`);
|
|
745
|
+
errors.forEach(({ table, error }) => {
|
|
746
|
+
console.log(` ${table}: ${error}`);
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
console.log(`\nš” Troubleshooting tips:`);
|
|
750
|
+
console.log(` 1. Verify the sys_id exists in ServiceNow`);
|
|
751
|
+
console.log(` 2. Check your permissions for the target table`);
|
|
752
|
+
console.log(` 3. Try specifying the table explicitly: snow_pull_artifact({sys_id, table: 'sp_widget'})`);
|
|
753
|
+
console.log(` 4. Supported tables: ${tables.join(', ')}`);
|
|
754
|
+
throw new Error(`Could not find artifact with sys_id ${sys_id} in any supported table. See details above.`);
|
|
727
755
|
}
|
|
728
756
|
/**
|
|
729
757
|
* Get supported artifact types
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.5.
|
|
4
|
-
"description": "ServiceNow development framework with
|
|
3
|
+
"version": "3.5.17",
|
|
4
|
+
"description": "ServiceNow development framework with ROBUST artifact detection fix. v3.5.17 FIXES the intermittent 'Could not find artifact' errors in snow_pull_artifact. Enhanced pullArtifactBySysId with detailed error logging, longer timeouts (8s per table), smart table ordering, and comprehensive troubleshooting guidance. ULTRA-CONSERVATIVE wrapper system prevents duplicate HTML comments. Enhanced 'snow-flow init' creates optimized settings.json with 18 MCP servers, extensive development permissions, intelligent hooks, and ServiceNow-specific commands. Features intelligent timeout configuration and comprehensive ServiceNow development workflow.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|