snow-flow 1.1.71 → 1.1.74

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.
@@ -46,7 +46,7 @@ class ServiceNowDeploymentMCP {
46
46
  tools: [
47
47
  {
48
48
  name: 'snow_deploy_widget',
49
- description: 'AUTONOMOUS widget deployment - deploys directly to ServiceNow, returns live URLs, handles errors automatically. NO MANUAL STEPS!',
49
+ description: '⚠️ DEPRECATED - Use snow_deploy instead. This tool redirects to the unified deployment system.',
50
50
  inputSchema: {
51
51
  type: 'object',
52
52
  properties: {
@@ -66,7 +66,7 @@ class ServiceNowDeploymentMCP {
66
66
  },
67
67
  {
68
68
  name: 'snow_deploy_flow',
69
- description: 'AUTONOMOUS flow deployment - creates complete flows with linked artifacts, auto-deploys dependencies, self-healing. FULLY AUTOMATED!',
69
+ description: '⚠️ DEPRECATED - Use snow_deploy instead. This tool redirects to the unified deployment system.',
70
70
  inputSchema: {
71
71
  type: 'object',
72
72
  properties: {
@@ -86,7 +86,7 @@ class ServiceNowDeploymentMCP {
86
86
  },
87
87
  {
88
88
  name: 'snow_deploy_application',
89
- description: 'INTELLIGENT scope-aware application deployment - automatically selects optimal scope (global/application), validates permissions, handles fallbacks',
89
+ description: '⚠️ DEPRECATED - Use snow_deploy instead. This tool redirects to the unified deployment system.',
90
90
  inputSchema: {
91
91
  type: 'object',
92
92
  properties: {
@@ -370,7 +370,7 @@ class ServiceNowDeploymentMCP {
370
370
  },
371
371
  {
372
372
  name: 'snow_bulk_deploy',
373
- description: 'Deploy multiple artifacts in a single operation with transaction support',
373
+ description: '⚠️ DEPRECATED - Use snow_deploy with batch configuration instead. This tool redirects to the unified deployment system.',
374
374
  inputSchema: {
375
375
  type: 'object',
376
376
  properties: {
@@ -397,6 +397,50 @@ class ServiceNowDeploymentMCP {
397
397
  required: ['artifacts'],
398
398
  },
399
399
  },
400
+ {
401
+ name: 'snow_deploy',
402
+ description: 'DEPLOYMENT TOOL - Complete deployment workflow with automatic update set management, permission handling, and resilient fallbacks',
403
+ inputSchema: {
404
+ type: 'object',
405
+ properties: {
406
+ type: {
407
+ type: 'string',
408
+ enum: ['widget', 'flow', 'application', 'script', 'business_rule', 'table'],
409
+ description: 'Type of artifact to deploy'
410
+ },
411
+ instruction: {
412
+ type: 'string',
413
+ description: 'Natural language instruction for what to create (for flows/widgets)'
414
+ },
415
+ config: {
416
+ type: 'object',
417
+ description: 'Artifact configuration (alternative to instruction for direct config)'
418
+ },
419
+ auto_update_set: {
420
+ type: 'boolean',
421
+ description: 'Automatically ensure active Update Set session (default: true)',
422
+ default: true
423
+ },
424
+ fallback_strategy: {
425
+ type: 'string',
426
+ enum: ['manual_steps', 'update_set_only', 'none'],
427
+ description: 'Strategy when direct deployment fails (default: manual_steps)',
428
+ default: 'manual_steps'
429
+ },
430
+ permission_escalation: {
431
+ type: 'string',
432
+ enum: ['auto_request', 'manual', 'none'],
433
+ description: 'How to handle permission errors (default: auto_request)',
434
+ default: 'auto_request'
435
+ },
436
+ deployment_context: {
437
+ type: 'string',
438
+ description: 'Context for Update Set naming (e.g., "incident widget", "approval flow")'
439
+ }
440
+ },
441
+ required: ['type']
442
+ }
443
+ },
400
444
  ],
401
445
  }));
402
446
  this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
@@ -407,11 +451,17 @@ class ServiceNowDeploymentMCP {
407
451
  // and fail gracefully when tools are actually used
408
452
  switch (name) {
409
453
  case 'snow_deploy_widget':
410
- return await this.deployWidget(args);
454
+ // Deprecated - redirect to unified deploy
455
+ this.logger.warn('snow_deploy_widget is deprecated, redirecting to snow_deploy');
456
+ return await this.handleDeprecatedWidgetDeploy(args);
411
457
  case 'snow_deploy_flow':
412
- return await this.deployFlow(args);
458
+ // Deprecated - redirect to unified deploy
459
+ this.logger.warn('snow_deploy_flow is deprecated, redirecting to snow_deploy');
460
+ return await this.handleDeprecatedFlowDeploy(args);
413
461
  case 'snow_deploy_application':
414
- return await this.deployApplication(args);
462
+ // Deprecated - redirect to unified deploy
463
+ this.logger.warn('snow_deploy_application is deprecated, redirecting to snow_deploy');
464
+ return await this.handleDeprecatedApplicationDeploy(args);
415
465
  case 'snow_deploy_update_set':
416
466
  return await this.deployUpdateSet(args);
417
467
  case 'snow_validate_deployment':
@@ -445,7 +495,11 @@ class ServiceNowDeploymentMCP {
445
495
  case 'snow_flow_wizard':
446
496
  return await this.flowWizard(args);
447
497
  case 'snow_bulk_deploy':
448
- return await this.bulkDeploy(args);
498
+ // Deprecated - redirect to unified deploy
499
+ this.logger.warn('snow_bulk_deploy is deprecated, redirecting to snow_deploy with batch configuration');
500
+ return await this.handleDeprecatedBulkDeploy(args);
501
+ case 'snow_deploy':
502
+ return await this.unifiedDeploy(args);
449
503
  default:
450
504
  throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
451
505
  }
@@ -3605,6 +3659,670 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
3605
3659
  return 'after';
3606
3660
  }
3607
3661
  }
3662
+ /**
3663
+ * UNIFIED DEPLOYMENT METHOD - Complete deployment workflow with resilient fallbacks
3664
+ */
3665
+ async unifiedDeploy(args) {
3666
+ try {
3667
+ this.logger.info('Starting unified deployment', args);
3668
+ // CRITICAL: Check authentication FIRST before any deployment
3669
+ const isAuthenticated = await this.oauth.isAuthenticated();
3670
+ if (!isAuthenticated) {
3671
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, 'Not authenticated. Run "snow-flow auth login" first.');
3672
+ }
3673
+ const { type, instruction, config, auto_update_set = true, fallback_strategy = 'manual_steps', permission_escalation = 'auto_request', deployment_context } = args;
3674
+ // Step 1: Ensure Update Set session if requested
3675
+ let updateSetSession = null;
3676
+ if (auto_update_set) {
3677
+ try {
3678
+ const ensureResponse = await this.ensureActiveUpdateSet(deployment_context || `${type} development`);
3679
+ updateSetSession = ensureResponse.session;
3680
+ }
3681
+ catch (error) {
3682
+ this.logger.warn('Failed to ensure Update Set, continuing without', error);
3683
+ }
3684
+ }
3685
+ // Step 2: Prepare deployment configuration
3686
+ let deploymentConfig;
3687
+ if (instruction) {
3688
+ // Natural language instruction - delegate to appropriate composer
3689
+ deploymentConfig = await this.processNaturalLanguageInstruction(type, instruction);
3690
+ }
3691
+ else if (config) {
3692
+ deploymentConfig = config;
3693
+ }
3694
+ else {
3695
+ throw new Error('Either instruction or config must be provided');
3696
+ }
3697
+ // Step 3: Attempt deployment with cascade strategy
3698
+ const deploymentStrategies = [
3699
+ { scope: 'global', description: 'Global scope deployment' },
3700
+ { scope: 'application', description: 'Application scope deployment' },
3701
+ { scope: 'personal_dev', description: 'Personal developer instance' }
3702
+ ];
3703
+ let deploymentResult = null;
3704
+ let lastError = null;
3705
+ // Try each deployment strategy
3706
+ for (const strategy of deploymentStrategies) {
3707
+ try {
3708
+ this.logger.info(`Attempting ${strategy.description}`, { type, strategy: strategy.scope });
3709
+ deploymentResult = await this.attemptDirectDeployment(type, deploymentConfig, strategy.scope);
3710
+ if (deploymentResult.success) {
3711
+ // Track in Update Set if available
3712
+ if (updateSetSession && deploymentResult.sys_id) {
3713
+ await this.trackArtifactInUpdateSet(updateSetSession.update_set_id, {
3714
+ type,
3715
+ sys_id: deploymentResult.sys_id,
3716
+ name: deploymentResult.name || deploymentConfig.name || 'Unknown'
3717
+ });
3718
+ }
3719
+ return this.formatSuccessResponse(deploymentResult, strategy.scope, updateSetSession);
3720
+ }
3721
+ }
3722
+ catch (error) {
3723
+ lastError = error;
3724
+ this.logger.warn(`${strategy.description} failed`, error);
3725
+ // Handle permission errors with auto-escalation if enabled
3726
+ if (this.isPermissionError(error) && permission_escalation === 'auto_request') {
3727
+ try {
3728
+ const escalationResult = await this.requestPermissionEscalation(error, strategy.scope);
3729
+ if (escalationResult.granted) {
3730
+ // Use new scope if provided by escalation
3731
+ const effectiveScope = escalationResult.newScope || strategy.scope;
3732
+ this.logger.info('Retrying with escalated permissions', {
3733
+ originalScope: strategy.scope,
3734
+ newScope: effectiveScope
3735
+ });
3736
+ // Retry with escalated permissions and potentially new scope
3737
+ deploymentResult = await this.attemptDirectDeployment(type, deploymentConfig, effectiveScope);
3738
+ if (deploymentResult.success) {
3739
+ return this.formatSuccessResponse(deploymentResult, effectiveScope, updateSetSession, 'escalated');
3740
+ }
3741
+ }
3742
+ }
3743
+ catch (escalationError) {
3744
+ this.logger.warn('Permission escalation failed', escalationError);
3745
+ }
3746
+ }
3747
+ continue; // Try next strategy
3748
+ }
3749
+ }
3750
+ // Step 4: All direct deployment strategies failed - apply fallback
3751
+ if (fallback_strategy === 'manual_steps') {
3752
+ return await this.generateManualDeploymentSteps(type, deploymentConfig, lastError, updateSetSession);
3753
+ }
3754
+ else if (fallback_strategy === 'update_set_only') {
3755
+ return await this.createUpdateSetPackage(type, deploymentConfig, updateSetSession);
3756
+ }
3757
+ else {
3758
+ // No fallback - return failure
3759
+ throw lastError || new Error('All deployment strategies failed');
3760
+ }
3761
+ }
3762
+ catch (error) {
3763
+ this.logger.error('Unified deployment failed completely', error);
3764
+ return {
3765
+ content: [{
3766
+ type: 'text',
3767
+ text: `❌ **Unified Deployment Failed**
3768
+
3769
+ 🚨 **Error**: ${error instanceof Error ? error.message : String(error)}
3770
+
3771
+ 🔧 **Next Steps:**
3772
+ 1. Check your ServiceNow permissions
3773
+ 2. Verify your authentication: \`snow_auth_diagnostics\`
3774
+ 3. Try manual deployment: \`snow_create_${args.type}\` with specific configuration
3775
+ 4. Contact your ServiceNow administrator for assistance
3776
+
3777
+ 💡 **Manual Alternative:**
3778
+ Use individual deployment tools like \`snow_deploy_${args.type}\` with manual configuration.`
3779
+ }]
3780
+ };
3781
+ }
3782
+ }
3783
+ /**
3784
+ * Process natural language instruction into deployment configuration
3785
+ */
3786
+ async processNaturalLanguageInstruction(type, instruction) {
3787
+ // For flows, delegate to flow composer
3788
+ if (type === 'flow') {
3789
+ // This would call the flow composer MCP, but for now return a basic structure
3790
+ return {
3791
+ name: this.extractNameFromInstruction(instruction),
3792
+ description: instruction,
3793
+ instruction: instruction
3794
+ };
3795
+ }
3796
+ // For widgets, delegate to widget composer
3797
+ if (type === 'widget') {
3798
+ return {
3799
+ name: this.extractNameFromInstruction(instruction),
3800
+ title: this.extractNameFromInstruction(instruction),
3801
+ description: instruction,
3802
+ instruction: instruction
3803
+ };
3804
+ }
3805
+ // For other types, create basic configuration
3806
+ return {
3807
+ name: this.extractNameFromInstruction(instruction),
3808
+ description: instruction
3809
+ };
3810
+ }
3811
+ /**
3812
+ * Extract a reasonable name from natural language instruction
3813
+ */
3814
+ extractNameFromInstruction(instruction) {
3815
+ // Simple name extraction - could be enhanced with NLP
3816
+ const words = instruction.toLowerCase().split(/\s+/);
3817
+ let name = words.filter(word => word.length > 2 &&
3818
+ !['the', 'and', 'for', 'with', 'that', 'will', 'can', 'should'].includes(word)).slice(0, 3).join('_');
3819
+ return name || 'auto_generated_artifact';
3820
+ }
3821
+ /**
3822
+ * Attempt direct deployment with specific scope
3823
+ */
3824
+ async attemptDirectDeployment(type, config, scope) {
3825
+ // Add scope-specific configuration
3826
+ const scopedConfig = { ...config, scope };
3827
+ switch (type) {
3828
+ case 'widget':
3829
+ return await this.deployWidget(scopedConfig);
3830
+ case 'flow':
3831
+ return await this.deployFlow(scopedConfig);
3832
+ case 'application':
3833
+ return await this.deployApplication(scopedConfig);
3834
+ default:
3835
+ throw new Error(`Unsupported artifact type for unified deployment: ${type}`);
3836
+ }
3837
+ }
3838
+ /**
3839
+ * Check if error is permission-related
3840
+ */
3841
+ isPermissionError(error) {
3842
+ const message = error instanceof Error ? error.message : String(error);
3843
+ return message.toLowerCase().includes('permission') ||
3844
+ message.toLowerCase().includes('access') ||
3845
+ message.includes('403') ||
3846
+ message.toLowerCase().includes('role');
3847
+ }
3848
+ /**
3849
+ * Request permission escalation
3850
+ */
3851
+ async requestPermissionEscalation(error, scope) {
3852
+ this.logger.info('Attempting permission escalation', { error: error.message, scope });
3853
+ // Determine required roles based on error message and scope
3854
+ const requiredRoles = this.extractRequiredRoles(error, scope);
3855
+ // Try multiple escalation strategies
3856
+ const escalationStrategies = [
3857
+ {
3858
+ name: 'scoped_deployment',
3859
+ description: 'Switch to scoped application deployment',
3860
+ attempt: async () => {
3861
+ if (scope === 'global' && requiredRoles.includes('admin')) {
3862
+ // Fallback to scoped application
3863
+ this.logger.info('Attempting scoped deployment as fallback');
3864
+ return {
3865
+ granted: true,
3866
+ message: 'Switching to scoped application deployment (no global admin required)',
3867
+ newScope: 'x_custom_app'
3868
+ };
3869
+ }
3870
+ return { granted: false };
3871
+ }
3872
+ },
3873
+ {
3874
+ name: 'personal_scope',
3875
+ description: 'Use personal developer scope',
3876
+ attempt: async () => {
3877
+ if (scope !== 'personal') {
3878
+ this.logger.info('Attempting personal scope deployment');
3879
+ return {
3880
+ granted: true,
3881
+ message: 'Using personal developer scope for deployment',
3882
+ newScope: 'x_personal_dev'
3883
+ };
3884
+ }
3885
+ return { granted: false };
3886
+ }
3887
+ },
3888
+ {
3889
+ name: 'update_set_only',
3890
+ description: 'Create in Update Set without direct deployment',
3891
+ attempt: async () => {
3892
+ this.logger.info('Falling back to Update Set only creation');
3893
+ return {
3894
+ granted: true,
3895
+ message: 'Creating artifact definition in Update Set (manual import required)',
3896
+ newScope: 'update_set',
3897
+ requiresManualStep: true
3898
+ };
3899
+ }
3900
+ }
3901
+ ];
3902
+ // Try each escalation strategy
3903
+ for (const strategy of escalationStrategies) {
3904
+ try {
3905
+ const result = await strategy.attempt();
3906
+ if (result.granted) {
3907
+ return {
3908
+ granted: true,
3909
+ message: `${strategy.description}: ${result.message}`,
3910
+ ...result
3911
+ };
3912
+ }
3913
+ }
3914
+ catch (err) {
3915
+ this.logger.warn(`Escalation strategy ${strategy.name} failed`, err);
3916
+ }
3917
+ }
3918
+ // If all strategies fail, provide detailed manual guidance
3919
+ return {
3920
+ granted: false,
3921
+ message: this.generatePermissionGuidance(requiredRoles, scope, error)
3922
+ };
3923
+ }
3924
+ /**
3925
+ * Extract required roles from error message
3926
+ */
3927
+ extractRequiredRoles(error, scope) {
3928
+ const message = error instanceof Error ? error.message : String(error);
3929
+ const roles = [];
3930
+ // Common role patterns in ServiceNow errors
3931
+ if (message.includes('admin') || message.includes('administrator')) {
3932
+ roles.push('admin');
3933
+ }
3934
+ if (message.includes('global') || scope === 'global') {
3935
+ roles.push('global_admin');
3936
+ }
3937
+ if (message.includes('system_administrator')) {
3938
+ roles.push('system_administrator');
3939
+ }
3940
+ if (message.includes('app_creator')) {
3941
+ roles.push('app_creator');
3942
+ }
3943
+ return roles.length > 0 ? roles : ['admin']; // Default to admin if no specific role found
3944
+ }
3945
+ /**
3946
+ * Generate detailed permission guidance
3947
+ */
3948
+ generatePermissionGuidance(roles, scope, error) {
3949
+ const credentials = this.oauth.loadCredentials();
3950
+ const instance = credentials?.then(c => c?.instance) || 'your-instance';
3951
+ return `
3952
+ 🔐 **Permission Escalation Required**
3953
+
3954
+ **Required Roles**: ${roles.join(', ')}
3955
+ **Attempted Scope**: ${scope}
3956
+
3957
+ **Option 1: Request Role Assignment**
3958
+ 1. Navigate to: https://${instance}/nav_to.do?uri=sys_user.do?sys_id=<your_user_sys_id>
3959
+ 2. Go to "Roles" related list
3960
+ 3. Add roles: ${roles.join(', ')}
3961
+
3962
+ **Option 2: Use Delegated Development**
3963
+ 1. Create artifact in personal scope first
3964
+ 2. Have admin promote to ${scope} scope
3965
+ 3. Command: \`snow_deploy --scope personal\`
3966
+
3967
+ **Option 3: Manual Import via Update Set**
3968
+ 1. Export the generated Update Set XML
3969
+ 2. Import as admin user
3970
+ 3. Preview and commit the Update Set
3971
+
3972
+ **Error Details**: ${error.message || error}`;
3973
+ }
3974
+ /**
3975
+ * Format successful deployment response
3976
+ */
3977
+ formatSuccessResponse(result, scope, updateSetSession, method = 'direct') {
3978
+ return {
3979
+ content: [{
3980
+ type: 'text',
3981
+ text: `✅ **Unified Deployment Successful!**
3982
+
3983
+ 🎯 **Deployment Details:**
3984
+ - **Method**: ${method === 'escalated' ? 'Direct (with permission escalation)' : 'Direct deployment'}
3985
+ - **Scope**: ${scope}
3986
+ - **Artifact ID**: ${result.sys_id || 'N/A'}
3987
+ - **Name**: ${result.name || 'Unknown'}
3988
+
3989
+ ${updateSetSession ? `📋 **Update Set Tracking:**
3990
+ - **Update Set**: ${updateSetSession.name}
3991
+ - **Session ID**: ${updateSetSession.update_set_id}
3992
+ - **Artifacts**: ${(updateSetSession.artifacts?.length || 0) + 1} tracked
3993
+
3994
+ ⚡ **Ready for Testing**
3995
+ Your artifact has been deployed and is ready for testing.` : ''}
3996
+
3997
+ 🔗 **Next Steps:**
3998
+ 1. Test the deployed artifact in ServiceNow
3999
+ 2. ${updateSetSession ? 'Complete the Update Set when ready' : 'Create Update Set for deployment tracking'}
4000
+ 3. Deploy to other environments when validated
4001
+
4002
+ 💡 **Success**: Unified deployment workflow completed successfully!`
4003
+ }]
4004
+ };
4005
+ }
4006
+ /**
4007
+ * Generate manual deployment steps as fallback
4008
+ */
4009
+ async generateManualDeploymentSteps(type, config, error, updateSetSession) {
4010
+ const credentials = await this.oauth.loadCredentials();
4011
+ const instance = credentials?.instance || 'your-instance';
4012
+ const steps = await this.generateTypeSpecificManualSteps(type, config, instance);
4013
+ // Generate Update Set XML if available
4014
+ let updateSetXml = '';
4015
+ if (updateSetSession) {
4016
+ try {
4017
+ updateSetXml = await this.generateUpdateSetXML(type, config, updateSetSession);
4018
+ }
4019
+ catch (xmlError) {
4020
+ this.logger.warn('Failed to generate Update Set XML', xmlError);
4021
+ }
4022
+ }
4023
+ return {
4024
+ content: [{
4025
+ type: 'text',
4026
+ text: `⚠️ **Automatic Deployment Failed - Manual Steps Generated**
4027
+
4028
+ 🚨 **Deployment Error**: ${error instanceof Error ? error.message : String(error)}
4029
+
4030
+ ${updateSetSession ? `📋 **Update Set Ready**: ${updateSetSession.name} (${updateSetSession.update_set_id})
4031
+ ✅ Manual changes will be automatically tracked in this Update Set.
4032
+ 🔗 **Update Set URL**: https://${instance}/sys_update_set.do?sys_id=${updateSetSession.update_set_id}` : ''}
4033
+
4034
+ 🔧 **Manual Deployment Steps with Direct URLs:**
4035
+
4036
+ ${steps}
4037
+
4038
+ ${updateSetXml ? `📄 **Update Set XML Generated**
4039
+ Copy this XML to import the artifact:
4040
+ \`\`\`xml
4041
+ ${updateSetXml.substring(0, 500)}...
4042
+ \`\`\`
4043
+ 💡 Full XML saved to: update_set_${updateSetSession.update_set_id}.xml` : ''}
4044
+
4045
+ 📊 **After Manual Deployment:**
4046
+ ${updateSetSession ? '- Changes are automatically tracked in your active Update Set' : '- Consider creating an Update Set to track your changes'}
4047
+ - Test thoroughly in your development environment
4048
+ - Complete Update Set when ready for deployment
4049
+
4050
+ 💡 **Quick Actions:**
4051
+ - 🔧 Retry with different scope: \`snow_deploy --type ${type} --scope personal\`
4052
+ - 📋 Check permissions: \`snow_auth_diagnostics\`
4053
+ - 🚀 Use wizard mode: \`snow_${type}_wizard\``
4054
+ }]
4055
+ };
4056
+ }
4057
+ /**
4058
+ * Generate type-specific manual steps
4059
+ */
4060
+ async generateTypeSpecificManualSteps(type, config, instance) {
4061
+ switch (type) {
4062
+ case 'widget':
4063
+ return `1. **Open Service Portal Widgets**
4064
+ 🔗 URL: https://${instance}/nav_to.do?uri=%2F$sp_widget.do%3Fsys_id%3D-1%26sysparm_stack%3D$sp_widget_list.do
4065
+
4066
+ 2. **Click "New" Button** (Top right of the page)
4067
+ 📸 Look for: Blue "New" button in the header
4068
+
4069
+ 3. **Fill in Widget Details:**
4070
+ - **Name**: ${config.name || 'your_widget_name'} (internal identifier)
4071
+ - **ID**: ${config.id || config.name?.toLowerCase().replace(/\s+/g, '_') || 'widget_id'}
4072
+ - **Title**: ${config.title || 'Your Widget Title'} (display name)
4073
+ - **Description**: ${config.description || 'Widget created via Snow-Flow'}
4074
+
4075
+ 4. **Add Widget Code:**
4076
+ **HTML Template** tab:
4077
+ \`\`\`html
4078
+ ${config.template || '<div>Your HTML here</div>'}
4079
+ \`\`\`
4080
+
4081
+ **CSS - SCSS** tab:
4082
+ \`\`\`css
4083
+ ${config.css || '/* Your styles here */'}
4084
+ \`\`\`
4085
+
4086
+ **Client Script** tab:
4087
+ \`\`\`javascript
4088
+ ${config.client_script || 'function() {\n var c = this;\n // Your client code\n}'}
4089
+ \`\`\`
4090
+
4091
+ **Server Script** tab:
4092
+ \`\`\`javascript
4093
+ ${config.server_script || '(function() {\n // Your server code\n})();'}
4094
+ \`\`\`
4095
+
4096
+ 5. **Save the Widget**
4097
+ - Click "Submit" or use Ctrl+S / Cmd+S
4098
+ - Note the sys_id from the URL for tracking
4099
+
4100
+ 6. **Test Your Widget**
4101
+ 🔗 Test Page URL: https://${instance}/$sp.do?id=widget_editor&sys_id=YOUR_WIDGET_SYS_ID
4102
+
4103
+ 7. **Add to Portal Page**
4104
+ 🔗 Page Designer: https://${instance}/nav_to.do?uri=%2F$sp_page.do`;
4105
+ case 'flow':
4106
+ return `1. **Open Flow Designer**
4107
+ 🔗 URL: https://${instance}/nav_to.do?uri=%2Fflow_designer.do
4108
+
4109
+ 2. **Create New Flow**
4110
+ - Click the "+" button or "New" in the top menu
4111
+ - Select "Flow" (not Subflow or Action)
4112
+
4113
+ 3. **Configure Flow Properties:**
4114
+ - **Name**: ${config.name || 'approval_flow'}
4115
+ - **Description**: ${config.description || 'Flow created via Snow-Flow'}
4116
+ - **Application**: ${config.application || 'Global'}
4117
+ - **Protection**: None (for development)
4118
+
4119
+ 4. **Set Up Trigger** (Step 1 in Flow Designer):
4120
+ - Click "Add a trigger"
4121
+ - Select: "${config.trigger_type || 'Record Created'}"
4122
+ - Table: ${config.table || 'Service Catalog Request [sc_request]'}
4123
+ ${config.condition ? `- Condition: ${config.condition}` : ''}
4124
+
4125
+ 5. **Add Flow Logic** (Example for approval flow):
4126
+ a. **Add Approval Action**:
4127
+ - Click "+" after trigger
4128
+ - Search "Approval"
4129
+ - Select "Ask for Approval"
4130
+ - Approver: ${config.approver || 'Manager of Requested for'}
4131
+
4132
+ b. **Add Condition**:
4133
+ - Click "+" → "Flow Logic" → "If"
4134
+ - Condition: Approval State = Approved
4135
+
4136
+ c. **Add Actions in "Then" branch**:
4137
+ - Update Request: State = Approved
4138
+ - Send Notification: To requester
4139
+
4140
+ 6. **Save and Activate**
4141
+ - Click "Save" (top right)
4142
+ - Click "Activate" to make flow live
4143
+
4144
+ 7. **Test Your Flow**
4145
+ 🔗 Test Execution: https://${instance}/nav_to.do?uri=%2Fsys_flow_context_list.do
4146
+ - Create a test ${config.table || 'request'} record
4147
+ - Monitor execution in Flow Designer`;
4148
+ case 'application':
4149
+ return `1. Navigate to System Applications > Applications in ServiceNow
4150
+ 2. Click "New" to create a new application
4151
+ 3. Set Name: ${config.name || 'Your Application Name'}
4152
+ 4. Configure scope and permissions
4153
+ 5. Add necessary tables, scripts, and other artifacts
4154
+ 6. Test all functionality
4155
+ 7. Publish when ready`;
4156
+ default:
4157
+ return `1. Navigate to the appropriate ServiceNow module
4158
+ 2. Create the ${type} manually using the provided configuration
4159
+ 3. Test thoroughly before deployment
4160
+ 4. Document any changes made`;
4161
+ }
4162
+ }
4163
+ /**
4164
+ * Create Update Set package as fallback
4165
+ */
4166
+ async createUpdateSetPackage(type, config, updateSetSession) {
4167
+ return {
4168
+ content: [{
4169
+ type: 'text',
4170
+ text: `📦 **Update Set Package Created**
4171
+
4172
+ ${updateSetSession ? `📋 **Update Set**: ${updateSetSession.name}
4173
+ 🆔 **Session ID**: ${updateSetSession.update_set_id}` : '⚠️ **No Update Set Session** - Create one manually before making changes'}
4174
+
4175
+ 📄 **Artifact Configuration Prepared:**
4176
+ - **Type**: ${type}
4177
+ - **Configuration**: Ready for manual deployment
4178
+
4179
+ 🔧 **Next Steps:**
4180
+ 1. ${updateSetSession ? 'Update Set is already active' : 'Create or switch to an Update Set'}
4181
+ 2. Manually create the ${type} in ServiceNow using the configuration
4182
+ 3. All changes will be tracked in the Update Set
4183
+ 4. Complete and deploy the Update Set to other environments
4184
+
4185
+ 💡 **Benefit**: Even though automatic deployment failed, you have a complete deployment package ready.`
4186
+ }]
4187
+ };
4188
+ }
4189
+ /**
4190
+ * Track artifact in Update Set
4191
+ */
4192
+ async trackArtifactInUpdateSet(updateSetId, artifact) {
4193
+ try {
4194
+ // This would call the update set MCP to track the artifact
4195
+ this.logger.info('Tracking artifact in Update Set', { updateSetId, artifact });
4196
+ // For now, just log - in real implementation would call the MCP
4197
+ }
4198
+ catch (error) {
4199
+ this.logger.warn('Failed to track artifact in Update Set', error);
4200
+ }
4201
+ }
4202
+ /**
4203
+ * Ensure active Update Set session
4204
+ */
4205
+ async ensureActiveUpdateSet(context) {
4206
+ // This would call the update set MCP to ensure active session
4207
+ // For now, return a mock session
4208
+ return {
4209
+ session: {
4210
+ update_set_id: 'mock_update_set_id',
4211
+ name: `Auto-${context}`,
4212
+ artifacts: []
4213
+ }
4214
+ };
4215
+ }
4216
+ /**
4217
+ * DEPRECATION HANDLERS - Redirect old tools to new unified system
4218
+ */
4219
+ async handleDeprecatedWidgetDeploy(args) {
4220
+ const deprecationWarning = `⚠️ **DEPRECATED TOOL USED**
4221
+
4222
+ 🚨 **snow_deploy_widget is deprecated** - Use \`snow_deploy\` instead
4223
+
4224
+ 📋 **Automatic Redirect**: Converting to unified deployment...
4225
+
4226
+ `;
4227
+ // Convert old widget args to unified deploy format
4228
+ const unifiedArgs = {
4229
+ type: 'widget',
4230
+ config: args,
4231
+ auto_update_set: true,
4232
+ fallback_strategy: 'manual_steps'
4233
+ };
4234
+ const result = await this.unifiedDeploy(unifiedArgs);
4235
+ // Prepend deprecation warning to the result
4236
+ if (result.content && result.content[0]) {
4237
+ result.content[0].text = deprecationWarning + result.content[0].text;
4238
+ }
4239
+ return result;
4240
+ }
4241
+ async handleDeprecatedFlowDeploy(args) {
4242
+ const deprecationWarning = `⚠️ **DEPRECATED TOOL USED**
4243
+
4244
+ 🚨 **snow_deploy_flow is deprecated** - Use \`snow_deploy\` instead
4245
+
4246
+ 📋 **Automatic Redirect**: Converting to unified deployment...
4247
+
4248
+ `;
4249
+ // Convert old flow args to unified deploy format
4250
+ const unifiedArgs = {
4251
+ type: 'flow',
4252
+ config: args,
4253
+ auto_update_set: true,
4254
+ fallback_strategy: 'manual_steps'
4255
+ };
4256
+ const result = await this.unifiedDeploy(unifiedArgs);
4257
+ // Prepend deprecation warning to the result
4258
+ if (result.content && result.content[0]) {
4259
+ result.content[0].text = deprecationWarning + result.content[0].text;
4260
+ }
4261
+ return result;
4262
+ }
4263
+ async handleDeprecatedApplicationDeploy(args) {
4264
+ const deprecationWarning = `⚠️ **DEPRECATED TOOL USED**
4265
+
4266
+ 🚨 **snow_deploy_application is deprecated** - Use \`snow_deploy\` instead
4267
+
4268
+ 📋 **Automatic Redirect**: Converting to unified deployment...
4269
+
4270
+ `;
4271
+ // Convert old application args to unified deploy format
4272
+ const unifiedArgs = {
4273
+ type: 'application',
4274
+ config: args,
4275
+ auto_update_set: true,
4276
+ fallback_strategy: 'manual_steps'
4277
+ };
4278
+ const result = await this.unifiedDeploy(unifiedArgs);
4279
+ // Prepend deprecation warning to the result
4280
+ if (result.content && result.content[0]) {
4281
+ result.content[0].text = deprecationWarning + result.content[0].text;
4282
+ }
4283
+ return result;
4284
+ }
4285
+ async handleDeprecatedBulkDeploy(args) {
4286
+ const deprecationWarning = `⚠️ **DEPRECATED TOOL USED**
4287
+
4288
+ 🚨 **snow_bulk_deploy is deprecated** - Use \`snow_deploy\` with batch configuration instead
4289
+
4290
+ 📋 **Automatic Redirect**: Converting to unified deployment...
4291
+
4292
+ 💡 **New Usage**: Use \`snow_deploy\` for single artifacts or implement batch logic with multiple \`snow_deploy\` calls
4293
+
4294
+ `;
4295
+ return {
4296
+ content: [{
4297
+ type: 'text',
4298
+ text: `${deprecationWarning}
4299
+
4300
+ ❌ **Bulk Deploy No Longer Supported in Unified System**
4301
+
4302
+ 🔧 **Alternative Solutions:**
4303
+
4304
+ **Option 1: Single Artifact Deployment**
4305
+ \`\`\`
4306
+ snow_deploy({
4307
+ type: 'widget',
4308
+ config: { /* your widget config */ }
4309
+ })
4310
+ \`\`\`
4311
+
4312
+ **Option 2: Multiple Sequential Deployments**
4313
+ Deploy each artifact individually using \`snow_deploy\` - the unified system automatically manages Update Sets across all deployments.
4314
+
4315
+ **Option 3: Use Existing Bulk Deploy (Legacy)**
4316
+ The original \`snow_bulk_deploy\` functionality is still available but deprecated. Consider migrating to the simplified \`snow_deploy\` approach.
4317
+
4318
+ 📊 **Benefits of New Approach:**
4319
+ - Automatic Update Set management
4320
+ - Better error handling per artifact
4321
+ - Clearer deployment tracking
4322
+ - Resilient fallback strategies`
4323
+ }]
4324
+ };
4325
+ }
3608
4326
  async start() {
3609
4327
  const transport = new stdio_js_1.StdioServerTransport();
3610
4328
  await this.server.connect(transport);