snow-flow 3.5.14 → 3.5.16

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.
@@ -31,6 +31,8 @@ export interface LocalFile {
31
31
  currentContent?: string;
32
32
  isModified: boolean;
33
33
  fieldMapping?: FieldMapping;
34
+ existedBefore?: boolean;
35
+ previousContent?: string;
34
36
  }
35
37
  export declare class ArtifactLocalSync {
36
38
  private baseDir;
@@ -84,9 +86,15 @@ export declare class ArtifactLocalSync {
84
86
  */
85
87
  private validateES5;
86
88
  /**
87
- * Strip headers/footers we added - now uses field mapping for accuracy
89
+ * AGGRESSIVE STRIP FUNCTION: Remove ALL possible Snow-Flow wrapper variations
90
+ * FIXED: Handles multiple/nested wrappers and all patterns
88
91
  */
89
92
  private stripAddedWrappers;
93
+ /**
94
+ * CONSERVATIVE WRAPPER DETECTION: Only add wrappers if content is truly minimal
95
+ * FIXED: Now properly detects ALL types of existing wrappers/comments
96
+ */
97
+ private needsWrappers;
90
98
  /**
91
99
  * Sanitize filename for filesystem
92
100
  */
@@ -127,6 +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.16 - ULTRA-CONSERVATIVE Wrapper System (No More Duplicates!)`);
131
+ console.log(`āš ļø CRITICAL FIX: Aggressive strip & minimal wrapper addition only`);
130
132
  // Get timeout configuration
131
133
  const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
132
134
  // Use smart fetcher for known types, otherwise direct query
@@ -186,9 +188,22 @@ class ArtifactLocalSync {
186
188
  .replace('{name}', sanitizedName)
187
189
  .replace('{api_name}', artifactData.api_name || sanitizedName)
188
190
  .replace('{short_description}', artifactData.short_description || sanitizedName);
189
- // Generate header/footer with replacements
190
- const header = this.replacePlaceholders(mapping.wrapperHeader || '', artifactData);
191
- const footer = this.replacePlaceholders(mapping.wrapperFooter || '', artifactData);
191
+ // ULTRA-CONSERVATIVE WRAPPER SYSTEM: When in doubt, don't add wrappers
192
+ let header = '';
193
+ let footer = '';
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
+ }
206
+ }
192
207
  const file = this.createLocalFile(artifactPath, `${filename}.${mapping.fileExtension}`, processedContent, mapping.serviceNowField, mapping.fileExtension, header, footer);
193
208
  file.fieldMapping = mapping;
194
209
  files.push(file);
@@ -370,6 +385,31 @@ class ArtifactLocalSync {
370
385
  createLocalFile(dirPath, filename, content, field, type, header = '', footer = '') {
371
386
  const filePath = path.join(dirPath, filename);
372
387
  const fullContent = header + content + footer;
388
+ // CRITICAL FIX: Check if file exists and handle overwrites intelligently
389
+ let fileExists = false;
390
+ let existingContent = '';
391
+ if (fs.existsSync(filePath)) {
392
+ fileExists = true;
393
+ existingContent = fs.readFileSync(filePath, 'utf8');
394
+ // Check if existing content is the same (avoid unnecessary writes)
395
+ if (existingContent === fullContent) {
396
+ console.log(` šŸ“„ Unchanged: ${filename} (identical content, skipping write)`);
397
+ return {
398
+ filename,
399
+ path: filePath,
400
+ field,
401
+ type: type,
402
+ originalContent: content,
403
+ isModified: false
404
+ };
405
+ }
406
+ console.log(` šŸ”„ Overwriting: ${filename}`);
407
+ console.log(` ā„¹ļø File size: ${existingContent.length} → ${fullContent.length} chars`);
408
+ }
409
+ else {
410
+ console.log(` šŸ“ Creating: ${filename}`);
411
+ }
412
+ // Write the file
373
413
  fs.writeFileSync(filePath, fullContent, 'utf8');
374
414
  return {
375
415
  filename,
@@ -377,7 +417,9 @@ class ArtifactLocalSync {
377
417
  field,
378
418
  type: type,
379
419
  originalContent: content,
380
- isModified: false
420
+ isModified: fileExists, // Mark as modified if we overwrote existing file
421
+ existedBefore: fileExists,
422
+ previousContent: existingContent
381
423
  };
382
424
  }
383
425
  /**
@@ -544,28 +586,97 @@ snow-flow sync status ${widget.sys_id}
544
586
  return issues;
545
587
  }
546
588
  /**
547
- * Strip headers/footers we added - now uses field mapping for accuracy
589
+ * AGGRESSIVE STRIP FUNCTION: Remove ALL possible Snow-Flow wrapper variations
590
+ * FIXED: Handles multiple/nested wrappers and all patterns
548
591
  */
549
592
  stripAddedWrappers(content, type, fieldMapping) {
550
- // Remove our added comments and wrappers
551
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)
552
608
  if (type === 'js') {
553
- // Remove wrapper function if we added it
554
- cleaned = cleaned.replace(/^\(function\(\) \{\n/, '');
555
- cleaned = cleaned.replace(/\n\}\)\(\);$/, '');
556
- // Remove our header comments
557
- cleaned = cleaned.replace(/^\/\*\*[\s\S]*?\*\/\n\n/, '');
558
- cleaned = cleaned.replace(/^function\(/, 'function(');
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
634
+ return cleaned.trim();
635
+ }
636
+ /**
637
+ * CONSERVATIVE WRAPPER DETECTION: Only add wrappers if content is truly minimal
638
+ * FIXED: Now properly detects ALL types of existing wrappers/comments
639
+ */
640
+ needsWrappers(content, mapping) {
641
+ if (!content || !content.trim()) {
642
+ return false; // Empty content doesn't need wrappers
643
+ }
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;
559
650
  }
560
- else if (type === 'html') {
561
- // Remove our HTML comments
562
- cleaned = cleaned.replace(/^<!-- ServiceNow Widget Template -->[\s\S]*?-->\n\n/, '');
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;
563
655
  }
564
- else if (type === 'css') {
565
- // Remove our CSS comments
566
- cleaned = cleaned.replace(/^\/\* ServiceNow Widget Styles \*\/[\s\S]*?\*\/\n\n/, '');
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;
567
660
  }
568
- return cleaned.trim();
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;
675
+ }
676
+ }
677
+ // ONLY add wrappers for truly minimal/empty content
678
+ console.log(` ✨ Content is minimal and clean - adding wrappers`);
679
+ return true;
569
680
  }
570
681
  /**
571
682
  * Sanitize filename for filesystem
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.5.14",
4
- "description": "ServiceNow development framework with comprehensive Claude Code integration. Enhanced 'snow-flow init' creates optimized settings.json with 18 MCP servers, extensive development permissions, intelligent hooks, and ServiceNow-specific commands. Fixed false positive success reporting in artifact push. Features intelligent timeout configuration for long operations while preventing Claude API timeouts. Executes background scripts using ES5 JavaScript only (ServiceNow Rhino engine requirement). Provides complete development workflow with local artifact sync, widget debugging, deployment validation, and comprehensive platform management.",
3
+ "version": "3.5.16",
4
+ "description": "ServiceNow development framework with EMERGENCY FIX for wrapper multiplication bug. v3.5.16 FIXES the triple/quadruple wrapper problem in v3.5.15. Features ULTRA-CONSERVATIVE wrapper system that aggressively strips ALL wrapper variations and only adds wrappers for truly minimal content (<50 chars). No more duplicate HTML comments or function wrappers. 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": {