snow-flow 2.0.2 → 2.0.4

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.
Files changed (173) hide show
  1. package/{.claude/mcp-config.json → .mcp.json} +13 -12
  2. package/.releaserc.json +47 -0
  3. package/README.md +48 -1
  4. package/package.json +1 -1
  5. package/.claude/claude-settings.json +0 -15
  6. package/.claude/commands/analysis/README.md +0 -9
  7. package/.claude/commands/automation/README.md +0 -9
  8. package/.claude/commands/github/README.md +0 -11
  9. package/.claude/commands/helpers/standard-checkpoint-hooks.sh +0 -179
  10. package/.claude/commands/hooks/README.md +0 -11
  11. package/.claude/commands/monitoring/README.md +0 -9
  12. package/.claude/commands/optimization/README.md +0 -9
  13. package/.claude/commands/training/README.md +0 -9
  14. package/.claude/commands/workflows/README.md +0 -9
  15. package/.claude/config.json +0 -36
  16. package/.claude/helpers/github-setup.sh +0 -28
  17. package/.claude/helpers/quick-start.sh +0 -19
  18. package/.claude/helpers/setup-mcp.sh +0 -18
  19. package/.claude/settings.json +0 -114
  20. package/.claude/settings.local.json +0 -33
  21. package/.claude-flow/metrics/agent-metrics.json +0 -1
  22. package/.claude-flow/metrics/performance.json +0 -9
  23. package/.claude-flow/metrics/system-metrics.json +0 -15986
  24. package/.claude-flow/metrics/task-metrics.json +0 -10
  25. package/.roo/README.md +0 -402
  26. package/.roo/mcp-list.txt +0 -257
  27. package/.roo/mcp.json +0 -32
  28. package/.roo/workflows/basic-tdd.json +0 -32
  29. package/.roomodes +0 -201
  30. package/CLAUDE.md +0 -393
  31. package/bin/snow-flow.js +0 -3
  32. package/dist/cli.js.bak +0 -2052
  33. package/dist/config/snow-flow-config.d.ts +0 -1492
  34. package/dist/config/snow-flow-config.js +0 -938
  35. package/scripts/create-env.js +0 -91
  36. package/scripts/postinstall.js +0 -30
  37. package/scripts/register-mcp-servers.js +0 -210
  38. package/scripts/reset-mcp-servers.js +0 -246
  39. package/scripts/setup-mcp.js +0 -106
  40. package/scripts/update-version.js +0 -31
  41. package/src/agents/README.md +0 -192
  42. package/src/agents/base-agent.ts +0 -251
  43. package/src/agents/coordinator.ts +0 -971
  44. package/src/agents/index.ts +0 -18
  45. package/src/agents/queen-403-handler.ts +0 -230
  46. package/src/agents/queen-agent.ts +0 -1399
  47. package/src/agents/script-writer-agent.ts +0 -769
  48. package/src/agents/security-agent.ts +0 -726
  49. package/src/agents/widget-creator-agent.ts +0 -568
  50. package/src/api/error-handling.ts +0 -1758
  51. package/src/api/natural-language-mapper.ts +0 -630
  52. package/src/api/performance-optimizer.ts +0 -891
  53. package/src/api/transaction-manager.ts +0 -754
  54. package/src/cli/deploy-artifact.ts +0 -304
  55. package/src/cli/snow-flow-cli-integration.ts +0 -434
  56. package/src/cli.ts +0 -4455
  57. package/src/cli.ts.bak +0 -5616
  58. package/src/compliance/advanced-compliance-system.ts +0 -1268
  59. package/src/compliance/index.ts +0 -19
  60. package/src/config/snow-flow-config.ts +0 -1019
  61. package/src/documentation/index.ts +0 -16
  62. package/src/documentation/self-documenting-system.ts +0 -1421
  63. package/src/dynamic-version.ts +0 -44
  64. package/src/healing/index.ts +0 -20
  65. package/src/healing/self-healing-system.ts +0 -1435
  66. package/src/health/README.md +0 -161
  67. package/src/health/system-health.ts +0 -995
  68. package/src/index.ts +0 -60
  69. package/src/intelligence/acl-analyzer.ts +0 -377
  70. package/src/intelligence/auto-resolution-engine.ts +0 -643
  71. package/src/intelligence/gap-analysis-engine.ts +0 -488
  72. package/src/intelligence/manual-instructions-generator.ts +0 -744
  73. package/src/intelligence/mcp-coverage-analyzer.ts +0 -708
  74. package/src/intelligence/multi-pass-requirements-analyzer.ts +0 -603
  75. package/src/intelligence/performance-recommendations-engine.ts +0 -1223
  76. package/src/intelligence/requirements-analyzer.ts +0 -1148
  77. package/src/intelligence/task-analyzer.ts +0 -628
  78. package/src/managers/scope-manager.ts +0 -555
  79. package/src/mcp/advanced/servicenow-advanced-features-mcp.ts +0 -16110
  80. package/src/mcp/base-mcp-server.ts +0 -660
  81. package/src/mcp/http-transport-wrapper.ts +0 -426
  82. package/src/mcp/service-discovery-client.ts +0 -312
  83. package/src/mcp/servicenow-automation-mcp-refactored.ts +0 -678
  84. package/src/mcp/servicenow-automation-mcp.ts +0 -838
  85. package/src/mcp/servicenow-deployment-mcp-refactored.ts +0 -1292
  86. package/src/mcp/servicenow-deployment-mcp.ts +0 -7244
  87. package/src/mcp/servicenow-graph-memory-mcp-refactored.ts +0 -721
  88. package/src/mcp/servicenow-graph-memory-mcp.ts +0 -832
  89. package/src/mcp/servicenow-integration-mcp-refactored.ts +0 -655
  90. package/src/mcp/servicenow-integration-mcp.ts +0 -819
  91. package/src/mcp/servicenow-intelligent-mcp-refactored.ts +0 -977
  92. package/src/mcp/servicenow-intelligent-mcp.ts +0 -4638
  93. package/src/mcp/servicenow-mcp-server.ts +0 -728
  94. package/src/mcp/servicenow-memory-mcp.ts +0 -474
  95. package/src/mcp/servicenow-operations-mcp-refactored.ts +0 -1995
  96. package/src/mcp/servicenow-operations-mcp.ts +0 -3384
  97. package/src/mcp/servicenow-platform-development-mcp-refactored.ts +0 -611
  98. package/src/mcp/servicenow-platform-development-mcp.ts +0 -970
  99. package/src/mcp/servicenow-progressive-indexer.ts +0 -370
  100. package/src/mcp/servicenow-reporting-analytics-mcp-refactored.ts +0 -695
  101. package/src/mcp/servicenow-reporting-analytics-mcp.ts +0 -1123
  102. package/src/mcp/servicenow-security-compliance-mcp-refactored.ts +0 -642
  103. package/src/mcp/servicenow-security-compliance-mcp.ts +0 -1157
  104. package/src/mcp/servicenow-update-set-mcp-refactored.ts +0 -751
  105. package/src/mcp/servicenow-update-set-mcp.ts +0 -811
  106. package/src/mcp/shared/agent-context-provider.ts +0 -365
  107. package/src/mcp/shared/base-mcp-server.ts +0 -2463
  108. package/src/mcp/shared/mcp-memory-manager.ts +0 -540
  109. package/src/mcp/shared/mcp-resource-manager.ts +0 -367
  110. package/src/mcp/snow-flow-mcp.ts +0 -911
  111. package/src/mcp/start-all-mcp-servers.ts +0 -102
  112. package/src/mcp/start-servicenow-mcp.ts +0 -67
  113. package/src/monitoring/enhanced-monitoring-system.ts +0 -1345
  114. package/src/monitoring/performance-tracker.ts +0 -777
  115. package/src/optimization/cost-optimization-engine.ts +0 -1125
  116. package/src/optimization/index.ts +0 -10
  117. package/src/queen/README.md +0 -403
  118. package/src/queen/agent-factory.ts +0 -574
  119. package/src/queen/index.ts +0 -94
  120. package/src/queen/mcp-execution-bridge.ts +0 -681
  121. package/src/queen/neural-learning.ts +0 -319
  122. package/src/queen/parallel-agent-engine.ts +0 -848
  123. package/src/queen/queen-memory-system.ts +0 -490
  124. package/src/queen/queen-memory.ts +0 -456
  125. package/src/queen/servicenow-queen.ts +0 -1029
  126. package/src/queen/types.ts +0 -87
  127. package/src/rollback/smart-rollback-system.ts +0 -866
  128. package/src/schemas/deployment.schema.json +0 -58
  129. package/src/schemas/flow.schema.json +0 -79
  130. package/src/schemas/widget.schema.json +0 -72
  131. package/src/snow-flow-system.ts +0 -541
  132. package/src/sparc/sparc-help.ts +0 -49
  133. package/src/sparc/team-sparc.ts +0 -88
  134. package/src/strategies/global-scope-strategy.ts +0 -736
  135. package/src/templates/base/application.template.json +0 -45
  136. package/src/templates/base/business_rule.template.json +0 -33
  137. package/src/templates/base/script_include.template.json +0 -18
  138. package/src/templates/base/table.template.json +0 -64
  139. package/src/templates/base/widget.template.json +0 -25
  140. package/src/templates/patterns/composite.incident-management.template.json +0 -140
  141. package/src/templates/patterns/widget.dashboard.template.json +0 -238
  142. package/src/templates/patterns/widget.datatable.template.json +0 -292
  143. package/src/testing/integration-test-suite.ts +0 -1276
  144. package/src/types/index.ts +0 -183
  145. package/src/types/neo4j-driver.d.ts +0 -23
  146. package/src/types/servicenow.types.ts +0 -307
  147. package/src/types/snow-flow.types.ts +0 -186
  148. package/src/types/todo.types.ts +0 -70
  149. package/src/utils/action-type-cache.ts +0 -286
  150. package/src/utils/agent-detector.ts +0 -573
  151. package/src/utils/artifact-tracker.ts +0 -379
  152. package/src/utils/dependency-detector.ts +0 -233
  153. package/src/utils/deployment-metadata-handler.ts +0 -518
  154. package/src/utils/error-recovery.ts +0 -680
  155. package/src/utils/logger.ts +0 -60
  156. package/src/utils/mcp-auth-middleware.ts +0 -262
  157. package/src/utils/mcp-config-manager.ts +0 -270
  158. package/src/utils/mcp-server-manager.ts +0 -446
  159. package/src/utils/mcp-tool-registry.ts +0 -298
  160. package/src/utils/migrate-snow-flow.ts +0 -98
  161. package/src/utils/oauth-html-templates.ts +0 -188
  162. package/src/utils/scope-utils.ts +0 -443
  163. package/src/utils/servicenow-client.ts +0 -3321
  164. package/src/utils/servicenow-id-generator.ts +0 -181
  165. package/src/utils/snow-memory-manager.ts +0 -605
  166. package/src/utils/snow-oauth.ts +0 -797
  167. package/src/utils/template-engine.ts +0 -463
  168. package/src/utils/theme-manager.ts +0 -295
  169. package/src/utils/unified-auth-store.ts +0 -222
  170. package/src/utils/update-set-importer.ts +0 -422
  171. package/src/utils/update-set-xml-packager.ts +0 -371
  172. package/src/utils/widget-template-generator.ts +0 -1744
  173. package/src/version.ts +0 -1950
@@ -1,1292 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * ServiceNow Deployment MCP Server - Agent-Integrated Version
4
- * Provides specialized deployment tools with full agent coordination
5
- * NEW v1.3.1: Complete XML Update Set auto-import with preview and commit controls
6
- */
7
-
8
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
- import {
10
- CallToolRequestSchema,
11
- ListToolsRequestSchema,
12
- } from '@modelcontextprotocol/sdk/types.js';
13
- import { BaseMCPServer, MCPToolResult } from './shared/base-mcp-server.js';
14
- import { AgentContext } from './shared/mcp-memory-manager.js';
15
- import { ScopeManager, DeploymentContext } from '../managers/scope-manager.js';
16
- import { GlobalScopeStrategy, ScopeType } from '../strategies/global-scope-strategy.js';
17
- import { artifactTracker } from '../utils/artifact-tracker.js';
18
- import { promises as fs } from 'fs';
19
-
20
- export class ServiceNowDeploymentMCP extends BaseMCPServer {
21
- private scopeManager: ScopeManager;
22
- private globalScopeStrategy: GlobalScopeStrategy;
23
-
24
- constructor() {
25
- super('servicenow-deployment', '2.0.0');
26
-
27
- // Initialize scope management
28
- this.scopeManager = new ScopeManager({
29
- defaultScope: ScopeType.GLOBAL,
30
- allowFallback: true,
31
- validatePermissions: true,
32
- enableMigration: false
33
- });
34
- this.globalScopeStrategy = new GlobalScopeStrategy();
35
-
36
- // Start artifact tracking session
37
- artifactTracker.startSession();
38
-
39
- this.setupHandlers();
40
- }
41
-
42
- private setupHandlers() {
43
- // Define available tools
44
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
45
- tools: [
46
- {
47
- name: 'snow_deploy',
48
- description: 'AGENT-AWARE DEPLOYMENT - Complete deployment workflow with automatic update set management, agent coordination, and memory integration',
49
- inputSchema: {
50
- type: 'object',
51
- properties: {
52
- type: {
53
- type: 'string',
54
- enum: ['widget', 'flow', 'application', 'script', 'business_rule', 'table', 'batch', 'xml_update_set'],
55
- description: 'Type of artifact to deploy (use xml_update_set for XML import)'
56
- },
57
- xml_file_path: {
58
- type: 'string',
59
- description: 'Path to XML update set file (for xml_update_set type)'
60
- },
61
- auto_preview: {
62
- type: 'boolean',
63
- description: 'Automatically preview the update set after import (default: true)',
64
- default: true
65
- },
66
- auto_commit: {
67
- type: 'boolean',
68
- description: 'Automatically commit the update set if preview is clean (default: true)',
69
- default: true
70
- },
71
- instruction: {
72
- type: 'string',
73
- description: 'Natural language instruction for what to create (for flows/widgets)'
74
- },
75
- config: {
76
- type: 'object',
77
- description: 'Artifact configuration (alternative to instruction for direct config)'
78
- },
79
- artifacts: {
80
- type: 'array',
81
- description: 'For batch deployments - array of artifacts',
82
- items: {
83
- type: 'object',
84
- properties: {
85
- type: { type: 'string' },
86
- config: { type: 'object' },
87
- instruction: { type: 'string' }
88
- }
89
- }
90
- },
91
- // Agent context parameters
92
- session_id: {
93
- type: 'string',
94
- description: 'Agent session ID for coordination'
95
- },
96
- agent_id: {
97
- type: 'string',
98
- description: 'Deploying agent ID'
99
- },
100
- agent_type: {
101
- type: 'string',
102
- description: 'Type of agent performing deployment'
103
- },
104
- // Deployment options
105
- auto_update_set: {
106
- type: 'boolean',
107
- description: 'Automatically ensure active Update Set session (default: true)',
108
- default: true
109
- },
110
- fallback_strategy: {
111
- type: 'string',
112
- enum: ['manual_steps', 'update_set_only', 'none'],
113
- description: 'Strategy when direct deployment fails (default: manual_steps)',
114
- default: 'manual_steps'
115
- },
116
- permission_escalation: {
117
- type: 'string',
118
- enum: ['auto_request', 'manual', 'none'],
119
- description: 'How to handle permission errors (default: auto_request)',
120
- default: 'auto_request'
121
- },
122
- deployment_context: {
123
- type: 'string',
124
- description: 'Context for Update Set naming (e.g., "incident widget", "approval flow")'
125
- },
126
- // Batch options
127
- parallel: {
128
- type: 'boolean',
129
- description: 'Deploy batch artifacts in parallel',
130
- default: false
131
- },
132
- transaction_mode: {
133
- type: 'boolean',
134
- description: 'All-or-nothing batch deployment',
135
- default: true
136
- },
137
- dry_run: {
138
- type: 'boolean',
139
- description: 'Validate without deploying',
140
- default: false
141
- }
142
- },
143
- required: ['type']
144
- }
145
- },
146
- {
147
- name: 'snow_deployment_status',
148
- description: 'Check deployment status and history with agent tracking',
149
- inputSchema: {
150
- type: 'object',
151
- properties: {
152
- session_id: { type: 'string', description: 'Session ID to filter by' },
153
- limit: { type: 'number', description: 'Number of recent deployments to show', default: 10 },
154
- }
155
- }
156
- },
157
- {
158
- name: 'snow_validate_deployment',
159
- description: 'Validate a deployment before executing with agent coordination',
160
- inputSchema: {
161
- type: 'object',
162
- properties: {
163
- type: { type: 'string', enum: ['widget', 'workflow', 'application'] },
164
- artifact: { type: 'object', description: 'The artifact to validate' },
165
- session_id: { type: 'string' },
166
- agent_id: { type: 'string' }
167
- },
168
- required: ['type', 'artifact']
169
- }
170
- },
171
- {
172
- name: 'snow_rollback_deployment',
173
- description: 'Rollback a deployment with agent coordination',
174
- inputSchema: {
175
- type: 'object',
176
- properties: {
177
- update_set_id: { type: 'string', description: 'Update set sys_id to rollback' },
178
- reason: { type: 'string', description: 'Reason for rollback' },
179
- session_id: { type: 'string' },
180
- agent_id: { type: 'string' }
181
- },
182
- required: ['update_set_id', 'reason']
183
- }
184
- }
185
- ]
186
- }));
187
-
188
- // Handle tool calls
189
- this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
190
- const { name, arguments: args } = request.params;
191
-
192
- try {
193
- switch (name) {
194
- case 'snow_deploy':
195
- return await this.deployWithAgentCoordination(args);
196
- case 'snow_deployment_status':
197
- return await this.getDeploymentStatusWithContext(args);
198
- case 'snow_validate_deployment':
199
- return await this.validateDeploymentWithContext(args);
200
- case 'snow_rollback_deployment':
201
- return await this.rollbackDeploymentWithContext(args);
202
- default:
203
- throw new Error(`Unknown tool: ${name}`);
204
- }
205
- } catch (error) {
206
- return this.createErrorResponse(
207
- `Tool execution failed: ${name}`,
208
- error
209
- );
210
- }
211
- });
212
- }
213
-
214
- /**
215
- * Main deployment method with full agent integration and intelligent workflow
216
- */
217
- private async deployWithAgentCoordination(args: any): Promise<MCPToolResult> {
218
- return await this.executeWithAgentContext(
219
- 'snow_deploy',
220
- args,
221
- async (context) => {
222
- // 🔧 STEP 1: MANDATORY Authentication and Connection Validation
223
- this.logger.info('🔍 Step 1: Validating ServiceNow connection...');
224
- const connectionResult = await this.validateServiceNowConnection();
225
- if (!connectionResult.success) {
226
- return this.createAuthenticationError(connectionResult.error);
227
- }
228
-
229
- // Assert no mock data
230
- this.assertNoMockData('deployment');
231
-
232
- // 🔧 STEP 2: Update Set Management
233
- this.logger.info('📦 Step 2: Ensuring Update Set for tracking...');
234
- await this.reportProgress(context, 15, 'Setting up Update Set');
235
-
236
- const purpose = args.type === 'batch' ? 'Batch Deployment' : `${args.type} Deployment`;
237
- const updateSetId = await this.ensureUpdateSet(context, purpose);
238
-
239
- if (!updateSetId) {
240
- this.logger.warn('⚠️ No Update Set created - changes will not be tracked');
241
- }
242
-
243
- // 🔧 STEP 3: Smart Artifact Discovery (DRY principle)
244
- if (args.type !== 'batch' && (args.config?.name || args.instruction)) {
245
- this.logger.info('🔍 Step 3: Discovering existing artifacts...');
246
- await this.reportProgress(context, 25, 'Checking for existing artifacts');
247
-
248
- const artifactName = args.config?.name || this.extractNameFromInstruction(args.instruction);
249
- if (artifactName) {
250
- const discovery = await this.discoverExistingArtifacts(
251
- args.type,
252
- artifactName,
253
- this.extractSearchTermsFromInstruction(args.instruction)
254
- );
255
-
256
- if (discovery.found) {
257
- this.logger.info(`🔍 Found ${discovery.artifacts.length} existing artifacts`);
258
- // Store discovery info in memory for reference
259
- await this.memory.updateSharedContext({
260
- session_id: context.session_id,
261
- context_key: `discovery_${args.type}`,
262
- context_value: JSON.stringify({
263
- artifacts: discovery.artifacts,
264
- suggestions: discovery.suggestions,
265
- timestamp: new Date().toISOString()
266
- }),
267
- created_by_agent: context.agent_id
268
- });
269
- }
270
- }
271
- }
272
-
273
- // Get session context for coordination
274
- const sessionContext = await this.getSessionContext(context.session_id);
275
-
276
- // Report progress
277
- await this.reportProgress(context, 35, 'Starting deployment');
278
-
279
- try {
280
- // Handle different deployment types
281
- let result;
282
- if (args.type === 'batch') {
283
- result = await this.deployBatch(args, context, updateSetId);
284
- } else if (args.type === 'xml_update_set') {
285
- result = await this.deployXMLUpdateSet(args, context);
286
- } else {
287
- result = await this.deploySingleArtifact(args, context, updateSetId);
288
- }
289
-
290
- // Add discovery information to successful results (from memory context)
291
- try {
292
- const discoveryResults = await this.memory.query(
293
- 'SELECT context_value FROM shared_context WHERE session_id = ? AND context_key = ?',
294
- [context.session_id, `discovery_${args.type}`]
295
- );
296
-
297
- if (discoveryResults.length > 0) {
298
- const discovery = JSON.parse(discoveryResults[0].context_value);
299
- if (discovery.artifacts && discovery.artifacts.length > 0) {
300
- result.content.push({
301
- type: 'text',
302
- text: `\n📋 Artifact Discovery Results:\n${discovery.suggestions?.join('\n') || ''}`
303
- });
304
- }
305
- }
306
- } catch (discoveryError) {
307
- this.logger.warn('Could not retrieve discovery information', discoveryError);
308
- }
309
-
310
- return result;
311
-
312
- } catch (error) {
313
- this.logger.error('Deployment failed, attempting intelligent recovery...', error);
314
-
315
- // Use enhanced error handling with fallback options
316
- const fallbackOptions = {
317
- enableRetry: true,
318
- enableScopeEscalation: args.permission_escalation === 'auto_request',
319
- enableManualSteps: args.fallback_strategy === 'manual_steps'
320
- };
321
-
322
- const errorResult = await this.handleServiceNowError(
323
- error,
324
- `${args.type} deployment`,
325
- context,
326
- fallbackOptions
327
- );
328
-
329
- // If error handling provided a recovery solution
330
- if (errorResult.content.some(c => c.text?.includes('can_continue: true'))) {
331
- this.logger.info('✅ Error recovered - retrying deployment...');
332
-
333
- try {
334
- // Retry the deployment after recovery
335
- await this.reportProgress(context, 85, 'Retrying after error recovery');
336
-
337
- let retryResult;
338
- if (args.type === 'batch') {
339
- retryResult = await this.deployBatch(args, context, updateSetId);
340
- } else {
341
- retryResult = await this.deploySingleArtifact(args, context, updateSetId);
342
- }
343
-
344
- // Add recovery note to success result
345
- retryResult.content.push({
346
- type: 'text',
347
- text: '\n✅ Deployment succeeded after automatic error recovery'
348
- });
349
-
350
- return retryResult;
351
-
352
- } catch (retryError) {
353
- this.logger.error('Retry after recovery also failed', retryError);
354
-
355
- // Request Queen intervention for persistent failures
356
- await this.requestQueenIntervention(context, {
357
- type: 'deployment_failure_persistent',
358
- priority: 'critical',
359
- description: `Failed to deploy ${args.type} even after error recovery: ${retryError instanceof Error ? retryError.message : String(retryError)}`,
360
- attempted_solutions: ['direct_deployment', 'error_recovery', 'retry_after_recovery']
361
- });
362
-
363
- return errorResult; // Return the error recovery guidance
364
- }
365
- }
366
-
367
- // If no automatic recovery possible, request Queen intervention
368
- await this.requestQueenIntervention(context, {
369
- type: 'deployment_failure',
370
- priority: 'high',
371
- description: `Failed to deploy ${args.type}: ${error instanceof Error ? error.message : String(error)}`,
372
- attempted_solutions: ['direct_deployment', 'intelligent_error_handling']
373
- });
374
-
375
- return errorResult; // Return the error recovery guidance instead of throwing
376
- }
377
- }
378
- );
379
- }
380
-
381
- /**
382
- * Deploy a single artifact with memory tracking
383
- */
384
- private async deploySingleArtifact(args: any, context: AgentContext, updateSetId?: string): Promise<MCPToolResult> {
385
- const { type, config, instruction } = args;
386
-
387
- // Report planning phase
388
- await this.reportProgress(context, 20, 'Planning deployment');
389
-
390
- // Ensure update set if requested
391
- let finalUpdateSetId = updateSetId;
392
- if (args.auto_update_set !== false && !finalUpdateSetId) {
393
- finalUpdateSetId = await this.ensureUpdateSet(context, config?.name || 'artifact');
394
-
395
- await this.reportProgress(context, 30, 'Update set ready');
396
- }
397
-
398
- // Deploy based on type
399
- let result: any;
400
- await this.reportProgress(context, 50, `Deploying ${type}`);
401
-
402
- switch (type) {
403
- case 'widget':
404
- result = await this.deployWidget(config, context, finalUpdateSetId);
405
- break;
406
- case 'flow':
407
- result = await this.deployFlow(config || { instruction }, context, finalUpdateSetId);
408
- break;
409
- case 'application':
410
- result = await this.deployApplication(config, context, finalUpdateSetId);
411
- break;
412
- case 'script':
413
- case 'business_rule':
414
- result = await this.deployScript(type, config, context, finalUpdateSetId);
415
- break;
416
- case 'xml_update_set':
417
- result = await this.deployXMLUpdateSet(config, context);
418
- break;
419
- default:
420
- throw new Error(`Unsupported deployment type: ${type}`);
421
- }
422
-
423
- // Store artifact in memory
424
- await this.storeArtifact(context, {
425
- sys_id: result.sys_id,
426
- type,
427
- name: result.name || config?.name || 'unnamed',
428
- description: config?.description,
429
- config,
430
- update_set_id: finalUpdateSetId
431
- });
432
-
433
- // Record deployment in history
434
- await this.memory.recordDeployment(
435
- context.session_id,
436
- result.sys_id,
437
- type,
438
- true,
439
- context.agent_id
440
- );
441
-
442
- await this.reportProgress(context, 90, 'Finalizing deployment');
443
-
444
- // Notify next agent if needed
445
- if (result.next_agent) {
446
- await this.notifyHandoff(context, result.next_agent, {
447
- type,
448
- sys_id: result.sys_id,
449
- next_steps: result.next_steps || []
450
- });
451
- }
452
-
453
- await this.reportProgress(context, 100, 'Deployment complete');
454
-
455
- return this.createSuccessResponse(
456
- `Successfully deployed ${type}: ${result.name}`,
457
- {
458
- sys_id: result.sys_id,
459
- name: result.name,
460
- update_set_id: finalUpdateSetId,
461
- deployment_details: result
462
- },
463
- {
464
- agent_id: context.agent_id,
465
- session_id: context.session_id,
466
- artifacts_created: [result.sys_id]
467
- }
468
- );
469
- }
470
-
471
- /**
472
- * Deploy multiple artifacts in batch
473
- */
474
- private async deployBatch(args: any, context: AgentContext, updateSetId?: string): Promise<MCPToolResult> {
475
- const { artifacts, parallel, transaction_mode, dry_run } = args;
476
-
477
- if (!artifacts || !Array.isArray(artifacts)) {
478
- throw new Error('Batch deployment requires artifacts array');
479
- }
480
-
481
- await this.reportProgress(context, 10, `Preparing batch deployment of ${artifacts.length} artifacts`);
482
-
483
- // Dry run validation
484
- if (dry_run) {
485
- const validationResults = await Promise.all(
486
- artifacts.map(artifact => this.validateArtifact(artifact, context))
487
- );
488
-
489
- return this.createSuccessResponse(
490
- 'Dry run completed - all artifacts validated',
491
- { validationResults }
492
- );
493
- }
494
-
495
- // Create update set for batch
496
- const batchUpdateSetId = await this.ensureUpdateSet(context, `Batch deployment`);
497
-
498
- const results: any[] = [];
499
- const errors: any[] = [];
500
-
501
- try {
502
- if (parallel) {
503
- // Deploy in parallel
504
- await this.reportProgress(context, 30, 'Deploying artifacts in parallel');
505
-
506
- const deploymentPromises = artifacts.map((artifact, index) =>
507
- this.deploySingleArtifact(
508
- { ...artifact, auto_update_set: false },
509
- context
510
- ).catch(error => {
511
- errors.push({ artifact, error: error.message });
512
- return null;
513
- })
514
- );
515
-
516
- const parallelResults = await Promise.all(deploymentPromises);
517
- results.push(...parallelResults.filter(r => r !== null));
518
-
519
- } else {
520
- // Deploy sequentially
521
- for (let i = 0; i < artifacts.length; i++) {
522
- const artifact = artifacts[i];
523
- await this.reportProgress(
524
- context,
525
- 30 + (60 * i / artifacts.length),
526
- `Deploying artifact ${i + 1} of ${artifacts.length}`
527
- );
528
-
529
- try {
530
- const result = await this.deploySingleArtifact(
531
- { ...artifact, auto_update_set: false },
532
- context
533
- );
534
- results.push(result);
535
- } catch (error) {
536
- errors.push({ artifact, error: error instanceof Error ? error.message : String(error) });
537
-
538
- if (transaction_mode) {
539
- // Rollback on error in transaction mode
540
- await this.rollbackBatch(results, batchUpdateSetId, context);
541
- throw new Error(`Batch deployment failed at artifact ${i + 1}: ${error}`);
542
- }
543
- }
544
- }
545
- }
546
-
547
- // Check if we need to rollback
548
- if (transaction_mode && errors.length > 0) {
549
- await this.rollbackBatch(results, batchUpdateSetId, context);
550
- throw new Error(`Batch deployment failed with ${errors.length} errors`);
551
- }
552
-
553
- await this.reportProgress(context, 100, 'Batch deployment complete');
554
-
555
- return this.createSuccessResponse(
556
- `Batch deployment completed: ${results.length} succeeded, ${errors.length} failed`,
557
- {
558
- successful: results.length,
559
- failed: errors.length,
560
- errors: errors.length > 0 ? errors : undefined,
561
- update_set_id: batchUpdateSetId
562
- }
563
- );
564
-
565
- } catch (error) {
566
- // Record failed deployment
567
- await this.memory.recordDeployment(
568
- context.session_id,
569
- 'batch_deployment',
570
- 'batch',
571
- false,
572
- context.agent_id,
573
- error instanceof Error ? error.message : String(error)
574
- );
575
-
576
- throw error;
577
- }
578
- }
579
-
580
- /**
581
- * Deploy XML Update Set to ServiceNow
582
- */
583
- private async deployXMLUpdateSet(args: any, context: AgentContext): Promise<MCPToolResult> {
584
- const { xml_file_path, auto_preview = true, auto_commit = true } = args;
585
-
586
- if (!xml_file_path) {
587
- throw new Error('XML file path is required for xml_update_set deployment');
588
- }
589
-
590
- this.logger.info('🚀 Deploying XML Update Set', {
591
- file: xml_file_path,
592
- auto_preview,
593
- auto_commit
594
- });
595
-
596
- try {
597
- // Read XML file
598
- await this.reportProgress(context, 20, 'Reading XML file');
599
- const xmlContent = await fs.readFile(xml_file_path, 'utf-8');
600
-
601
- // Import XML as remote update set
602
- await this.reportProgress(context, 40, 'Importing XML to ServiceNow');
603
- const importResponse = await this.client.makeRequest({
604
- method: 'POST',
605
- url: '/api/now/table/sys_remote_update_set',
606
- headers: {
607
- 'Content-Type': 'application/xml',
608
- 'Accept': 'application/json'
609
- },
610
- data: xmlContent
611
- });
612
-
613
- if (!importResponse.result || !importResponse.result.sys_id) {
614
- throw new Error('Failed to import XML update set');
615
- }
616
-
617
- const remoteUpdateSetId = importResponse.result.sys_id;
618
- this.logger.info('✅ XML imported successfully', { sys_id: remoteUpdateSetId });
619
-
620
- // Load the update set
621
- await this.reportProgress(context, 60, 'Loading update set');
622
- await this.client.makeRequest({
623
- method: 'PUT',
624
- url: `/api/now/table/sys_remote_update_set/${remoteUpdateSetId}`,
625
- data: {
626
- state: 'loaded'
627
- }
628
- });
629
-
630
- // Find the loaded update set
631
- const loadedResponse = await this.client.makeRequest({
632
- method: 'GET',
633
- url: '/api/now/table/sys_update_set',
634
- params: {
635
- sysparm_query: `remote_sys_id=${remoteUpdateSetId}`,
636
- sysparm_limit: 1
637
- }
638
- });
639
-
640
- if (!loadedResponse.result || loadedResponse.result.length === 0) {
641
- throw new Error('Failed to find loaded update set');
642
- }
643
-
644
- const updateSetId = loadedResponse.result[0].sys_id;
645
- const updateSetName = loadedResponse.result[0].name;
646
-
647
- // Preview if requested
648
- if (auto_preview) {
649
- await this.reportProgress(context, 80, 'Previewing update set');
650
-
651
- const previewResponse = await this.client.makeRequest({
652
- method: 'POST',
653
- url: `/api/now/table/sys_update_set/${updateSetId}/preview`
654
- });
655
-
656
- // Check preview results
657
- const previewProblems = await this.client.makeRequest({
658
- method: 'GET',
659
- url: '/api/now/table/sys_update_preview_problem',
660
- params: {
661
- sysparm_query: `update_set=${updateSetId}`,
662
- sysparm_limit: 100
663
- }
664
- });
665
-
666
- if (previewProblems.result && previewProblems.result.length > 0) {
667
- const problems = previewProblems.result.map((p: any) =>
668
- `- ${p.type}: ${p.description}`
669
- ).join('\n');
670
-
671
- if (auto_commit) {
672
- this.logger.warn('Preview found problems, skipping auto-commit', { problems });
673
- }
674
-
675
- return this.createSuccessResponse(
676
- 'XML imported and previewed with problems',
677
- {
678
- update_set_id: updateSetId,
679
- update_set_name: updateSetName,
680
- preview_status: 'problems_found',
681
- problems: previewProblems.result,
682
- next_steps: [
683
- '1. Review preview problems in ServiceNow',
684
- '2. Resolve any issues',
685
- '3. Commit manually when ready'
686
- ]
687
- }
688
- );
689
- }
690
-
691
- // Commit if clean and requested
692
- if (auto_commit) {
693
- await this.reportProgress(context, 95, 'Committing update set');
694
-
695
- await this.client.makeRequest({
696
- method: 'POST',
697
- url: `/api/now/table/sys_update_set/${updateSetId}/commit`
698
- });
699
-
700
- return this.createSuccessResponse(
701
- '✅ XML Update Set imported, previewed, and committed successfully!',
702
- {
703
- update_set_id: updateSetId,
704
- update_set_name: updateSetName,
705
- status: 'committed',
706
- flow_location: 'Flow Designer > Designer',
707
- next_steps: [
708
- '1. Navigate to Flow Designer',
709
- '2. Your flow should be visible in the list',
710
- '3. Open the flow to verify all components'
711
- ]
712
- }
713
- );
714
- }
715
- }
716
-
717
- // Return success without preview/commit
718
- return this.createSuccessResponse(
719
- 'XML Update Set imported successfully',
720
- {
721
- update_set_id: updateSetId,
722
- update_set_name: updateSetName,
723
- status: 'imported',
724
- next_steps: [
725
- '1. Navigate to System Update Sets > Local Update Sets',
726
- '2. Find your update set: ' + updateSetName,
727
- '3. Click Preview Update Set',
728
- '4. Review and commit when ready'
729
- ]
730
- }
731
- );
732
-
733
- } catch (error) {
734
- const errorMsg = error instanceof Error ? error.message : String(error);
735
-
736
- if (errorMsg.includes('ENOENT')) {
737
- throw new Error(`XML file not found: ${xml_file_path}`);
738
- }
739
-
740
- throw new Error(`Failed to deploy XML update set: ${errorMsg}`);
741
- }
742
- }
743
-
744
- /**
745
- * Deploy widget with agent tracking and intelligent error handling
746
- */
747
- private async deployWidget(config: any, context: AgentContext, updateSetId?: string): Promise<any> {
748
- this.logger.info('Deploying widget', {
749
- name: config.name,
750
- agent_id: context.agent_id
751
- });
752
-
753
- try {
754
- // Validate widget configuration first
755
- const validationErrors = this.validateWidgetConfig(config);
756
- if (validationErrors.length > 0) {
757
- throw new Error(`Widget validation failed: ${validationErrors.join(', ')}`);
758
- }
759
-
760
- // Create widget in ServiceNow
761
- const widgetData = {
762
- name: config.name,
763
- id: config.name,
764
- template: config.template || '<div>Widget Template</div>',
765
- css: config.css || '',
766
- server_script: config.server_script || '',
767
- client_script: config.client_script || '',
768
- public: false,
769
- roles: '',
770
- active: true
771
- };
772
-
773
- const response = await this.client.createRecord('sp_widget', widgetData);
774
-
775
- if (!response.success || !response.result) {
776
- // Try to provide more specific error information
777
- const errorMsg = response.error || 'Unknown error creating widget';
778
-
779
- // Check for common widget creation issues
780
- if (errorMsg.includes('duplicate') || errorMsg.includes('already exists')) {
781
- throw new Error(`Widget '${config.name}' already exists. Consider using a different name or updating the existing widget.`);
782
- }
783
-
784
- if (errorMsg.includes('permission') || errorMsg.includes('access') || errorMsg.includes('403')) {
785
- throw new Error(`
786
- 🚫 Service Portal Permission Error (403)
787
-
788
- Even with sp_admin role, this can happen due to:
789
-
790
- 1. **OAuth Scope Restrictions**
791
- - Go to: System OAuth > Application Registry
792
- - Set "Accessible from" to "All application scopes"
793
-
794
- 2. **Cross-Scope Access**
795
- - Switch to Global scope and try again
796
- - Check ACLs on sp_widget table
797
-
798
- 3. **Missing System Properties**
799
- - Ensure: glide.service_portal.enable_api_access = true
800
-
801
- 4. **Update Set Required**
802
- - Widgets must be created in an active Update Set
803
- - Use: snow_ensure_active_update_set() first
804
-
805
- 🔧 Quick Fix: Try deployment with global scope:
806
- await snow_deploy({
807
- type: "widget",
808
- config: {...},
809
- scope_preference: "global"
810
- });
811
-
812
- 📚 See SERVICE_PORTAL_403_FIX.md for detailed troubleshooting.
813
- `);
814
- }
815
-
816
- throw new Error(`Failed to create widget in ServiceNow: ${errorMsg}`);
817
- }
818
-
819
- const result = response.result as any;
820
- const widgetSysId = Array.isArray(result) ? result[0]?.sys_id : result?.sys_id;
821
-
822
- // 🔧 Track artifact in Update Set
823
- if (updateSetId) {
824
- try {
825
- await this.trackArtifact(widgetSysId, 'widget', config.name, updateSetId);
826
- } catch (trackingError) {
827
- this.logger.warn('Update Set tracking failed (widget created but not tracked)', trackingError);
828
- // Don't fail the deployment, just warn
829
- }
830
- }
831
-
832
- // Determine next agent based on widget complexity
833
- let nextAgent: string | undefined;
834
- let nextSteps: string[] = [];
835
-
836
- if (config.requires_styling || config.template?.includes('class=')) {
837
- nextAgent = 'ui_specialist';
838
- nextSteps = ['responsive_styling', 'accessibility_compliance'];
839
- } else if (config.requires_testing) {
840
- nextAgent = 'test_agent';
841
- nextSteps = ['functional_testing', 'performance_testing'];
842
- }
843
-
844
- // Log successful deployment
845
- this.logger.info(`✅ Widget deployed successfully: ${config.name} (${widgetSysId})`);
846
-
847
- return {
848
- sys_id: widgetSysId,
849
- name: config.name,
850
- table: 'sp_widget',
851
- next_agent: nextAgent,
852
- next_steps: nextSteps,
853
- success: true
854
- };
855
-
856
- } catch (error) {
857
- this.logger.error('Widget deployment failed', error);
858
-
859
- // Use intelligent error handling for specific recovery guidance
860
- const errorResult = await this.handleServiceNowError(
861
- error,
862
- 'widget deployment',
863
- context,
864
- {
865
- enableRetry: true,
866
- enableScopeEscalation: true,
867
- enableManualSteps: true
868
- }
869
- );
870
-
871
- // Re-throw with enhanced error information for higher-level handling
872
- const enhancedError = new Error(`Widget deployment failed: ${error instanceof Error ? error.message : String(error)}`);
873
- (enhancedError as any).errorRecoveryGuidance = errorResult;
874
- throw enhancedError;
875
- }
876
- }
877
-
878
- /**
879
- * Validate widget configuration before deployment
880
- */
881
- private validateWidgetConfig(config: any): string[] {
882
- const errors: string[] = [];
883
-
884
- if (!config.name) {
885
- errors.push('Widget name is required');
886
- } else {
887
- // Check for valid widget naming
888
- if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(config.name)) {
889
- errors.push('Widget name must start with letter and contain only letters, numbers, and underscores');
890
- }
891
-
892
- if (config.name.length > 40) {
893
- errors.push('Widget name must be 40 characters or less');
894
- }
895
- }
896
-
897
- if (!config.template) {
898
- errors.push('Widget template is required');
899
- } else {
900
- // Basic HTML validation
901
- if (config.template.length > 100000) {
902
- errors.push('Widget template is too large (max 100KB)');
903
- }
904
- }
905
-
906
- // Validate scripts if provided
907
- if (config.server_script && config.server_script.length > 1000000) {
908
- errors.push('Server script is too large (max 1MB)');
909
- }
910
-
911
- if (config.client_script && config.client_script.length > 1000000) {
912
- errors.push('Client script is too large (max 1MB)');
913
- }
914
-
915
- return errors;
916
- }
917
-
918
- /**
919
- * Deploy flow with agent tracking
920
- */
921
- private async deployFlow(config: any, context: AgentContext, updateSetId?: string): Promise<any> {
922
- // For flows with natural language instructions, delegate to flow composer
923
- if (config.instruction) {
924
- // Store instruction in shared context for flow builder agent
925
- await this.memory.updateSharedContext({
926
- session_id: context.session_id,
927
- context_key: 'flow_instruction',
928
- context_value: config.instruction,
929
- created_by_agent: context.agent_id
930
- });
931
-
932
- return {
933
- sys_id: `pending_flow_${Date.now()}`,
934
- name: 'Flow from instruction',
935
- instruction: config.instruction,
936
- next_agent: 'flow_builder',
937
- next_steps: ['analyze_requirements', 'create_flow_structure', 'deploy_flow']
938
- };
939
- }
940
-
941
- // Direct flow deployment
942
- const flowData = {
943
- name: config.name,
944
- description: config.description,
945
- active: config.active !== false,
946
- sys_scope: 'global'
947
- };
948
-
949
- const response = await this.client.createRecord('sys_hub_flow', flowData);
950
-
951
- if (!response.success || !response.result) {
952
- throw new Error('Failed to create flow in ServiceNow');
953
- }
954
-
955
- const result = response.result as any;
956
- return {
957
- sys_id: Array.isArray(result) ? result[0]?.sys_id : result?.sys_id,
958
- name: config.name,
959
- table: 'sys_hub_flow'
960
- };
961
- }
962
-
963
- /**
964
- * Deploy application with scope management
965
- */
966
- private async deployApplication(config: any, context: AgentContext, updateSetId?: string): Promise<any> {
967
- // Determine deployment scope (simplified)
968
- const scopeStrategy = config.scope_strategy || 'auto';
969
- const targetScope = scopeStrategy === 'auto' ? 'global' : (config.scope || 'global');
970
-
971
- const appData = {
972
- name: config.name,
973
- scope: targetScope,
974
- short_description: config.short_description,
975
- version: config.version,
976
- vendor: config.vendor || 'Custom',
977
- vendor_prefix: config.vendor_prefix || 'x',
978
- active: config.active !== false
979
- };
980
-
981
- const response = await this.client.createRecord('sys_app', appData);
982
-
983
- if (!response.success || !response.result) {
984
- throw new Error('Failed to create application in ServiceNow');
985
- }
986
-
987
- const result = response.result as any;
988
- return {
989
- sys_id: Array.isArray(result) ? result[0]?.sys_id : result?.sys_id,
990
- name: config.name,
991
- scope: targetScope,
992
- table: 'sys_app'
993
- };
994
- }
995
-
996
- /**
997
- * Deploy script or business rule
998
- */
999
- private async deployScript(type: string, config: any, context: AgentContext, updateSetId?: string): Promise<any> {
1000
- const table = type === 'script' ? 'sys_script' : 'sys_script';
1001
-
1002
- const scriptData = {
1003
- name: config.name,
1004
- script: config.script,
1005
- active: config.active !== false,
1006
- description: config.description
1007
- };
1008
-
1009
- const response = await this.client.createRecord(table, scriptData);
1010
-
1011
- if (!response.success || !response.result) {
1012
- throw new Error(`Failed to create ${type} in ServiceNow`);
1013
- }
1014
-
1015
- // Scripts often need testing
1016
- const result = response.result as any;
1017
- return {
1018
- sys_id: Array.isArray(result) ? result[0]?.sys_id : result?.sys_id,
1019
- name: config.name,
1020
- table,
1021
- next_agent: 'test_agent',
1022
- next_steps: ['syntax_validation', 'unit_testing']
1023
- };
1024
- }
1025
-
1026
- /**
1027
- * Get deployment status with session filtering
1028
- */
1029
- private async getDeploymentStatusWithContext(args: any): Promise<MCPToolResult> {
1030
- return await this.executeWithAgentContext(
1031
- 'snow_deployment_status',
1032
- args,
1033
- async (context) => {
1034
- const session_id = args.session_id || context.session_id;
1035
-
1036
- // Get artifacts from memory
1037
- const artifacts = await this.memory.getSessionArtifacts(session_id);
1038
-
1039
- // Get active agents
1040
- const activeAgents = await this.memory.query(`
1041
- SELECT * FROM agent_coordination
1042
- WHERE session_id = ?
1043
- ORDER BY last_activity DESC
1044
- `, [session_id]);
1045
-
1046
- // Get recent deployments
1047
- const deployments = await this.memory.query(`
1048
- SELECT * FROM deployment_history
1049
- WHERE session_id = ?
1050
- ORDER BY deployment_time DESC
1051
- LIMIT ?
1052
- `, [session_id, args.limit || 10]);
1053
-
1054
- return this.createSuccessResponse(
1055
- `Deployment status for session ${session_id}`,
1056
- {
1057
- artifacts: artifacts.length,
1058
- active_agents: activeAgents.length,
1059
- recent_deployments: deployments,
1060
- session_summary: {
1061
- total_artifacts: artifacts.length,
1062
- artifact_types: this.groupByType(artifacts),
1063
- success_rate: this.calculateSuccessRate(deployments)
1064
- }
1065
- }
1066
- );
1067
- }
1068
- );
1069
- }
1070
-
1071
- /**
1072
- * Validate deployment with agent context
1073
- */
1074
- private async validateDeploymentWithContext(args: any): Promise<MCPToolResult> {
1075
- return await this.executeWithAgentContext(
1076
- 'snow_validate_deployment',
1077
- args,
1078
- async (context) => {
1079
- const { type, artifact } = args;
1080
-
1081
- const validationResult = await this.validateArtifact(
1082
- { type, config: artifact },
1083
- context
1084
- );
1085
-
1086
- if (validationResult.valid) {
1087
- return this.createSuccessResponse(
1088
- `Validation passed for ${type}`,
1089
- validationResult
1090
- );
1091
- } else {
1092
- // Store validation failure in context
1093
- await this.memory.updateSharedContext({
1094
- session_id: context.session_id,
1095
- context_key: `validation_failure_${type}`,
1096
- context_value: JSON.stringify(validationResult),
1097
- created_by_agent: context.agent_id
1098
- });
1099
-
1100
- return this.createErrorResponse(
1101
- `Validation failed for ${type}`,
1102
- validationResult.errors
1103
- );
1104
- }
1105
- }
1106
- );
1107
- }
1108
-
1109
- /**
1110
- * Rollback deployment with coordination
1111
- */
1112
- private async rollbackDeploymentWithContext(args: any): Promise<MCPToolResult> {
1113
- return await this.executeWithAgentContext(
1114
- 'snow_rollback_deployment',
1115
- args,
1116
- async (context) => {
1117
- const { update_set_id, reason } = args;
1118
-
1119
- // Notify all agents about rollback
1120
- await this.memory.sendAgentMessage({
1121
- session_id: context.session_id,
1122
- from_agent: context.agent_id,
1123
- to_agent: 'all',
1124
- message_type: 'status_update',
1125
- content: JSON.stringify({
1126
- action: 'rollback_initiated',
1127
- update_set_id,
1128
- reason
1129
- })
1130
- });
1131
-
1132
- // Perform rollback
1133
- const rollbackResult = await this.client.updateRecord('sys_update_set', update_set_id, {
1134
- state: 'reverted',
1135
- description: `Rolled back: ${reason}`
1136
- });
1137
-
1138
- if (rollbackResult.success) {
1139
- // Update deployment history
1140
- await this.memory.recordDeployment(
1141
- context.session_id,
1142
- update_set_id,
1143
- 'rollback',
1144
- true,
1145
- context.agent_id
1146
- );
1147
-
1148
- return this.createSuccessResponse(
1149
- `Successfully rolled back update set ${update_set_id}`,
1150
- { reason }
1151
- );
1152
- } else {
1153
- throw new Error('Rollback failed');
1154
- }
1155
- }
1156
- );
1157
- }
1158
-
1159
- // Helper methods
1160
-
1161
- private async validateArtifact(artifact: any, context: AgentContext): Promise<any> {
1162
- // Simplified validation logic
1163
- const errors: string[] = [];
1164
-
1165
- if (!artifact.type) errors.push('Missing artifact type');
1166
- if (!artifact.config && !artifact.instruction) errors.push('Missing configuration or instruction');
1167
-
1168
- if (artifact.type === 'widget') {
1169
- if (!artifact.config?.name) errors.push('Widget name is required');
1170
- if (!artifact.config?.template) errors.push('Widget template is required');
1171
- }
1172
-
1173
- return {
1174
- valid: errors.length === 0,
1175
- errors,
1176
- warnings: []
1177
- };
1178
- }
1179
-
1180
- private async rollbackBatch(results: any[], updateSetId: string, context: AgentContext): Promise<void> {
1181
- // Rollback logic for batch deployments
1182
- for (const result of results) {
1183
- if (result?.data?.sys_id) {
1184
- try {
1185
- await this.client.deleteRecord(result.data.table || 'sys_metadata', result.data.sys_id);
1186
- } catch (error) {
1187
- this.logger.error('Failed to rollback artifact', error);
1188
- }
1189
- }
1190
- }
1191
- }
1192
-
1193
- private groupByType(artifacts: any[]): Record<string, number> {
1194
- return artifacts.reduce((acc, artifact) => {
1195
- acc[artifact.artifact_type] = (acc[artifact.artifact_type] || 0) + 1;
1196
- return acc;
1197
- }, {});
1198
- }
1199
-
1200
- private calculateSuccessRate(deployments: any[]): number {
1201
- if (deployments.length === 0) return 0;
1202
- const successful = deployments.filter(d => d.success).length;
1203
- return Math.round((successful / deployments.length) * 100);
1204
- }
1205
-
1206
- /**
1207
- * Extract artifact name from natural language instruction
1208
- */
1209
- private extractNameFromInstruction(instruction: string): string | null {
1210
- if (!instruction) return null;
1211
-
1212
- // Look for patterns like "create a widget called X" or "make a flow named Y"
1213
- const patterns = [
1214
- /(?:create|make|build)\s+(?:a|an)?\s*\w+\s+(?:called|named|for)\s+["']?([^"']+)["']?/i,
1215
- /(?:create|make|build)\s+["']([^"']+)["']\s+\w+/i,
1216
- /(?:widget|flow|script|rule|table|application)\s+(?:called|named|for)\s+["']?([^"']+)["']?/i,
1217
- /"([^"]+)"\s+(?:widget|flow|script|rule|table|application)/i,
1218
- /'([^']+)'\s+(?:widget|flow|script|rule|table|application)/i
1219
- ];
1220
-
1221
- for (const pattern of patterns) {
1222
- const match = instruction.match(pattern);
1223
- if (match && match[1]) {
1224
- return match[1].trim();
1225
- }
1226
- }
1227
-
1228
- // Fallback: look for quoted text that might be a name
1229
- const quotedMatch = instruction.match(/["']([^"']{3,30})["']/);
1230
- if (quotedMatch && quotedMatch[1]) {
1231
- return quotedMatch[1].trim();
1232
- }
1233
-
1234
- return null;
1235
- }
1236
-
1237
- /**
1238
- * Extract search terms from instruction for discovery
1239
- */
1240
- private extractSearchTermsFromInstruction(instruction: string): string[] {
1241
- if (!instruction) return [];
1242
-
1243
- const terms: string[] = [];
1244
-
1245
- // Common keywords that might indicate similar functionality
1246
- const keywords = [
1247
- 'incident', 'dashboard', 'report', 'approval', 'notification', 'user', 'profile',
1248
- 'management', 'tracking', 'monitoring', 'analytics', 'workflow', 'request',
1249
- 'ticket', 'service', 'catalog', 'portal', 'form', 'table', 'list', 'chart',
1250
- 'graph', 'widget', 'flow', 'automation', 'integration', 'api', 'rest',
1251
- 'email', 'alert', 'escalation', 'assignment', 'routing', 'sla', 'metric'
1252
- ];
1253
-
1254
- const lowercaseInstruction = instruction.toLowerCase();
1255
-
1256
- // Extract keywords that appear in the instruction
1257
- for (const keyword of keywords) {
1258
- if (lowercaseInstruction.includes(keyword)) {
1259
- terms.push(keyword);
1260
- }
1261
- }
1262
-
1263
- // Extract quoted terms
1264
- const quotedTerms = instruction.match(/["']([^"']{2,20})["']/g);
1265
- if (quotedTerms) {
1266
- quotedTerms.forEach(quoted => {
1267
- const term = quoted.replace(/["']/g, '').trim();
1268
- if (term.length >= 2 && !terms.includes(term.toLowerCase())) {
1269
- terms.push(term.toLowerCase());
1270
- }
1271
- });
1272
- }
1273
-
1274
- // Extract important words (3+ characters, not common words)
1275
- const words = lowercaseInstruction.match(/\b[a-z]{3,}\b/g) || [];
1276
- const commonWords = ['the', 'and', 'for', 'are', 'but', 'not', 'you', 'all', 'can', 'had', 'her', 'was', 'one', 'our', 'out', 'day', 'get', 'has', 'him', 'his', 'how', 'man', 'new', 'now', 'old', 'see', 'two', 'who', 'boy', 'did', 'its', 'let', 'put', 'say', 'she', 'too', 'use'];
1277
-
1278
- for (const word of words) {
1279
- if (!commonWords.includes(word) && word.length >= 3 && !terms.includes(word)) {
1280
- terms.push(word);
1281
- }
1282
- }
1283
-
1284
- return terms.slice(0, 5); // Limit to 5 terms to avoid too many searches
1285
- }
1286
- }
1287
-
1288
- // Start the server
1289
- if (require.main === module) {
1290
- const server = new ServiceNowDeploymentMCP();
1291
- server.start().catch(console.error);
1292
- }