snow-flow 4.5.21 → 4.5.23

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/CLAUDE.md CHANGED
@@ -524,20 +524,25 @@ Snow-Flow includes 18 specialized MCP servers, each providing comprehensive Serv
524
524
  - Property validation
525
525
 
526
526
  ### 7. ServiceNow Update Set Server
527
- **Purpose:** Change management and deployment
527
+ **Purpose:** Change management and deployment with automatic user synchronization
528
528
 
529
529
  **Key Tools:**
530
530
  - `snow_create_update_set` - Create new update sets
531
- - `snow_switch_update_set` - Switch active update set
531
+ - `snow_ensure_active_update_set` - Ensure active Update Set (auto-syncs current)
532
+ - `snow_sync_current_update_set` - **NEW:** Sync user's current Update Set with Snow-Flow
532
533
  - `snow_complete_update_set` - Mark as complete
533
534
  - `snow_preview_update_set` - Preview changes
534
535
  - `snow_export_update_set` - Export as XML
535
536
 
537
+ **🆕 AUTO-SYNC FEATURE:**
538
+ Snow-Flow now automatically sets its Update Set as the user's current Update Set in ServiceNow. This prevents confusion where Snow-Flow works in one Update Set while the user sees a different current Update Set.
539
+
536
540
  **Features:**
537
- - Full update set lifecycle
538
- - Change tracking
539
- - XML export/import
540
- - Conflict detection
541
+ - **Automatic current Update Set synchronization** - user and Snow-Flow always in same Update Set
542
+ - Full update set lifecycle management
543
+ - Change tracking and artifact management
544
+ - XML export/import capabilities
545
+ - Conflict detection and resolution
541
546
 
542
547
  ### 8. ServiceNow Development Assistant Server
543
548
  **Purpose:** Code generation and best practices
@@ -1281,19 +1281,34 @@ ${executionList}
1281
1281
  suggestion: 'Install Agent Workspace plugin: System Applications → All Available Applications → Search for "Agent Workspace"'
1282
1282
  };
1283
1283
  }
1284
+ // Fix from user feedback: Add ALL required fields for workspace creation
1285
+ const workspaceUrl = this.generateWorkspaceUrl(args.name);
1284
1286
  const workspaceData = {
1285
1287
  name: args.name,
1286
1288
  description: args.description || '',
1289
+ active: true,
1290
+ // CRITICAL: Add missing required fields
1291
+ workspace_url: workspaceUrl,
1292
+ navigation_type: 'tab',
1293
+ search_enabled: true,
1294
+ notifications_enabled: true,
1295
+ user_preference_controls_enabled: true,
1296
+ // Add default colors for branding
1297
+ primary_color: '#1F8476',
1298
+ brand_color: '#2FC2B0',
1299
+ // These will be updated after search config creation
1300
+ global_search: '',
1301
+ global_search_data: '',
1302
+ // Optional fields with defaults
1287
1303
  tables: args.tables ? args.tables.join(',') : '',
1288
1304
  home_page: args.home_page || '',
1289
1305
  theme: args.theme || 'default',
1290
- roles: args.roles ? args.roles.join(',') : '',
1291
- active: true
1306
+ roles: args.roles ? args.roles.join(',') : ''
1292
1307
  };
1293
1308
  this.logger.trackAPICall('CREATE', 'sys_aw_master_config', 1);
1294
1309
  const response = await this.client.createRecord('sys_aw_master_config', workspaceData);
1295
1310
  if (!response.success) {
1296
- // Provide specific error guidance
1311
+ // Enhanced error handling with required fields info
1297
1312
  if (response.error?.includes('403') || response.error?.includes('Forbidden')) {
1298
1313
  return {
1299
1314
  success: false,
@@ -1304,12 +1319,52 @@ ${executionList}
1304
1319
  if (response.error?.includes('400') || response.error?.includes('Bad Request')) {
1305
1320
  return {
1306
1321
  success: false,
1307
- error: 'Invalid workspace configuration. Agent Workspace may not be properly configured in this instance.',
1308
- suggestion: 'Verify Agent Workspace is enabled and configured. Check System Properties > Agent Workspace settings.'
1322
+ error: 'Invalid workspace configuration. Missing required fields detected.',
1323
+ suggestion: 'Verify all required fields: workspace_url, navigation_type, search settings.',
1324
+ remediation: 'Check ServiceNow Agent Workspace documentation for required field specifications'
1309
1325
  };
1310
1326
  }
1311
1327
  throw new Error(`Failed to create workspace: ${response.error}`);
1312
1328
  }
1329
+ const workspaceId = response.data.sys_id;
1330
+ // Fix from user feedback: Create global search config and update workspace
1331
+ try {
1332
+ const searchConfig = await this.client.createRecord('sys_aw_global_search_config', {
1333
+ name: `${args.name} Search`,
1334
+ workspace: workspaceId,
1335
+ active: true
1336
+ });
1337
+ if (searchConfig.success && searchConfig.data.sys_id) {
1338
+ // Update workspace with search config references
1339
+ await this.client.updateRecord('sys_aw_master_config', workspaceId, {
1340
+ global_search: searchConfig.data.sys_id,
1341
+ global_search_data: searchConfig.data.sys_id
1342
+ });
1343
+ }
1344
+ }
1345
+ catch (searchError) {
1346
+ this.logger.warn('Could not create search config, workspace created without search:', searchError);
1347
+ }
1348
+ // Fix from user feedback: Create tabs for each table automatically
1349
+ if (args.tables && args.tables.length > 0) {
1350
+ for (let i = 0; i < args.tables.length; i++) {
1351
+ const table = args.tables[i];
1352
+ const tabLabel = table.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
1353
+ try {
1354
+ await this.client.createRecord('sys_aw_tab', {
1355
+ workspace: workspaceId,
1356
+ table: table,
1357
+ label: tabLabel,
1358
+ name: `${table}_tab`,
1359
+ order: (i + 1) * 100,
1360
+ active: true
1361
+ });
1362
+ }
1363
+ catch (tabError) {
1364
+ this.logger.warn(`Could not create tab for table ${table}:`, tabError);
1365
+ }
1366
+ }
1367
+ }
1313
1368
  return {
1314
1369
  content: [{
1315
1370
  type: 'text',
@@ -2871,6 +2926,37 @@ ${configList}${layoutsText}${offlineText}
2871
2926
  throw error;
2872
2927
  }
2873
2928
  }
2929
+ /**
2930
+ * Generate valid workspace URL from name (fix from user feedback)
2931
+ */
2932
+ generateWorkspaceUrl(name) {
2933
+ return name
2934
+ .toLowerCase()
2935
+ .trim()
2936
+ .replace(/\s+/g, '-') // Spaces -> hyphens
2937
+ .replace(/[^a-z0-9-]/g, '') // Remove special characters
2938
+ .replace(/--+/g, '-') // Multiple hyphens -> single
2939
+ .replace(/^-|-$/g, '') // Trim leading/trailing hyphens
2940
+ .substring(0, 80); // Max 80 chars (ServiceNow field limit)
2941
+ }
2942
+ /**
2943
+ * Validate workspace configuration (fix from user feedback)
2944
+ */
2945
+ validateWorkspaceConfig(config) {
2946
+ const errors = [];
2947
+ // Check required fields
2948
+ if (!config.name)
2949
+ errors.push('name is required');
2950
+ if (!config.workspace_url)
2951
+ errors.push('workspace_url is required');
2952
+ if (!config.navigation_type)
2953
+ errors.push('navigation_type is required');
2954
+ // Validate workspace_url format
2955
+ if (config.workspace_url && !/^[a-z0-9-]+$/.test(config.workspace_url)) {
2956
+ errors.push('workspace_url must contain only lowercase letters, numbers and hyphens');
2957
+ }
2958
+ return errors;
2959
+ }
2874
2960
  async run() {
2875
2961
  const transport = new stdio_js_1.StdioServerTransport();
2876
2962
  await this.server.connect(transport);
@@ -263,6 +263,9 @@ class ServiceNowUpdateSetMCP {
263
263
  case 'snow_ensure_active_update_set':
264
264
  result = await this.ensureActiveUpdateSet(args);
265
265
  break;
266
+ case 'snow_sync_current_update_set':
267
+ result = await this.syncCurrentUpdateSet(args);
268
+ break;
266
269
  default:
267
270
  throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
268
271
  }
@@ -663,20 +666,19 @@ ${changes.length > 20 ? `\n... and ${changes.length - 20} more changes` : ''}
663
666
  this.logger.info('Ensuring active Update Set session', args);
664
667
  // Check if we already have an active session
665
668
  if (this.currentSession?.state === 'in_progress') {
669
+ // Also sync current Update Set if requested
670
+ if (args.set_as_current !== false) {
671
+ await this.syncCurrentUpdateSet({ force_switch: true });
672
+ }
666
673
  return {
667
- content: [{
668
- type: 'text',
669
- text: `✅ **Active Update Set Session Found**
670
-
671
- 📋 **Current Session:**
672
- - **Name**: ${this.currentSession.name}
673
- - **ID**: ${this.currentSession.update_set_id}
674
- - **Created**: ${new Date(this.currentSession.created_at).toLocaleString()}
675
- - **Artifacts**: ${this.currentSession.artifacts?.length || 0} tracked
676
-
677
- ⚡ **Ready for Deployment**
678
- All subsequent changes will be tracked in this Update Set.`
679
- }]
674
+ success: true,
675
+ message: 'Active Update Set session found and synchronized',
676
+ update_set: {
677
+ name: this.currentSession.name,
678
+ sys_id: this.currentSession.update_set_id,
679
+ artifacts_count: this.currentSession.artifacts?.length || 0
680
+ },
681
+ synchronized: args.set_as_current !== false
680
682
  };
681
683
  }
682
684
  // Auto-create if requested (default: true)
@@ -737,6 +739,86 @@ snow_update_set_create({
737
739
  .map(([type, count]) => `- ${type}: ${count}`)
738
740
  .join('\n');
739
741
  }
742
+ /**
743
+ * NEW: Synchronize user's current Update Set with Snow-Flow's active Update Set
744
+ */
745
+ async syncCurrentUpdateSet(args) {
746
+ try {
747
+ this.logger.info('Synchronizing user current Update Set with Snow-Flow session...');
748
+ if (!this.currentSession) {
749
+ return {
750
+ success: false,
751
+ error: 'No active Snow-Flow Update Set session found.',
752
+ suggestion: 'Run snow_ensure_active_update_set first to create or activate an Update Set.'
753
+ };
754
+ }
755
+ // Set Snow-Flow Update Set as current for user via script
756
+ const syncScript = `
757
+ // Synchronize user's current Update Set with Snow-Flow session
758
+ var updateSetId = '${this.currentSession.update_set_id}';
759
+ var currentUser = gs.getUserID();
760
+
761
+ // Get current Update Set info
762
+ var updateSet = new GlideRecord('sys_update_set');
763
+ if (updateSet.get(updateSetId)) {
764
+ gs.info('Snow-Flow Update Set found: ' + updateSet.name);
765
+
766
+ // Set as current for user via session variable
767
+ gs.getSession().putProperty('update_set', updateSetId);
768
+ gs.info('Set as current Update Set for user: ' + updateSet.name);
769
+
770
+ // Also try to set via user preference
771
+ var pref = new GlideRecord('sys_user_preference');
772
+ pref.addQuery('user', currentUser);
773
+ pref.addQuery('name', 'update_set.current');
774
+ pref.query();
775
+
776
+ if (pref.next()) {
777
+ pref.value = updateSetId;
778
+ pref.update();
779
+ gs.info('Updated user preference for current Update Set');
780
+ } else {
781
+ var newPref = new GlideRecord('sys_user_preference');
782
+ newPref.initialize();
783
+ newPref.user = currentUser;
784
+ newPref.name = 'update_set.current';
785
+ newPref.value = updateSetId;
786
+ newPref.insert();
787
+ gs.info('Created user preference for current Update Set');
788
+ }
789
+
790
+ gs.info('SYNC COMPLETE: User current Update Set = Snow-Flow session Update Set');
791
+ } else {
792
+ gs.error('Snow-Flow Update Set not found: ' + updateSetId);
793
+ }
794
+ `;
795
+ const scriptResponse = await this.client.executeScript(syncScript);
796
+ if (!scriptResponse.success) {
797
+ return {
798
+ success: false,
799
+ error: 'Failed to synchronize current Update Set',
800
+ suggestion: 'Check ServiceNow connection and Update Set permissions',
801
+ update_set_id: this.currentSession.update_set_id
802
+ };
803
+ }
804
+ return {
805
+ success: true,
806
+ message: `Current Update Set synchronized with Snow-Flow session`,
807
+ update_set_name: this.currentSession.name,
808
+ update_set_id: this.currentSession.update_set_id,
809
+ sync_method: 'session_variable_and_user_preference',
810
+ sync_status: 'completed'
811
+ };
812
+ }
813
+ catch (error) {
814
+ this.logger.error('Failed to sync current Update Set:', error);
815
+ return {
816
+ success: false,
817
+ error: error instanceof Error ? error.message : String(error),
818
+ suggestion: 'Check ServiceNow connection and permissions'
819
+ };
820
+ }
821
+ }
740
822
  async run() {
741
823
  const transport = new stdio_js_1.StdioServerTransport();
742
824
  await this.server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "4.5.21",
3
+ "version": "4.5.23",
4
4
  "description": "Conversational ServiceNow development platform using Claude Code. Multi-agent orchestration with 20+ MCP servers providing 200+ ServiceNow tools for comprehensive platform development.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",