snow-flow 1.1.42 → 1.1.43

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.
@@ -368,6 +368,35 @@ class ServiceNowDeploymentMCP {
368
368
  required: ['name'],
369
369
  },
370
370
  },
371
+ {
372
+ name: 'snow_bulk_deploy',
373
+ description: 'Deploy multiple artifacts in a single operation with transaction support',
374
+ inputSchema: {
375
+ type: 'object',
376
+ properties: {
377
+ artifacts: {
378
+ type: 'array',
379
+ description: 'Array of artifacts to deploy',
380
+ items: {
381
+ type: 'object',
382
+ properties: {
383
+ type: { type: 'string', enum: ['widget', 'flow', 'script', 'business_rule', 'table', 'application'] },
384
+ sys_id: { type: 'string', description: 'Existing artifact sys_id (for updates)' },
385
+ config: { type: 'object', description: 'Artifact configuration' },
386
+ action: { type: 'string', enum: ['create', 'update', 'deploy'], default: 'deploy' },
387
+ },
388
+ required: ['type', 'config'],
389
+ },
390
+ },
391
+ transaction_mode: { type: 'boolean', description: 'All or nothing deployment', default: true },
392
+ parallel: { type: 'boolean', description: 'Deploy in parallel when possible', default: false },
393
+ dry_run: { type: 'boolean', description: 'Validate without deploying', default: false },
394
+ update_set_name: { type: 'string', description: 'Custom update set name' },
395
+ rollback_on_error: { type: 'boolean', description: 'Rollback all on any failure', default: true },
396
+ },
397
+ required: ['artifacts'],
398
+ },
399
+ },
371
400
  ],
372
401
  }));
373
402
  this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
@@ -415,6 +444,8 @@ class ServiceNowDeploymentMCP {
415
444
  return await this.createSolutionPackage(args);
416
445
  case 'snow_flow_wizard':
417
446
  return await this.flowWizard(args);
447
+ case 'snow_bulk_deploy':
448
+ return await this.bulkDeploy(args);
418
449
  default:
419
450
  throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
420
451
  }
@@ -2625,6 +2656,327 @@ Use \`snow_preview_widget\` to see a detailed preview of the widget rendering.`,
2625
2656
  throw new Error(`Flow wizard failed: ${error instanceof Error ? error.message : String(error)}`);
2626
2657
  }
2627
2658
  }
2659
+ /**
2660
+ * Bulk Deploy Multiple Artifacts
2661
+ */
2662
+ async bulkDeploy(args) {
2663
+ try {
2664
+ const { artifacts, transaction_mode = true, parallel = false, dry_run = false, update_set_name, rollback_on_error = true } = args;
2665
+ this.logger.info(`Starting bulk deployment of ${artifacts.length} artifacts`);
2666
+ // Create or ensure update set
2667
+ if (update_set_name) {
2668
+ await this.client.createUpdateSet({
2669
+ name: update_set_name,
2670
+ description: 'Bulk deployment from Snow-Flow',
2671
+ state: 'in_progress'
2672
+ });
2673
+ }
2674
+ else {
2675
+ await this.client.ensureUpdateSet();
2676
+ }
2677
+ const results = {
2678
+ total: artifacts.length,
2679
+ successful: 0,
2680
+ failed: 0,
2681
+ skipped: 0,
2682
+ details: []
2683
+ };
2684
+ // Track deployed artifacts for rollback
2685
+ const deployedArtifacts = [];
2686
+ try {
2687
+ if (dry_run) {
2688
+ // Validation only
2689
+ for (const artifact of artifacts) {
2690
+ try {
2691
+ const validation = await this.validateArtifact(artifact);
2692
+ results.details.push({
2693
+ type: artifact.type,
2694
+ name: artifact.config?.name || 'Unknown',
2695
+ status: validation.valid ? '✅ Valid' : '❌ Invalid',
2696
+ message: validation.message
2697
+ });
2698
+ if (validation.valid) {
2699
+ results.successful++;
2700
+ }
2701
+ else {
2702
+ results.failed++;
2703
+ }
2704
+ }
2705
+ catch (error) {
2706
+ results.failed++;
2707
+ results.details.push({
2708
+ type: artifact.type,
2709
+ name: artifact.config?.name || 'Unknown',
2710
+ status: '❌ Error',
2711
+ message: error instanceof Error ? error.message : String(error)
2712
+ });
2713
+ }
2714
+ }
2715
+ }
2716
+ else {
2717
+ // Actual deployment
2718
+ if (parallel && !transaction_mode) {
2719
+ // Parallel deployment (no transaction support)
2720
+ const deploymentPromises = artifacts.map(async (artifact) => {
2721
+ try {
2722
+ const result = await this.deployArtifact(artifact);
2723
+ if (result.success) {
2724
+ deployedArtifacts.push({ type: artifact.type, sys_id: result.sys_id });
2725
+ results.successful++;
2726
+ results.details.push({
2727
+ type: artifact.type,
2728
+ name: artifact.config?.name || 'Unknown',
2729
+ sys_id: result.sys_id,
2730
+ status: '✅ Deployed',
2731
+ message: result.message
2732
+ });
2733
+ }
2734
+ else {
2735
+ throw new Error(result.message);
2736
+ }
2737
+ }
2738
+ catch (error) {
2739
+ results.failed++;
2740
+ results.details.push({
2741
+ type: artifact.type,
2742
+ name: artifact.config?.name || 'Unknown',
2743
+ status: '❌ Failed',
2744
+ message: error instanceof Error ? error.message : String(error)
2745
+ });
2746
+ if (transaction_mode && rollback_on_error) {
2747
+ throw error; // Will trigger rollback
2748
+ }
2749
+ }
2750
+ });
2751
+ await Promise.all(deploymentPromises);
2752
+ }
2753
+ else {
2754
+ // Sequential deployment (supports transactions)
2755
+ for (const artifact of artifacts) {
2756
+ try {
2757
+ const result = await this.deployArtifact(artifact);
2758
+ if (result.success) {
2759
+ deployedArtifacts.push({ type: artifact.type, sys_id: result.sys_id });
2760
+ results.successful++;
2761
+ results.details.push({
2762
+ type: artifact.type,
2763
+ name: artifact.config?.name || 'Unknown',
2764
+ sys_id: result.sys_id,
2765
+ status: '✅ Deployed',
2766
+ message: result.message
2767
+ });
2768
+ }
2769
+ else {
2770
+ throw new Error(result.message);
2771
+ }
2772
+ }
2773
+ catch (error) {
2774
+ results.failed++;
2775
+ results.details.push({
2776
+ type: artifact.type,
2777
+ name: artifact.config?.name || 'Unknown',
2778
+ status: '❌ Failed',
2779
+ message: error instanceof Error ? error.message : String(error)
2780
+ });
2781
+ if (transaction_mode && rollback_on_error) {
2782
+ throw error; // Will trigger rollback
2783
+ }
2784
+ }
2785
+ }
2786
+ }
2787
+ }
2788
+ }
2789
+ catch (error) {
2790
+ // Rollback if needed
2791
+ if (rollback_on_error && deployedArtifacts.length > 0) {
2792
+ this.logger.info(`Rolling back ${deployedArtifacts.length} deployed artifacts`);
2793
+ for (const deployed of deployedArtifacts) {
2794
+ try {
2795
+ await this.rollbackArtifact(deployed);
2796
+ results.details.push({
2797
+ type: deployed.type,
2798
+ sys_id: deployed.sys_id,
2799
+ status: '🔄 Rolled back',
2800
+ message: 'Artifact rolled back due to deployment failure'
2801
+ });
2802
+ }
2803
+ catch (rollbackError) {
2804
+ this.logger.error(`Failed to rollback ${deployed.type} ${deployed.sys_id}:`, rollbackError);
2805
+ }
2806
+ }
2807
+ }
2808
+ throw error;
2809
+ }
2810
+ // Generate summary
2811
+ let summary = `🚀 Bulk Deployment ${dry_run ? 'Validation' : 'Complete'}\n\n`;
2812
+ summary += `📊 Summary:\n`;
2813
+ summary += ` Total: ${results.total}\n`;
2814
+ summary += ` ✅ Successful: ${results.successful}\n`;
2815
+ summary += ` ❌ Failed: ${results.failed}\n`;
2816
+ if (results.skipped > 0) {
2817
+ summary += ` ⏭️ Skipped: ${results.skipped}\n`;
2818
+ }
2819
+ summary += `\n📋 Details:\n`;
2820
+ for (const detail of results.details) {
2821
+ summary += `\n${detail.status} ${detail.type}: ${detail.name}`;
2822
+ if (detail.sys_id) {
2823
+ summary += ` (${detail.sys_id})`;
2824
+ }
2825
+ if (detail.message) {
2826
+ summary += `\n ${detail.message}`;
2827
+ }
2828
+ }
2829
+ if (transaction_mode && !dry_run) {
2830
+ summary += `\n\n🔒 Transaction Mode: ${results.failed === 0 ? 'All deployed successfully' : 'Rolled back due to failures'}`;
2831
+ }
2832
+ return {
2833
+ content: [{
2834
+ type: 'text',
2835
+ text: summary
2836
+ }]
2837
+ };
2838
+ }
2839
+ catch (error) {
2840
+ throw new Error(`Bulk deployment failed: ${error instanceof Error ? error.message : String(error)}`);
2841
+ }
2842
+ }
2843
+ /**
2844
+ * Deploy a single artifact
2845
+ */
2846
+ async deployArtifact(artifact) {
2847
+ const { type, sys_id, config, action = 'deploy' } = artifact;
2848
+ try {
2849
+ switch (type) {
2850
+ case 'widget':
2851
+ if (action === 'update' && sys_id) {
2852
+ const result = await this.client.updateRecord('sp_widget', sys_id, config);
2853
+ return {
2854
+ success: result.success,
2855
+ sys_id: sys_id,
2856
+ message: result.success ? 'Widget updated' : result.error
2857
+ };
2858
+ }
2859
+ else {
2860
+ const result = await this.deployWidget(config);
2861
+ return {
2862
+ success: result.content[0].text.includes('✅'),
2863
+ sys_id: result.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
2864
+ message: 'Widget deployed'
2865
+ };
2866
+ }
2867
+ case 'flow':
2868
+ const flowResult = await this.deployFlow(config);
2869
+ return {
2870
+ success: flowResult.content[0].text.includes('✅'),
2871
+ sys_id: flowResult.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
2872
+ message: 'Flow deployed'
2873
+ };
2874
+ case 'script':
2875
+ case 'script_include':
2876
+ const scriptResult = await this.client.createRecord('sys_script_include', config);
2877
+ return {
2878
+ success: scriptResult.success,
2879
+ sys_id: scriptResult.data?.sys_id,
2880
+ message: scriptResult.success ? 'Script deployed' : scriptResult.error
2881
+ };
2882
+ case 'business_rule':
2883
+ const ruleResult = await this.client.createRecord('sys_script', config);
2884
+ return {
2885
+ success: ruleResult.success,
2886
+ sys_id: ruleResult.data?.sys_id,
2887
+ message: ruleResult.success ? 'Business rule deployed' : ruleResult.error
2888
+ };
2889
+ case 'table':
2890
+ const tableResult = await this.client.createRecord('sys_db_object', config);
2891
+ return {
2892
+ success: tableResult.success,
2893
+ sys_id: tableResult.data?.sys_id,
2894
+ message: tableResult.success ? 'Table created' : tableResult.error
2895
+ };
2896
+ case 'application':
2897
+ const appResult = await this.deployApplication(config);
2898
+ return {
2899
+ success: appResult.content[0].text.includes('✅'),
2900
+ sys_id: appResult.content[0].text.match(/sys_id: ([a-f0-9]+)/)?.[1],
2901
+ message: 'Application deployed'
2902
+ };
2903
+ default:
2904
+ return {
2905
+ success: false,
2906
+ message: `Unknown artifact type: ${type}`
2907
+ };
2908
+ }
2909
+ }
2910
+ catch (error) {
2911
+ return {
2912
+ success: false,
2913
+ message: error instanceof Error ? error.message : String(error)
2914
+ };
2915
+ }
2916
+ }
2917
+ /**
2918
+ * Validate artifact before deployment
2919
+ */
2920
+ async validateArtifact(artifact) {
2921
+ const { type, config } = artifact;
2922
+ // Basic validation
2923
+ if (!type || !config) {
2924
+ return { valid: false, message: 'Missing type or config' };
2925
+ }
2926
+ // Type-specific validation
2927
+ switch (type) {
2928
+ case 'widget':
2929
+ if (!config.name || !config.template) {
2930
+ return { valid: false, message: 'Widget requires name and template' };
2931
+ }
2932
+ break;
2933
+ case 'flow':
2934
+ if (!config.name || !config.definition) {
2935
+ return { valid: false, message: 'Flow requires name and definition' };
2936
+ }
2937
+ break;
2938
+ case 'script':
2939
+ case 'script_include':
2940
+ if (!config.name || !config.script) {
2941
+ return { valid: false, message: 'Script requires name and script content' };
2942
+ }
2943
+ break;
2944
+ case 'business_rule':
2945
+ if (!config.name || !config.collection || !config.script) {
2946
+ return { valid: false, message: 'Business rule requires name, collection, and script' };
2947
+ }
2948
+ break;
2949
+ case 'table':
2950
+ if (!config.name || !config.label) {
2951
+ return { valid: false, message: 'Table requires name and label' };
2952
+ }
2953
+ break;
2954
+ case 'application':
2955
+ if (!config.name || !config.scope) {
2956
+ return { valid: false, message: 'Application requires name and scope' };
2957
+ }
2958
+ break;
2959
+ }
2960
+ return { valid: true, message: 'Validation passed' };
2961
+ }
2962
+ /**
2963
+ * Rollback deployed artifact
2964
+ */
2965
+ async rollbackArtifact(artifact) {
2966
+ const tableMap = {
2967
+ 'widget': 'sp_widget',
2968
+ 'flow': 'sys_hub_flow',
2969
+ 'script': 'sys_script_include',
2970
+ 'script_include': 'sys_script_include',
2971
+ 'business_rule': 'sys_script',
2972
+ 'table': 'sys_db_object',
2973
+ 'application': 'sys_app'
2974
+ };
2975
+ const table = tableMap[artifact.type];
2976
+ if (table) {
2977
+ await this.client.deleteRecord(table, artifact.sys_id);
2978
+ }
2979
+ }
2628
2980
  /**
2629
2981
  * Extract dependencies from flow definition
2630
2982
  */