snow-flow 3.6.3 → 3.6.5

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/dist/cli.js CHANGED
@@ -2584,6 +2584,14 @@ async function createMCPConfig(targetDir, force = false) {
2584
2584
  "Bash(sudo *)"
2585
2585
  ]
2586
2586
  },
2587
+ "autoCompactThreshold": 0.65,
2588
+ "compactMode": "aggressive",
2589
+ "contextPreservation": {
2590
+ "preserveMCPState": true,
2591
+ "preserveToolResults": true,
2592
+ "preserveRecentContext": 5000,
2593
+ "prioritizeServiceNowOperations": true
2594
+ },
2587
2595
  "hooks": {
2588
2596
  "PreCompact": [
2589
2597
  {
@@ -2597,10 +2605,11 @@ async function createMCPConfig(targetDir, force = false) {
2597
2605
  },
2598
2606
  {
2599
2607
  "matcher": "auto",
2608
+ "threshold": 0.65,
2600
2609
  "hooks": [
2601
2610
  {
2602
2611
  "type": "command",
2603
- "command": "/bin/bash -c 'echo \"šŸ”„ Auto-Compact Guidance (Context Window Full):\"; echo \"šŸ“‹ CRITICAL: Before compacting, ensure you understand:\"; echo \" • All 18+ MCP servers including servicenow-local-development\"; echo \" • Use snow_pull_artifact for widget debugging (NOT snow_query_table)\"; echo \" • Concurrent execution patterns from CLAUDE.md\"; echo \" • Batchtools optimization for 300% performance gains\"; echo \" • Swarm coordination strategies for complex tasks\"; echo \"⚔ Apply GOLDEN RULE: Always batch operations in single messages\"; echo \"āœ… Auto-compact proceeding with full agent context\"'"
2612
+ "command": "/bin/bash -c 'echo \"⚔ EARLY Auto-Compact triggered at 65% context usage\"; echo \"šŸ”” Compacting BEFORE API calls fail\"; echo \"šŸ“‹ Preserving critical Snow-Flow context:\"; echo \" • Active MCP connections and tool state\"; echo \" • Recent ServiceNow operations and results\"; echo \" • Current artifact sync status\"; echo \" • Authentication and session data\"; echo \"āš ļø This prevents mid-operation failures\"; echo \"āœ… Safe compact at 65% threshold\"'"
2604
2613
  }
2605
2614
  ]
2606
2615
  }
@@ -2620,6 +2629,10 @@ async function createMCPConfig(targetDir, force = false) {
2620
2629
  "CLAUDE_CODE_TIMEOUT": "0",
2621
2630
  "CLAUDE_CODE_SESSION_TIMEOUT": "0",
2622
2631
  "CLAUDE_CODE_EXECUTION_TIMEOUT": "0",
2632
+ "CLAUDE_CODE_EARLY_COMPACT": "true",
2633
+ "CLAUDE_CODE_COMPACT_THRESHOLD": "0.65",
2634
+ "CLAUDE_CODE_PRESERVE_MCP_STATE": "true",
2635
+ "CLAUDE_CODE_CONTEXT_WINDOW_BUFFER": "35",
2623
2636
  "SNOW_FLOW_DEBUG": "false",
2624
2637
  "SNOW_FLOW_LOG_LEVEL": "info",
2625
2638
  "MCP_DEBUG": "false",
@@ -21,6 +21,7 @@ export interface LocalArtifact {
21
21
  createdAt: Date;
22
22
  lastSyncedAt: Date;
23
23
  artifactConfig?: ArtifactTypeConfig;
24
+ isGeneric?: boolean;
24
25
  }
25
26
  export interface LocalFile {
26
27
  filename: string;
@@ -55,6 +56,11 @@ export declare class ArtifactLocalSync {
55
56
  * DYNAMIC push local changes back to ServiceNow using artifact registry
56
57
  */
57
58
  pushArtifact(sys_id: string): Promise<boolean>;
59
+ /**
60
+ * Push generic artifact changes back to ServiceNow
61
+ * Only updates known script fields to avoid data corruption
62
+ */
63
+ pushGenericArtifact(artifact: LocalArtifact): Promise<boolean>;
58
64
  /**
59
65
  * Push local changes back to ServiceNow
60
66
  * (Wrapper for backward compatibility)
@@ -109,9 +115,14 @@ export declare class ArtifactLocalSync {
109
115
  getSyncStatus(sys_id: string): string;
110
116
  /**
111
117
  * Pull any supported artifact type by detecting table from sys_id
112
- * ENHANCED: Better error logging and more robust detection
118
+ * ENHANCED: Now uses sys_metadata to find ANY table, not just registered ones!
113
119
  */
114
120
  pullArtifactBySysId(sys_id: string): Promise<LocalArtifact>;
121
+ /**
122
+ * Pull a generic artifact from an unknown/custom table
123
+ * Creates a basic file structure for any ServiceNow record
124
+ */
125
+ pullGenericArtifact(tableName: string, sys_id: string): Promise<LocalArtifact>;
115
126
  /**
116
127
  * Get supported artifact types
117
128
  */
@@ -254,6 +254,10 @@ class ArtifactLocalSync {
254
254
  if (!artifact) {
255
255
  throw new Error(`No local artifact found for ${sys_id}. Run pullArtifact first.`);
256
256
  }
257
+ // Handle generic artifacts differently
258
+ if (artifact.isGeneric) {
259
+ return this.pushGenericArtifact(artifact);
260
+ }
257
261
  const config = artifact.artifactConfig;
258
262
  if (!config) {
259
263
  throw new Error(`No configuration found for artifact ${sys_id}`);
@@ -354,6 +358,56 @@ class ArtifactLocalSync {
354
358
  return false;
355
359
  }
356
360
  }
361
+ /**
362
+ * Push generic artifact changes back to ServiceNow
363
+ * Only updates known script fields to avoid data corruption
364
+ */
365
+ async pushGenericArtifact(artifact) {
366
+ console.log(`\nšŸ”„ Pushing generic artifact changes to ${artifact.tableName}...`);
367
+ const updates = {};
368
+ let hasChanges = false;
369
+ // Only update known script fields for safety
370
+ const scriptFields = ['script', 'condition', 'script_plain', 'advanced',
371
+ 'client_script', 'server_script', 'template', 'body'];
372
+ for (const file of artifact.files) {
373
+ if (file.field && scriptFields.includes(file.field)) {
374
+ if (fs.existsSync(file.path)) {
375
+ const currentContent = fs.readFileSync(file.path, 'utf8');
376
+ if (currentContent !== file.originalContent) {
377
+ hasChanges = true;
378
+ updates[file.field] = currentContent;
379
+ console.log(` šŸ“ Changed: ${file.filename} (${file.field})`);
380
+ }
381
+ }
382
+ }
383
+ }
384
+ if (!hasChanges) {
385
+ console.log(`āœ… No changes detected. Generic artifact is up to date.`);
386
+ return true;
387
+ }
388
+ try {
389
+ console.log(`\nšŸ“¤ Updating generic artifact in ServiceNow...`);
390
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
391
+ const updateResult = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.updateRecord(artifact.tableName, artifact.sys_id, updates), timeoutConfig.pushToolTimeout, `Update generic artifact ${artifact.sys_id}`);
392
+ if (!updateResult || !updateResult.success) {
393
+ const errorMsg = updateResult?.error || 'Unknown API error';
394
+ console.error(`āŒ ServiceNow API returned failure: ${errorMsg}`);
395
+ artifact.syncStatus = 'pending_upload';
396
+ return false;
397
+ }
398
+ artifact.syncStatus = 'synced';
399
+ artifact.lastSyncedAt = new Date();
400
+ console.log(`āœ… Generic artifact successfully updated in ServiceNow!`);
401
+ console.log(`šŸ”— Table: ${artifact.tableName}`);
402
+ console.log(`šŸ”— sys_id: ${artifact.sys_id}`);
403
+ return true;
404
+ }
405
+ catch (error) {
406
+ console.error(`āŒ Failed to update generic artifact:`, error);
407
+ artifact.syncStatus = 'pending_upload';
408
+ return false;
409
+ }
410
+ }
357
411
  /**
358
412
  * Push local changes back to ServiceNow
359
413
  * (Wrapper for backward compatibility)
@@ -703,20 +757,43 @@ snow-flow sync status ${widget.sys_id}
703
757
  }
704
758
  /**
705
759
  * Pull any supported artifact type by detecting table from sys_id
706
- * ENHANCED: Better error logging and more robust detection
760
+ * ENHANCED: Now uses sys_metadata to find ANY table, not just registered ones!
707
761
  */
708
762
  async pullArtifactBySysId(sys_id) {
709
763
  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
764
  // CRITICAL: Add MAXIMUM operation timeout to prevent infinite hanging
712
765
  const MAX_OPERATION_TIME = 30000; // 30 seconds max for entire operation
713
766
  const operationStart = Date.now();
714
- // SMART ORDER: Check most common tables first for better performance
767
+ const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
768
+ // STEP 1: Try to find the table name using sys_metadata (works for ANY table!)
769
+ console.log(`šŸ”® Querying sys_metadata to find table name...`);
770
+ try {
771
+ const metadataResponse = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords('sys_metadata', `sys_id=${sys_id}`, 1), 5000, `Query sys_metadata for ${sys_id}`);
772
+ if (metadataResponse.result?.[0]?.sys_class_name) {
773
+ const tableName = metadataResponse.result[0].sys_class_name;
774
+ console.log(` āœ… Found in sys_metadata! Table: ${tableName}`);
775
+ // Check if this table is in our registry
776
+ if (artifact_registry_1.ARTIFACT_REGISTRY[tableName]) {
777
+ console.log(` āœ… Table is supported! Proceeding with pull...`);
778
+ return this.pullArtifact(tableName, sys_id);
779
+ }
780
+ else {
781
+ console.log(` āš ļø Table '${tableName}' is not in artifact registry`);
782
+ console.log(` šŸ”§ Attempting generic pull for custom table...`);
783
+ return this.pullGenericArtifact(tableName, sys_id);
784
+ }
785
+ }
786
+ }
787
+ catch (error) {
788
+ console.log(` āš ļø sys_metadata query failed: ${error instanceof Error ? error.message : error}`);
789
+ console.log(` šŸ“‹ Falling back to registered table search...`);
790
+ }
791
+ // STEP 2: If sys_metadata fails, try common tables first
792
+ console.log(`\nšŸ“‹ Checking ${Object.keys(artifact_registry_1.ARTIFACT_REGISTRY).length} registered tables...`);
715
793
  const allTables = Object.keys(artifact_registry_1.ARTIFACT_REGISTRY);
716
794
  const commonTables = ['sp_widget', 'sys_script_include', 'sys_script', 'sys_ui_page'];
717
795
  const otherTables = allTables.filter(t => !commonTables.includes(t));
718
796
  const tables = [...commonTables, ...otherTables]; // Common tables first
719
- const timeoutConfig = (0, mcp_timeout_config_js_1.getMCPTimeoutConfig)();
720
797
  const errors = [];
721
798
  for (const table of tables) {
722
799
  // Check if we've exceeded maximum operation time
@@ -727,7 +804,7 @@ snow-flow sync status ${widget.sys_id}
727
804
  try {
728
805
  console.log(` šŸ”Ž Checking table: ${table}...`);
729
806
  // Reduced timeout per table for faster failure
730
- const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(table, `sys_id=${sys_id}`, 1), 3000, // 3 second timeout per table (reduced from 8s)
807
+ const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(table, `sys_id=${sys_id}`, 1), 3000, // 3 second timeout per table
731
808
  `Detect table for ${sys_id}`);
732
809
  if (response.result?.[0]) {
733
810
  console.log(` āœ… Found in table: ${table}`);
@@ -742,12 +819,29 @@ snow-flow sync status ${widget.sys_id}
742
819
  const errorMsg = error instanceof Error ? error.message : String(error);
743
820
  console.log(` āš ļø Error checking ${table}: ${errorMsg}`);
744
821
  errors.push({ table, error: errorMsg });
745
- // Don't fail on permission errors, timeouts, etc. - keep trying other tables
822
+ }
823
+ }
824
+ // STEP 3: Try a few common custom tables as last resort
825
+ const customTables = ['sys_ui_script', 'sys_processor', 'sys_ws_operation', 'sys_portal_page'];
826
+ console.log(`\nšŸ” Checking additional custom tables...`);
827
+ for (const table of customTables) {
828
+ if (Date.now() - operationStart > MAX_OPERATION_TIME)
829
+ break;
830
+ try {
831
+ console.log(` šŸ”Ž Checking custom table: ${table}...`);
832
+ const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(table, `sys_id=${sys_id}`, 1), 3000, `Check custom table ${table}`);
833
+ if (response.result?.[0]) {
834
+ console.log(` āœ… Found in custom table: ${table}`);
835
+ return this.pullGenericArtifact(table, sys_id);
836
+ }
837
+ }
838
+ catch (error) {
839
+ // Silent fail for custom tables
746
840
  }
747
841
  }
748
842
  // Generate detailed error message
749
843
  console.log(`\nāŒ Artifact detection failed!`);
750
- console.log(`šŸ” Searched ${tables.length} tables for sys_id: ${sys_id}`);
844
+ console.log(`šŸ” Searched sys_metadata + ${tables.length} registered tables + ${customTables.length} custom tables`);
751
845
  if (errors.length > 0) {
752
846
  console.log(`\nāš ļø Errors encountered:`);
753
847
  errors.forEach(({ table, error }) => {
@@ -757,9 +851,92 @@ snow-flow sync status ${widget.sys_id}
757
851
  console.log(`\nšŸ’” Troubleshooting tips:`);
758
852
  console.log(` 1. Verify the sys_id exists in ServiceNow`);
759
853
  console.log(` 2. Check your permissions for the target table`);
760
- console.log(` 3. Try specifying the table explicitly: snow_pull_artifact({sys_id, table: 'sp_widget'})`);
761
- console.log(` 4. Supported tables: ${tables.join(', ')}`);
762
- throw new Error(`Could not find artifact with sys_id ${sys_id} in any supported table. See details above.`);
854
+ console.log(` 3. Try specifying the table explicitly: snow_pull_artifact({sys_id, table: 'table_name'})`);
855
+ console.log(` 4. The artifact might be in a custom or scoped application table`);
856
+ throw new Error(`Could not find artifact with sys_id ${sys_id}. It may be in a custom table or you may lack permissions.`);
857
+ }
858
+ /**
859
+ * Pull a generic artifact from an unknown/custom table
860
+ * Creates a basic file structure for any ServiceNow record
861
+ */
862
+ async pullGenericArtifact(tableName, sys_id) {
863
+ console.log(`\nšŸ”§ Pulling generic artifact from custom table: ${tableName}`);
864
+ try {
865
+ // Fetch the record with all fields
866
+ const response = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.searchRecords(tableName, `sys_id=${sys_id}`, 1), 10000, `Fetch generic artifact from ${tableName}`);
867
+ const record = response.result?.[0];
868
+ if (!record) {
869
+ throw new Error(`Record not found in ${tableName}`);
870
+ }
871
+ // Create a generic folder structure
872
+ const name = record.name || record.short_description || record.sys_name || sys_id;
873
+ const sanitizedName = this.sanitizeFilename(name);
874
+ const artifactPath = path.join(this.baseDir, 'custom', tableName, sanitizedName);
875
+ // Clean up existing files
876
+ if (fs.existsSync(artifactPath)) {
877
+ fs.rmSync(artifactPath, { recursive: true });
878
+ }
879
+ fs.mkdirSync(artifactPath, { recursive: true });
880
+ const files = [];
881
+ // Create JSON file with all fields
882
+ const jsonFile = this.createLocalFile(artifactPath, `${sanitizedName}.json`, JSON.stringify(record, null, 2), 'all_fields', 'json');
883
+ files.push(jsonFile);
884
+ // Extract common script fields if they exist
885
+ const scriptFields = ['script', 'condition', 'script_plain', 'advanced',
886
+ 'client_script', 'server_script', 'template', 'body'];
887
+ for (const field of scriptFields) {
888
+ if (record[field] && typeof record[field] === 'string' && record[field].trim()) {
889
+ const ext = field.includes('template') || field === 'body' ? 'html' : 'js';
890
+ const scriptFile = this.createLocalFile(artifactPath, `${sanitizedName}.${field}.${ext}`, record[field], field, ext);
891
+ files.push(scriptFile);
892
+ }
893
+ }
894
+ // Create README
895
+ const readmeContent = `# Generic Artifact: ${name}\n\n` +
896
+ `**Table:** ${tableName}\n` +
897
+ `**Sys ID:** ${sys_id}\n` +
898
+ `**Created:** ${record.sys_created_on || 'Unknown'}\n` +
899
+ `**Updated:** ${record.sys_updated_on || 'Unknown'}\n\n` +
900
+ `## Notice\n\n` +
901
+ `This is a generic artifact from a custom/unknown table.\n` +
902
+ `Snow-Flow has created a basic file structure to allow editing.\n\n` +
903
+ `## Files\n\n` +
904
+ `- **${sanitizedName}.json** - Complete record data\n` +
905
+ (files.length > 1 ? files.slice(1).map(f => `- **${f.filename}** - ${f.field} field content\n`).join('') : '') +
906
+ `\n## Push Support\n\n` +
907
+ `Generic artifacts have limited push support. ` +
908
+ `Only script fields will be updated when pushing back.\n`;
909
+ const readmeFile = this.createLocalFile(artifactPath, 'README.md', readmeContent, 'documentation', 'md');
910
+ files.push(readmeFile);
911
+ // Create artifact record
912
+ const artifact = {
913
+ sys_id: sys_id,
914
+ name: name,
915
+ type: `Custom (${tableName})`,
916
+ tableName: tableName,
917
+ localPath: artifactPath,
918
+ files: files,
919
+ metadata: record,
920
+ syncStatus: 'synced',
921
+ createdAt: new Date(),
922
+ lastSyncedAt: new Date(),
923
+ isGeneric: true // Mark as generic for special handling
924
+ };
925
+ this.artifacts.set(sys_id, artifact);
926
+ const relativePath = path.relative(process.cwd(), artifactPath);
927
+ const displayPath = relativePath.startsWith('..') ? artifactPath : relativePath;
928
+ console.log(`āœ… Generic artifact pulled successfully!`);
929
+ console.log(`šŸ“ Location: ${displayPath}`);
930
+ console.log(`šŸ“„ Files created:`);
931
+ files.forEach(f => console.log(` - ${f.filename} (${f.type})`));
932
+ console.log(`\nāš ļø Note: This is a generic pull from a custom table.`);
933
+ console.log(` Full push support may be limited.`);
934
+ return artifact;
935
+ }
936
+ catch (error) {
937
+ console.error(`āŒ Failed to pull generic artifact:`, error);
938
+ throw error;
939
+ }
763
940
  }
764
941
  /**
765
942
  * Get supported artifact types
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.6.3",
4
- "description": "EMERGENCY FIX: Prevents infinite hanging in servicenow-local-development. v3.6.3 adds maximum operation timeouts (30s for artifact detection, 60s for progress indicator) to prevent operations from running forever. Fixes pullArtifactBySysId with fail-fast mechanism. Consolidated CLAUDE.md with ALL 18 MCP servers and 200+ tools. NO MOCK DATA policy enforced. Includes audit logging, token tracking, and ES5 enforcement.",
3
+ "version": "3.6.5",
4
+ "description": "UNIVERSAL ARTIFACT DETECTION via sys_metadata! v3.6.5 can now find ANY ServiceNow record by sys_id alone - even custom tables. Generic artifact support for unknown tables. Smarter pullArtifactBySysId that queries sys_metadata first. Auto-creates editable file structure for ANY table type. Includes early auto-compact at 65%, audit logging, and consolidated CLAUDE.md.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",
7
7
  "bin": {