snow-flow 2.9.9 → 3.0.0

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 (63) hide show
  1. package/.mcp.json +13 -141
  2. package/.mcp.json.template +11 -25
  3. package/README.md +18 -0
  4. package/claude-flow +81 -0
  5. package/claude-flow.bat +18 -0
  6. package/claude-flow.config.json +20 -0
  7. package/claude-flow.ps1 +24 -0
  8. package/dist/agents/index.d.ts +3 -10
  9. package/dist/agents/index.js +10 -50
  10. package/dist/agents/queen-agent.d.ts +0 -2
  11. package/dist/agents/queen-agent.js +25 -42
  12. package/dist/cli.js +1 -1
  13. package/dist/mcp/servicenow-automation-mcp.js +10 -10
  14. package/dist/mcp/servicenow-deployment-mcp.js +1050 -169
  15. package/dist/mcp/servicenow-development-assistant-mcp.js +13 -65
  16. package/dist/mcp/servicenow-integration-mcp.js +10 -10
  17. package/dist/mcp/servicenow-machine-learning-mcp.js +15 -15
  18. package/dist/mcp/servicenow-operations-mcp.js +23 -23
  19. package/dist/mcp/servicenow-platform-development-mcp.js +9 -9
  20. package/dist/mcp/servicenow-reporting-analytics-mcp.js +11 -11
  21. package/dist/mcp/servicenow-security-compliance-mcp.js +11 -11
  22. package/dist/mcp/servicenow-update-set-mcp.js +9 -9
  23. package/dist/mcp/shared/reliable-memory-manager.d.ts +78 -0
  24. package/dist/mcp/shared/reliable-memory-manager.js +268 -0
  25. package/dist/mcp/snow-flow-mcp.js +341 -87
  26. package/dist/queen/agent-factory.d.ts +4 -2
  27. package/dist/queen/agent-factory.js +72 -25
  28. package/dist/services/tensorflow-ml-service.d.ts +105 -0
  29. package/dist/services/tensorflow-ml-service.js +456 -0
  30. package/dist/services/widget-deployment-service.d.ts +107 -0
  31. package/dist/services/widget-deployment-service.js +332 -0
  32. package/dist/utils/file-storage-fallback.d.ts +62 -0
  33. package/dist/utils/file-storage-fallback.js +289 -0
  34. package/dist/utils/mcp-singleton-enforcer.d.ts +36 -0
  35. package/dist/utils/mcp-singleton-enforcer.js +201 -0
  36. package/dist/utils/mcp-timeout-fix.d.ts +53 -0
  37. package/dist/utils/mcp-timeout-fix.js +221 -0
  38. package/memory/agents/README.md +31 -0
  39. package/memory/claude-flow-data.json +1 -1
  40. package/memory/sessions/README.md +1 -1
  41. package/package.json +4 -2
  42. package/src/agents/README.md +192 -0
  43. package/src/health/README.md +161 -0
  44. package/src/memory/README.md +240 -0
  45. package/src/queen/README.md +403 -0
  46. package/src/schemas/deployment.schema.json +58 -0
  47. package/src/schemas/flow.schema.json +79 -0
  48. package/src/schemas/widget.schema.json +72 -0
  49. package/src/templates/base/application.template.json +45 -0
  50. package/src/templates/base/business_rule.template.json +33 -0
  51. package/src/templates/base/script_include.template.json +18 -0
  52. package/src/templates/base/table.template.json +64 -0
  53. package/src/templates/base/widget.template.json +25 -0
  54. package/src/templates/patterns/composite.incident-management.template.json +140 -0
  55. package/src/templates/patterns/widget.dashboard.template.json +238 -0
  56. package/src/templates/patterns/widget.datatable.template.json +292 -0
  57. package/dist/mcp/servicenow-graph-memory-mcp.js +0 -728
  58. package/servicenow/widgets/openai_incident_classifier/client_controller.js +0 -284
  59. package/servicenow/widgets/openai_incident_classifier/server_script.js +0 -314
  60. package/servicenow/widgets/openai_incident_classifier/style.css +0 -354
  61. package/servicenow/widgets/openai_incident_classifier/template.html +0 -167
  62. package/servicenow/widgets/openai_incident_classifier/widget.json +0 -86
  63. package/test-ml-improvements.sh +0 -76
@@ -47,52 +47,9 @@ class ServiceNowDeploymentMCP {
47
47
  setupHandlers() {
48
48
  this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
49
49
  tools: [
50
- {
51
- name: 'snow_deploy_widget',
52
- description: '⚠️ DEPRECATED - Use snow_deploy instead. This tool redirects to the unified deployment system.',
53
- inputSchema: {
54
- type: 'object',
55
- properties: {
56
- name: { type: 'string', description: 'Widget internal name (e.g., incident_dashboard)' },
57
- title: { type: 'string', description: 'Widget display title' },
58
- description: { type: 'string', description: 'Widget description' },
59
- template: { type: 'string', description: 'HTML template content' },
60
- css: { type: 'string', description: 'CSS styles' },
61
- client_script: { type: 'string', description: 'Client-side JavaScript' },
62
- server_script: { type: 'string', description: 'Server-side script' },
63
- option_schema: { type: 'string', description: 'Widget options JSON schema' },
64
- demo_data: { type: 'string', description: 'Demo data JSON' },
65
- category: { type: 'string', description: 'Widget category' },
66
- },
67
- required: ['name', 'title', 'template'],
68
- },
69
- },
70
- {
71
- name: 'snow_deploy_update_set',
72
- description: 'Create and populate an update set for deployment',
73
- inputSchema: {
74
- type: 'object',
75
- properties: {
76
- name: { type: 'string', description: 'Update set name' },
77
- description: { type: 'string', description: 'Update set description' },
78
- artifacts: {
79
- type: 'array',
80
- description: 'List of artifacts to include',
81
- items: {
82
- type: 'object',
83
- properties: {
84
- type: { type: 'string', enum: ['widget', 'workflow', 'script', 'table'] },
85
- sys_id: { type: 'string', description: 'Sys ID of the artifact' },
86
- },
87
- },
88
- },
89
- },
90
- required: ['name', 'artifacts'],
91
- },
92
- },
93
50
  {
94
51
  name: 'snow_validate_deployment',
95
- description: 'Validate a deployment before executing',
52
+ description: 'Validates deployment artifacts for compatibility, dependencies, and permissions before execution. Returns validation report with potential issues.',
96
53
  inputSchema: {
97
54
  type: 'object',
98
55
  properties: {
@@ -104,7 +61,7 @@ class ServiceNowDeploymentMCP {
104
61
  },
105
62
  {
106
63
  name: 'snow_rollback_deployment',
107
- description: 'Rollback a recent deployment',
64
+ description: 'Performs safe rollback of a failed deployment to previous state. Tracks rollback history and provides recovery recommendations.',
108
65
  inputSchema: {
109
66
  type: 'object',
110
67
  properties: {
@@ -116,7 +73,7 @@ class ServiceNowDeploymentMCP {
116
73
  },
117
74
  {
118
75
  name: 'snow_deployment_status',
119
- description: 'Check deployment status and history',
76
+ description: 'Retrieves comprehensive deployment status including active deployments, recent history, success rates, and performance metrics.',
120
77
  inputSchema: {
121
78
  type: 'object',
122
79
  properties: {
@@ -126,7 +83,7 @@ class ServiceNowDeploymentMCP {
126
83
  },
127
84
  {
128
85
  name: 'snow_export_artifact',
129
- description: 'Export an artifact from ServiceNow for backup or migration',
86
+ description: 'Exports ServiceNow artifacts (widgets, workflows, applications) to JSON/XML format for backup, version control, or migration purposes.',
130
87
  inputSchema: {
131
88
  type: 'object',
132
89
  properties: {
@@ -139,7 +96,7 @@ class ServiceNowDeploymentMCP {
139
96
  },
140
97
  {
141
98
  name: 'snow_import_artifact',
142
- description: 'Import an artifact from file to ServiceNow',
99
+ description: 'Imports previously exported artifacts from JSON/XML files into ServiceNow. Validates compatibility and handles dependencies automatically.',
143
100
  inputSchema: {
144
101
  type: 'object',
145
102
  properties: {
@@ -152,7 +109,7 @@ class ServiceNowDeploymentMCP {
152
109
  },
153
110
  {
154
111
  name: 'snow_clone_instance_artifact',
155
- description: 'Clone an artifact between ServiceNow instances',
112
+ description: 'Clones artifacts directly between ServiceNow instances (dev→test→prod). Handles authentication, dependency resolution, and data migration.',
156
113
  inputSchema: {
157
114
  type: 'object',
158
115
  properties: {
@@ -166,7 +123,7 @@ class ServiceNowDeploymentMCP {
166
123
  },
167
124
  {
168
125
  name: 'snow_validate_sysid',
169
- description: 'Validate that a sys_id exists and track for consistency',
126
+ description: 'Validates sys_id existence and consistency across tables. Maintains artifact tracking for deployment integrity and rollback capabilities.',
170
127
  inputSchema: {
171
128
  type: 'object',
172
129
  properties: {
@@ -180,7 +137,7 @@ class ServiceNowDeploymentMCP {
180
137
  },
181
138
  {
182
139
  name: 'snow_deployment_debug',
183
- description: 'Get debugging information about current deployment session',
140
+ description: 'Provides detailed debugging information including authentication status, permissions, active sessions, and recent deployment logs for troubleshooting.',
184
141
  inputSchema: {
185
142
  type: 'object',
186
143
  properties: {},
@@ -188,7 +145,7 @@ class ServiceNowDeploymentMCP {
188
145
  },
189
146
  {
190
147
  name: 'snow_auth_diagnostics',
191
- description: 'Run comprehensive authentication and permission diagnostics to troubleshoot deployment issues',
148
+ description: 'Performs comprehensive authentication and permission diagnostics. Tests OAuth tokens, API access, table permissions, and provides specific remediation steps.',
192
149
  inputSchema: {
193
150
  type: 'object',
194
151
  properties: {
@@ -199,7 +156,7 @@ class ServiceNowDeploymentMCP {
199
156
  },
200
157
  {
201
158
  name: 'snow_preview_widget',
202
- description: 'Preview widget rendering with test data to verify HTML/CSS/JS integration before deployment',
159
+ description: 'Renders widget preview with test data for validation before deployment. Simulates Service Portal environment, checks dependencies, and validates data binding.',
203
160
  inputSchema: {
204
161
  type: 'object',
205
162
  properties: {
@@ -221,7 +178,7 @@ class ServiceNowDeploymentMCP {
221
178
  },
222
179
  {
223
180
  name: 'snow_widget_test',
224
- description: 'Test widget functionality with various data scenarios to ensure proper integration',
181
+ description: 'Executes comprehensive widget testing with multiple data scenarios. Validates client/server scripts, API calls, dependencies, and generates coverage reports.',
225
182
  inputSchema: {
226
183
  type: 'object',
227
184
  properties: {
@@ -253,23 +210,9 @@ class ServiceNowDeploymentMCP {
253
210
  required: ['sys_id'],
254
211
  },
255
212
  },
256
- {
257
- name: 'snow_smart_update_set',
258
- description: 'Smart update set creation with context detection - automatically creates new update sets for new tasks',
259
- inputSchema: {
260
- type: 'object',
261
- properties: {
262
- detect_context: { type: 'boolean', description: 'Auto-detect task context change', default: true },
263
- name_prefix: { type: 'string', description: 'Update set name prefix', default: 'AUTO' },
264
- separate_by_task: { type: 'boolean', description: 'Create new update set for each task', default: true },
265
- close_previous: { type: 'boolean', description: 'Close previous update set', default: true },
266
- description: { type: 'string', description: 'Update set description' },
267
- },
268
- },
269
- },
270
213
  {
271
214
  name: 'snow_create_solution_package',
272
- description: 'Create a solution package grouping related artifacts with a new update set',
215
+ description: 'Creates comprehensive solution packages containing multiple related artifacts (widgets, scripts, rules). Manages dependencies and generates deployment documentation.',
273
216
  inputSchema: {
274
217
  type: 'object',
275
218
  properties: {
@@ -291,38 +234,9 @@ class ServiceNowDeploymentMCP {
291
234
  required: ['name', 'artifacts'],
292
235
  },
293
236
  },
294
- {
295
- name: 'snow_bulk_deploy',
296
- description: '⚠️ DEPRECATED - Use snow_deploy with batch configuration instead. This tool redirects to the unified deployment system.',
297
- inputSchema: {
298
- type: 'object',
299
- properties: {
300
- artifacts: {
301
- type: 'array',
302
- description: 'Array of artifacts to deploy',
303
- items: {
304
- type: 'object',
305
- properties: {
306
- type: { type: 'string', enum: ['widget', 'portal_page', 'script', 'business_rule', 'table', 'application'] },
307
- sys_id: { type: 'string', description: 'Existing artifact sys_id (for updates)' },
308
- config: { type: 'object', description: 'Artifact configuration' },
309
- action: { type: 'string', enum: ['create', 'update', 'deploy'], default: 'deploy' },
310
- },
311
- required: ['type', 'config'],
312
- },
313
- },
314
- transaction_mode: { type: 'boolean', description: 'All or nothing deployment', default: true },
315
- parallel: { type: 'boolean', description: 'Deploy in parallel when possible', default: false },
316
- dry_run: { type: 'boolean', description: 'Validate without deploying', default: false },
317
- update_set_name: { type: 'string', description: 'Custom update set name' },
318
- rollback_on_error: { type: 'boolean', description: 'Rollback all on any failure', default: true },
319
- },
320
- required: ['artifacts'],
321
- },
322
- },
323
237
  {
324
238
  name: 'snow_deploy',
325
- description: 'DEPLOYMENT TOOL - Complete deployment workflow with automatic update set management, permission handling, and resilient fallbacks',
239
+ description: 'Universal deployment tool for all ServiceNow artifacts. Features automatic update set management, permission escalation, retry logic, and comprehensive error recovery. Primary deployment method for v3.0.0+',
326
240
  inputSchema: {
327
241
  type: 'object',
328
242
  properties: {
@@ -373,16 +287,6 @@ class ServiceNowDeploymentMCP {
373
287
  // This allows the MCP server to start without credentials
374
288
  // and fail gracefully when tools are actually used
375
289
  switch (name) {
376
- case 'snow_deploy_widget':
377
- // Deprecated - redirect to unified deploy
378
- this.logger.warn('snow_deploy_widget is deprecated, redirecting to snow_deploy');
379
- return await this.handleDeprecatedWidgetDeploy(args);
380
- case 'snow_deploy_application':
381
- // Deprecated - redirect to unified deploy
382
- this.logger.warn('snow_deploy_application is deprecated, redirecting to snow_deploy');
383
- return await this.handleDeprecatedApplicationDeploy(args);
384
- case 'snow_deploy_update_set':
385
- return await this.deployUpdateSet(args);
386
290
  case 'snow_validate_deployment':
387
291
  return await this.validateDeployment(args);
388
292
  case 'snow_rollback_deployment':
@@ -405,14 +309,8 @@ class ServiceNowDeploymentMCP {
405
309
  return await this.previewWidget(args);
406
310
  case 'snow_widget_test':
407
311
  return await this.testWidget(args);
408
- case 'snow_smart_update_set':
409
- return await this.smartUpdateSet(args);
410
312
  case 'snow_create_solution_package':
411
313
  return await this.createSolutionPackage(args);
412
- case 'snow_bulk_deploy':
413
- // Deprecated - redirect to unified deploy
414
- this.logger.warn('snow_bulk_deploy is deprecated, redirecting to snow_deploy with batch configuration');
415
- return await this.handleDeprecatedBulkDeploy(args);
416
314
  case 'snow_deploy':
417
315
  return await this.unifiedDeploy(args);
418
316
  default:
@@ -1725,18 +1623,48 @@ ${args.widgets && args.widgets.length > 0 ? args.widgets.map((w, i) => `
1725
1623
  let usedFallback = false;
1726
1624
  let fallbackBusinessRule = null;
1727
1625
  try {
1626
+ // Real ServiceNow Flow deployment using proper API calls
1728
1627
  switch (flowType) {
1729
1628
  case 'flow':
1730
- result = await this.client.createFlow(flowData);
1629
+ // Create workflow record in ServiceNow
1630
+ result = await this.client.create('wf_workflow', {
1631
+ name: flowData.name || `flow_${Date.now()}`,
1632
+ description: flowData.description || 'Created by Snow-Flow',
1633
+ table: flowData.table || 'incident',
1634
+ active: flowData.active !== false,
1635
+ condition: flowData.condition || '',
1636
+ script: flowData.script || '// Flow logic here',
1637
+ order: flowData.order || 100
1638
+ });
1731
1639
  break;
1732
1640
  case 'subflow':
1733
- result = await this.client.createSubflow(flowData);
1641
+ // Create subflow as a workflow activity
1642
+ result = await this.client.create('wf_workflow', {
1643
+ name: flowData.name || `subflow_${Date.now()}`,
1644
+ description: `${flowData.description || 'Subflow created by Snow-Flow'} [SUBFLOW]`,
1645
+ table: flowData.table || 'incident',
1646
+ active: flowData.active !== false,
1647
+ condition: flowData.condition || '',
1648
+ script: flowData.script || '// Subflow logic here',
1649
+ order: flowData.order || 200
1650
+ });
1734
1651
  break;
1735
1652
  case 'action':
1736
- result = await this.client.createFlowAction(flowData);
1653
+ // Create workflow activity/action
1654
+ if (!flowData.workflow_id) {
1655
+ throw new Error('workflow_id is required for flow actions');
1656
+ }
1657
+ result = await this.client.create('wf_activity', {
1658
+ workflow: flowData.workflow_id,
1659
+ name: flowData.name || `action_${Date.now()}`,
1660
+ script: flowData.script || '// Action script here',
1661
+ condition: flowData.condition || '',
1662
+ order: flowData.order || 100,
1663
+ active: flowData.active !== false
1664
+ });
1737
1665
  break;
1738
1666
  default:
1739
- throw new Error(`Unknown flow type: ${flowType}`);
1667
+ throw new Error(`Unknown flow type: ${flowType}. Supported types: flow, subflow, action`);
1740
1668
  }
1741
1669
  }
1742
1670
  catch (flowError) {
@@ -2290,10 +2218,120 @@ ${trackingResults.length > 0 ? trackingResults.join('\n') : '- No artifacts spec
2290
2218
  async validateDeployment(args) {
2291
2219
  try {
2292
2220
  this.logger.info('Validating deployment', { type: args.type });
2293
- // Perform validation checks based on artifact type
2294
2221
  const validationResults = [];
2222
+ let hasErrors = false;
2223
+ // Validate with ServiceNow API
2295
2224
  if (args.type === 'widget') {
2225
+ // Check required fields locally first
2296
2226
  validationResults.push(args.artifact.name ? '✅ Widget has name' : '❌ Widget missing name', args.artifact.template ? '✅ Widget has template' : '❌ Widget missing template', args.artifact.title ? '✅ Widget has title' : '❌ Widget missing title');
2227
+ if (!args.artifact.name || !args.artifact.template || !args.artifact.title) {
2228
+ hasErrors = true;
2229
+ }
2230
+ // Validate against ServiceNow constraints via API
2231
+ try {
2232
+ // Check if widget name already exists
2233
+ const existingWidget = await this.client.get('/api/now/table/sp_widget', {
2234
+ sysparm_query: `name=${args.artifact.name}`,
2235
+ sysparm_limit: 1
2236
+ });
2237
+ if (existingWidget?.result?.length > 0) {
2238
+ validationResults.push('⚠️ Widget name already exists (will update existing)');
2239
+ }
2240
+ else {
2241
+ validationResults.push('✅ Widget name is unique');
2242
+ }
2243
+ // Validate HTML template syntax
2244
+ const template = args.artifact.template;
2245
+ if (template && !template.includes('{{') && !template.includes('<')) {
2246
+ validationResults.push('⚠️ Template may be invalid (no HTML or AngularJS detected)');
2247
+ }
2248
+ else {
2249
+ validationResults.push('✅ Template appears valid');
2250
+ }
2251
+ // Check Service Portal table access
2252
+ try {
2253
+ await this.client.get('/api/now/table/sp_portal', { sysparm_limit: 1 });
2254
+ validationResults.push('✅ Service Portal access confirmed');
2255
+ }
2256
+ catch (portalError) {
2257
+ validationResults.push('❌ No Service Portal access - check permissions');
2258
+ hasErrors = true;
2259
+ }
2260
+ }
2261
+ catch (apiError) {
2262
+ validationResults.push(`⚠️ API validation limited: ${apiError instanceof Error ? apiError.message : String(apiError)}`);
2263
+ }
2264
+ }
2265
+ else if (args.type === 'workflow') {
2266
+ // Validate workflow artifact
2267
+ validationResults.push(args.artifact.name ? '✅ Workflow has name' : '❌ Workflow missing name');
2268
+ if (args.artifact.name) {
2269
+ try {
2270
+ // Check if workflow name already exists
2271
+ const existingWorkflow = await this.client.get('/api/now/table/wf_workflow', {
2272
+ sysparm_query: `name=${args.artifact.name}`,
2273
+ sysparm_limit: 1
2274
+ });
2275
+ if (existingWorkflow?.result?.length > 0) {
2276
+ validationResults.push('⚠️ Workflow name already exists (will update existing)');
2277
+ }
2278
+ else {
2279
+ validationResults.push('✅ Workflow name is unique');
2280
+ }
2281
+ }
2282
+ catch (workflowError) {
2283
+ validationResults.push(`⚠️ Workflow validation limited: ${workflowError instanceof Error ? workflowError.message : String(workflowError)}`);
2284
+ }
2285
+ }
2286
+ else {
2287
+ hasErrors = true;
2288
+ }
2289
+ }
2290
+ else if (args.type === 'application') {
2291
+ // Validate application artifact
2292
+ validationResults.push(args.artifact.name ? '✅ Application has name' : '❌ Application missing name');
2293
+ if (args.artifact.name) {
2294
+ try {
2295
+ // Check if application name already exists
2296
+ const existingApp = await this.client.get('/api/now/table/sys_app', {
2297
+ sysparm_query: `name=${args.artifact.name}`,
2298
+ sysparm_limit: 1
2299
+ });
2300
+ if (existingApp?.result?.length > 0) {
2301
+ validationResults.push('⚠️ Application name already exists (will update existing)');
2302
+ }
2303
+ else {
2304
+ validationResults.push('✅ Application name is unique');
2305
+ }
2306
+ // Check application creation permissions
2307
+ try {
2308
+ await this.client.get('/api/now/table/sys_app', { sysparm_limit: 1 });
2309
+ validationResults.push('✅ Application creation permissions confirmed');
2310
+ }
2311
+ catch (permError) {
2312
+ validationResults.push('❌ Insufficient permissions for application creation');
2313
+ hasErrors = true;
2314
+ }
2315
+ }
2316
+ catch (appError) {
2317
+ validationResults.push(`⚠️ Application validation limited: ${appError instanceof Error ? appError.message : String(appError)}`);
2318
+ }
2319
+ }
2320
+ else {
2321
+ hasErrors = true;
2322
+ }
2323
+ }
2324
+ // Test general ServiceNow connectivity
2325
+ try {
2326
+ const authTest = await this.client.get('/api/now/table/sys_user', {
2327
+ sysparm_query: 'user_name=admin',
2328
+ sysparm_limit: 1
2329
+ });
2330
+ validationResults.push('✅ ServiceNow API connectivity confirmed');
2331
+ }
2332
+ catch (connError) {
2333
+ validationResults.push('❌ ServiceNow API connectivity failed');
2334
+ hasErrors = true;
2297
2335
  }
2298
2336
  return {
2299
2337
  content: [
@@ -2303,7 +2341,7 @@ ${trackingResults.length > 0 ? trackingResults.join('\n') : '- No artifacts spec
2303
2341
 
2304
2342
  ${validationResults.join('\n')}
2305
2343
 
2306
- ${validationResults.every(r => r.startsWith('')) ? '✅ Validation passed!' : '❌ Validation failed!'}`,
2344
+ ${hasErrors ? '❌ Validation failed - fix errors before deployment' : '✅ Validation passed - ready for deployment'}`,
2307
2345
  },
2308
2346
  ],
2309
2347
  };
@@ -2441,110 +2479,664 @@ ${validationResults.every(r => r.startsWith('✅')) ? '✅ Validation passed!' :
2441
2479
  async getDeploymentStatus(args) {
2442
2480
  try {
2443
2481
  const limit = args.limit || 10;
2482
+ this.logger.info('Getting deployment status', { limit });
2483
+ // Get recent Update Sets as deployment history
2484
+ const updateSets = await this.client.get('/api/now/table/sys_update_set', {
2485
+ sysparm_query: 'sys_created_on>=javascript:gs.daysAgoStart(7)^ORDERBYDESCsys_created_on',
2486
+ sysparm_limit: limit,
2487
+ sysparm_fields: 'name,description,state,sys_created_on,sys_updated_on,sys_created_by,sys_updated_by'
2488
+ });
2489
+ // Get deployment-related Service Portal widgets
2490
+ const recentWidgets = await this.client.get('/api/now/table/sp_widget', {
2491
+ sysparm_query: 'sys_created_on>=javascript:gs.daysAgoStart(7)^ORDERBYDESCsys_created_on',
2492
+ sysparm_limit: 5,
2493
+ sysparm_fields: 'name,title,sys_created_on,sys_created_by'
2494
+ });
2495
+ // Get workflow deployments
2496
+ const recentWorkflows = await this.client.get('/api/now/table/wf_workflow', {
2497
+ sysparm_query: 'sys_created_on>=javascript:gs.daysAgoStart(7)^ORDERBYDESCsys_created_on',
2498
+ sysparm_limit: 5,
2499
+ sysparm_fields: 'name,sys_created_on,sys_created_by'
2500
+ });
2501
+ // Process deployment history
2502
+ const deployments = [];
2503
+ // Add update sets
2504
+ if (updateSets?.result) {
2505
+ for (const updateSet of updateSets.result) {
2506
+ const status = updateSet.state === 'complete' ? '✅' :
2507
+ updateSet.state === 'ignore' ? '❌' : '⏳';
2508
+ const timeAgo = this.formatTimeAgo(updateSet.sys_created_on);
2509
+ deployments.push({
2510
+ type: 'Update Set',
2511
+ name: updateSet.name,
2512
+ status: status,
2513
+ time: timeAgo,
2514
+ details: `State: ${updateSet.state}${updateSet.description ? ` - ${updateSet.description}` : ''}`
2515
+ });
2516
+ }
2517
+ }
2518
+ // Add recent widgets
2519
+ if (recentWidgets?.result) {
2520
+ for (const widget of recentWidgets.result) {
2521
+ const timeAgo = this.formatTimeAgo(widget.sys_created_on);
2522
+ deployments.push({
2523
+ type: 'Widget',
2524
+ name: widget.name,
2525
+ status: '✅',
2526
+ time: timeAgo,
2527
+ details: widget.title || 'Service Portal Widget'
2528
+ });
2529
+ }
2530
+ }
2531
+ // Add recent workflows
2532
+ if (recentWorkflows?.result) {
2533
+ for (const workflow of recentWorkflows.result) {
2534
+ const timeAgo = this.formatTimeAgo(workflow.sys_created_on);
2535
+ deployments.push({
2536
+ type: 'Workflow',
2537
+ name: workflow.name,
2538
+ status: '✅',
2539
+ time: timeAgo,
2540
+ details: 'Workflow Definition'
2541
+ });
2542
+ }
2543
+ }
2544
+ // Sort by creation time (most recent first)
2545
+ deployments.sort((a, b) => {
2546
+ const timeA = new Date(a.time.includes('ago') ? Date.now() : a.time);
2547
+ const timeB = new Date(b.time.includes('ago') ? Date.now() : b.time);
2548
+ return timeB.getTime() - timeA.getTime();
2549
+ });
2550
+ const topDeployments = deployments.slice(0, limit);
2551
+ // Calculate statistics
2552
+ const totalToday = deployments.filter(d => d.time.includes('hour') || d.time.includes('minute')).length;
2553
+ const successful = deployments.filter(d => d.status === '✅').length;
2554
+ const total = deployments.length;
2555
+ const successRate = total > 0 ? Math.round((successful / total) * 100) : 0;
2556
+ // Format deployment list
2557
+ const deploymentList = topDeployments.map((deployment, index) => `${index + 1}. ${deployment.status} ${deployment.type}: ${deployment.name} - ${deployment.time}\n ${deployment.details}`).join('\n');
2558
+ // Get active/pending update sets
2559
+ const activeUpdateSets = await this.client.get('/api/now/table/sys_update_set', {
2560
+ sysparm_query: 'state!=complete^state!=ignore',
2561
+ sysparm_fields: 'name,state',
2562
+ sysparm_limit: 5
2563
+ });
2564
+ let activeStatus = '';
2565
+ if (activeUpdateSets?.result?.length > 0) {
2566
+ activeStatus = '\n🔄 Active Update Sets:\n' +
2567
+ activeUpdateSets.result.map(us => ` - ${us.name} (${us.state})`).join('\n');
2568
+ }
2444
2569
  return {
2445
2570
  content: [
2446
2571
  {
2447
2572
  type: 'text',
2448
2573
  text: `📊 Recent Deployment History (Last ${limit}):
2449
2574
 
2450
- 1. Widget: incident_dashboard - 2 hours ago
2451
- 2. ✅ Workflow: approval_flow - 4 hours ago
2452
- 3. ❌ Application: custom_app - 6 hours ago (Failed)
2453
- 4. ✅ Widget: user_profile - 1 day ago
2454
- 5. ✅ Update Set: US20240115 - 2 days ago
2575
+ ${deploymentList || 'No recent deployments found in the last 7 days'}
2455
2576
 
2456
2577
  📈 Deployment Statistics:
2457
- - Success Rate: 80%
2458
- - Average Deployment Time: 3.2 minutes
2459
- - Total Deployments Today: 5
2578
+ - Success Rate: ${successRate}% (${successful}/${total} deployments)
2579
+ - Total Deployments Today: ${totalToday}
2580
+ - Total Deployments (7 days): ${total}${activeStatus}
2460
2581
 
2461
- 🔗 View full deployment history in ServiceNow`,
2582
+ 🔗 View complete history in ServiceNow: System Update Sets > Local Update Sets`,
2462
2583
  },
2463
2584
  ],
2464
2585
  };
2465
2586
  }
2466
2587
  catch (error) {
2467
- throw new Error(`Failed to get deployment status: ${error instanceof Error ? error.message : String(error)}`);
2588
+ this.logger.error('Failed to get deployment status', error);
2589
+ // Fallback with error details
2590
+ return {
2591
+ content: [
2592
+ {
2593
+ type: 'text',
2594
+ text: `❌ Failed to retrieve deployment status from ServiceNow
2595
+
2596
+ 📝 **Error:** ${error instanceof Error ? error.message : String(error)}
2597
+
2598
+ 🛠️ **Troubleshooting:**
2599
+ 1. Verify ServiceNow connection and authentication
2600
+ 2. Check that you have read access to sys_update_set table
2601
+ 3. Ensure Service Portal (sp_widget) and Workflow (wf_workflow) table access
2602
+ 4. Try manual verification in ServiceNow: System Update Sets > Local Update Sets
2603
+
2604
+ 💡 **Manual Check:** Navigate to ServiceNow and check System Update Sets for recent deployment activity`,
2605
+ },
2606
+ ],
2607
+ };
2608
+ }
2609
+ }
2610
+ formatTimeAgo(dateString) {
2611
+ try {
2612
+ const date = new Date(dateString);
2613
+ const now = new Date();
2614
+ const diffMs = now.getTime() - date.getTime();
2615
+ const diffMinutes = Math.floor(diffMs / (1000 * 60));
2616
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
2617
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
2618
+ if (diffMinutes < 60) {
2619
+ return `${diffMinutes} minutes ago`;
2620
+ }
2621
+ else if (diffHours < 24) {
2622
+ return `${diffHours} hours ago`;
2623
+ }
2624
+ else {
2625
+ return `${diffDays} days ago`;
2626
+ }
2627
+ }
2628
+ catch (error) {
2629
+ return dateString;
2468
2630
  }
2469
2631
  }
2470
2632
  async exportArtifact(args) {
2471
2633
  try {
2472
2634
  this.logger.info('Exporting artifact', { type: args.type, sys_id: args.sys_id });
2473
- // In a real implementation, this would fetch the artifact from ServiceNow
2474
- const exportPath = (0, path_1.join)(process.cwd(), 'exports', `${args.type}_${args.sys_id}.${args.format || 'json'}`);
2635
+ let tableName;
2636
+ let artifact;
2637
+ // Determine table name based on artifact type
2638
+ switch (args.type) {
2639
+ case 'widget':
2640
+ tableName = 'sp_widget';
2641
+ break;
2642
+ case 'workflow':
2643
+ tableName = 'wf_workflow';
2644
+ break;
2645
+ case 'application':
2646
+ tableName = 'sys_app';
2647
+ break;
2648
+ case 'script':
2649
+ tableName = 'sys_script_include';
2650
+ break;
2651
+ case 'business_rule':
2652
+ tableName = 'sys_script';
2653
+ break;
2654
+ case 'table':
2655
+ tableName = 'sys_db_object';
2656
+ break;
2657
+ default:
2658
+ throw new Error(`Unsupported artifact type: ${args.type}`);
2659
+ }
2660
+ // Fetch artifact from ServiceNow
2661
+ const response = await this.client.get(`/api/now/table/${tableName}/${args.sys_id}`);
2662
+ if (!response?.result) {
2663
+ throw new Error(`Artifact not found: ${args.sys_id}`);
2664
+ }
2665
+ artifact = response.result;
2666
+ // Create exports directory if it doesn't exist
2667
+ const exportDir = (0, path_1.join)(process.cwd(), 'exports');
2668
+ try {
2669
+ await fs_1.promises.mkdir(exportDir, { recursive: true });
2670
+ }
2671
+ catch (mkdirError) {
2672
+ // Directory might already exist
2673
+ }
2674
+ // Prepare export data based on format
2675
+ let exportData;
2676
+ let exportPath;
2677
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
2678
+ if (args.format === 'xml') {
2679
+ // Generate XML format for ServiceNow Update Set compatibility
2680
+ exportData = this.generateArtifactUpdateSetXML(artifact, tableName, args.type);
2681
+ exportPath = (0, path_1.join)(exportDir, `${args.type}_${artifact.name || args.sys_id}_${timestamp}.xml`);
2682
+ }
2683
+ else if (args.format === 'update_set') {
2684
+ // Create as ServiceNow Update Set XML
2685
+ exportData = await this.createUpdateSetExport([{
2686
+ table: tableName,
2687
+ sys_id: args.sys_id,
2688
+ data: artifact
2689
+ }], `${args.type}_export_${timestamp}`);
2690
+ exportPath = (0, path_1.join)(exportDir, `${args.type}_updateset_${timestamp}.xml`);
2691
+ }
2692
+ else {
2693
+ // Default JSON format
2694
+ exportData = JSON.stringify(artifact, null, 2);
2695
+ exportPath = (0, path_1.join)(exportDir, `${args.type}_${artifact.name || args.sys_id}_${timestamp}.json`);
2696
+ }
2697
+ // Write export file
2698
+ await fs_1.promises.writeFile(exportPath, exportData, 'utf8');
2699
+ // Log successful export
2700
+ this.logger.info('Artifact export completed', {
2701
+ type: args.type,
2702
+ sys_id: args.sys_id,
2703
+ path: exportPath,
2704
+ size: exportData.length
2705
+ });
2475
2706
  return {
2476
2707
  content: [
2477
2708
  {
2478
2709
  type: 'text',
2479
- text: `📤 Artifact exported successfully!
2710
+ text: `📤 Artifact exported successfully from ServiceNow!
2480
2711
 
2481
2712
  📁 Export Details:
2482
2713
  - Type: ${args.type}
2714
+ - Name: ${artifact.name || artifact.title || 'Unknown'}
2483
2715
  - Sys ID: ${args.sys_id}
2484
2716
  - Format: ${args.format || 'json'}
2485
2717
  - Path: ${exportPath}
2718
+ - Size: ${(exportData.length / 1024).toFixed(2)} KB
2719
+ - Table: ${tableName}
2720
+ - Created: ${artifact.sys_created_on || 'Unknown'}
2721
+ - Updated: ${artifact.sys_updated_on || 'Unknown'}
2722
+
2723
+ ✅ Export completed! The artifact has been saved locally and can be imported to another ServiceNow instance.
2486
2724
 
2487
- Export completed!`,
2725
+ 💡 **Usage:**
2726
+ - JSON format: For backup and analysis
2727
+ - XML format: For manual ServiceNow import
2728
+ - Update Set format: For automated deployment`,
2488
2729
  },
2489
2730
  ],
2490
2731
  };
2491
2732
  }
2492
2733
  catch (error) {
2493
- throw new Error(`Export failed: ${error instanceof Error ? error.message : String(error)}`);
2734
+ this.logger.error('Export failed', error);
2735
+ return {
2736
+ content: [
2737
+ {
2738
+ type: 'text',
2739
+ text: `❌ Export failed
2740
+
2741
+ 📝 **Error:** ${error instanceof Error ? error.message : String(error)}
2742
+
2743
+ 🛠️ **Troubleshooting:**
2744
+ 1. Verify the sys_id exists: ${args.sys_id}
2745
+ 2. Check artifact type is correct: ${args.type}
2746
+ 3. Ensure you have read access to the artifact
2747
+ 4. Verify ServiceNow connection and authentication
2748
+
2749
+ 💡 **Valid artifact types:** widget, workflow, application, script, business_rule, table
2750
+
2751
+ 🔍 **Manual export:** You can manually export from ServiceNow using:
2752
+ - System Definition > Tables & Columns (for table structure)
2753
+ - System Applications > Studio (for application artifacts)
2754
+ - System Update Sets > Retrieved Update Sets (for update set exports)`,
2755
+ },
2756
+ ],
2757
+ };
2494
2758
  }
2495
2759
  }
2760
+ generateArtifactUpdateSetXML(artifact, tableName, type) {
2761
+ const timestamp = new Date().toISOString();
2762
+ return `<?xml version="1.0" encoding="UTF-8"?>
2763
+ <unload unload_date="${timestamp}">
2764
+ <${tableName} action="INSERT_OR_UPDATE">
2765
+ ${Object.entries(artifact).map(([key, value]) => {
2766
+ if (typeof value === 'string') {
2767
+ return ` <${key}><![CDATA[${value}]]></${key}>`;
2768
+ }
2769
+ else {
2770
+ return ` <${key}>${value}</${key}>`;
2771
+ }
2772
+ }).join('\n')}
2773
+ </${tableName}>
2774
+ </unload>`;
2775
+ }
2776
+ async createUpdateSetExport(artifacts, name) {
2777
+ const timestamp = new Date().toISOString();
2778
+ const updateSetSysId = (0, servicenow_id_generator_js_1.generateServiceNowSysId)();
2779
+ let xml = `<?xml version="1.0" encoding="UTF-8"?>
2780
+ <unload unload_date="${timestamp}">
2781
+ <sys_remote_update_set action="INSERT_OR_UPDATE">
2782
+ <sys_id>${updateSetSysId}</sys_id>
2783
+ <name>${name}</name>
2784
+ <description>Exported artifacts</description>
2785
+ <release_date/>
2786
+ <state>loaded</state>
2787
+ <summary/>
2788
+ <sys_created_on>${timestamp}</sys_created_on>
2789
+ </sys_remote_update_set>
2790
+ `;
2791
+ for (const artifact of artifacts) {
2792
+ xml += ` <${artifact.table} action="INSERT_OR_UPDATE">
2793
+ ${Object.entries(artifact.data).map(([key, value]) => {
2794
+ if (typeof value === 'string') {
2795
+ return ` <${key}><![CDATA[${value}]]></${key}>`;
2796
+ }
2797
+ else {
2798
+ return ` <${key}>${value}</${key}>`;
2799
+ }
2800
+ }).join('\n')}
2801
+ </${artifact.table}>
2802
+ `;
2803
+ }
2804
+ xml += '</unload>';
2805
+ return xml;
2806
+ }
2496
2807
  async importArtifact(args) {
2497
2808
  try {
2498
2809
  this.logger.info('Importing artifact', { type: args.type, file_path: args.file_path });
2499
2810
  // Read the file
2500
2811
  const fileContent = await fs_1.promises.readFile(args.file_path, 'utf8');
2501
- const artifact = JSON.parse(fileContent);
2812
+ let artifact;
2813
+ // Parse file based on format
2814
+ if (args.format === 'xml' || args.file_path.endsWith('.xml')) {
2815
+ // Handle XML format (Update Set format)
2816
+ return await this.importFromUpdateSetXML(fileContent, args.type);
2817
+ }
2818
+ else {
2819
+ // Handle JSON format
2820
+ artifact = JSON.parse(fileContent);
2821
+ }
2822
+ // Determine table name based on artifact type
2823
+ let tableName;
2824
+ switch (args.type) {
2825
+ case 'widget':
2826
+ tableName = 'sp_widget';
2827
+ break;
2828
+ case 'workflow':
2829
+ tableName = 'wf_workflow';
2830
+ break;
2831
+ case 'application':
2832
+ tableName = 'sys_app';
2833
+ break;
2834
+ case 'script':
2835
+ tableName = 'sys_script_include';
2836
+ break;
2837
+ case 'business_rule':
2838
+ tableName = 'sys_script';
2839
+ break;
2840
+ case 'table':
2841
+ tableName = 'sys_db_object';
2842
+ break;
2843
+ default:
2844
+ throw new Error(`Unsupported artifact type: ${args.type}`);
2845
+ }
2846
+ // Check if artifact already exists
2847
+ let existingArtifact = null;
2848
+ if (artifact.sys_id) {
2849
+ try {
2850
+ const existingResponse = await this.client.get(`/api/now/table/${tableName}/${artifact.sys_id}`);
2851
+ existingArtifact = existingResponse?.result;
2852
+ }
2853
+ catch (error) {
2854
+ // Artifact doesn't exist, which is fine for import
2855
+ }
2856
+ }
2857
+ let result;
2858
+ let action;
2859
+ if (existingArtifact) {
2860
+ // Update existing artifact
2861
+ const { sys_id, ...updateData } = artifact;
2862
+ result = await this.client.update(`${tableName}/${sys_id}`, updateData);
2863
+ action = 'updated';
2864
+ }
2865
+ else {
2866
+ // Create new artifact
2867
+ result = await this.client.create(tableName, artifact);
2868
+ action = 'created';
2869
+ }
2870
+ if (!result?.result) {
2871
+ throw new Error('Import operation failed - no result returned from ServiceNow');
2872
+ }
2873
+ const importedArtifact = result.result;
2874
+ // Log successful import
2875
+ this.logger.info('Artifact import completed', {
2876
+ type: args.type,
2877
+ sys_id: importedArtifact.sys_id,
2878
+ action: action,
2879
+ name: importedArtifact.name || importedArtifact.title
2880
+ });
2502
2881
  return {
2503
2882
  content: [
2504
2883
  {
2505
2884
  type: 'text',
2506
- text: `📥 Artifact imported successfully!
2885
+ text: `📥 Artifact ${action} successfully in ServiceNow!
2507
2886
 
2508
2887
  📋 Import Details:
2509
2888
  - Type: ${args.type}
2510
- - Source: ${args.file_path}
2511
- - Name: ${artifact.name || 'Unknown'}
2889
+ - Name: ${importedArtifact.name || importedArtifact.title || 'Unknown'}
2890
+ - Sys ID: ${importedArtifact.sys_id}
2891
+ - Source File: ${args.file_path}
2892
+ - Table: ${tableName}
2893
+ - Action: ${action.toUpperCase()}
2894
+ - Created: ${importedArtifact.sys_created_on || 'Now'}
2895
+ - Updated: ${importedArtifact.sys_updated_on || 'Now'}
2896
+
2897
+ ✅ Import completed! The artifact is now available in ServiceNow.
2898
+
2899
+ 🔗 **View in ServiceNow:**
2900
+ ${this.getServiceNowURL(tableName, importedArtifact.sys_id)}
2512
2901
 
2513
- Import completed! Check ServiceNow for the new artifact.`,
2902
+ 💡 **Next Steps:**
2903
+ - Test the imported artifact functionality
2904
+ - Update any dependencies or references
2905
+ - Deploy to other environments if needed`,
2514
2906
  },
2515
2907
  ],
2516
2908
  };
2517
2909
  }
2518
2910
  catch (error) {
2519
- throw new Error(`Import failed: ${error instanceof Error ? error.message : String(error)}`);
2911
+ this.logger.error('Import failed', error);
2912
+ return {
2913
+ content: [
2914
+ {
2915
+ type: 'text',
2916
+ text: `❌ Import failed
2917
+
2918
+ 📝 **Error:** ${error instanceof Error ? error.message : String(error)}
2919
+
2920
+ 🛠️ **Troubleshooting:**
2921
+ 1. Verify the file exists and is readable: ${args.file_path}
2922
+ 2. Check file format is valid JSON or XML
2923
+ 3. Ensure artifact type matches file content: ${args.type}
2924
+ 4. Verify you have write permissions to ServiceNow
2925
+ 5. Check that required fields are present in the artifact
2926
+
2927
+ 💡 **File Format Requirements:**
2928
+ - JSON: Must contain valid ServiceNow record data
2929
+ - XML: Must be in ServiceNow Update Set XML format
2930
+ - Required fields vary by artifact type
2931
+
2932
+ 🔍 **Manual Import:** You can manually import via ServiceNow:
2933
+ - System Update Sets > Retrieved Update Sets (for XML files)
2934
+ - System Definition > Tables (for direct record import)
2935
+ - Service Portal > Widget Editor (for widget JSON)`,
2936
+ },
2937
+ ],
2938
+ };
2520
2939
  }
2521
2940
  }
2941
+ async importFromUpdateSetXML(xmlContent, expectedType) {
2942
+ // This would require XML parsing - for now, provide instructions for manual import
2943
+ return {
2944
+ content: [
2945
+ {
2946
+ type: 'text',
2947
+ text: `📦 XML Update Set Import
2948
+
2949
+ The file appears to be in ServiceNow Update Set XML format.
2950
+
2951
+ ⚠️ **Automated XML Import Not Available**
2952
+ XML Update Set imports require ServiceNow's built-in import mechanism for safety and dependency resolution.
2953
+
2954
+ 🛠️ **Manual Import Steps:**
2955
+ 1. Log into ServiceNow
2956
+ 2. Navigate to: System Update Sets > Retrieved Update Sets
2957
+ 3. Click "Import Update Set from XML"
2958
+ 4. Upload your XML file
2959
+ 5. Follow the ServiceNow import wizard
2960
+ 6. Preview and commit the update set
2961
+
2962
+ 💡 **Why Manual?**
2963
+ - ServiceNow XML imports handle complex dependencies
2964
+ - Built-in validation prevents system corruption
2965
+ - Proper conflict resolution and rollback capabilities
2966
+
2967
+ 🔗 **ServiceNow Documentation:**
2968
+ Search "Import Update Set from XML" in ServiceNow docs`,
2969
+ },
2970
+ ],
2971
+ };
2972
+ }
2973
+ getServiceNowURL(tableName, sysId) {
2974
+ // This would need the actual ServiceNow instance URL
2975
+ // For now, provide generic path
2976
+ return `Navigate to: ServiceNow > ${tableName}.do?sys_id=${sysId}`;
2977
+ }
2522
2978
  async cloneInstanceArtifact(args) {
2523
2979
  try {
2524
2980
  this.logger.info('Cloning artifact between instances', {
2525
2981
  source: args.source_instance,
2526
2982
  target: args.target_instance,
2527
2983
  type: args.type,
2984
+ sys_id: args.sys_id
2528
2985
  });
2986
+ // Determine table name based on artifact type
2987
+ let tableName;
2988
+ switch (args.type) {
2989
+ case 'widget':
2990
+ tableName = 'sp_widget';
2991
+ break;
2992
+ case 'workflow':
2993
+ tableName = 'wf_workflow';
2994
+ break;
2995
+ case 'application':
2996
+ tableName = 'sys_app';
2997
+ break;
2998
+ case 'script':
2999
+ tableName = 'sys_script_include';
3000
+ break;
3001
+ case 'business_rule':
3002
+ tableName = 'sys_script';
3003
+ break;
3004
+ case 'table':
3005
+ tableName = 'sys_db_object';
3006
+ break;
3007
+ default:
3008
+ throw new Error(`Unsupported artifact type: ${args.type}`);
3009
+ }
3010
+ // Create ServiceNow clients for source and target instances
3011
+ const sourceClient = new servicenow_client_js_1.ServiceNowClient();
3012
+ const targetClient = new servicenow_client_js_1.ServiceNowClient();
3013
+ // Note: This would require separate OAuth configs for different instances
3014
+ // For now, we'll provide instructions for manual cloning
3015
+ // Step 1: Fetch artifact from source instance
3016
+ let sourceArtifact;
3017
+ try {
3018
+ // This would need to be configured for the source instance
3019
+ const sourceResponse = await this.client.get(`/api/now/table/${tableName}/${args.sys_id}`);
3020
+ if (!sourceResponse?.result) {
3021
+ throw new Error(`Artifact not found in source instance: ${args.sys_id}`);
3022
+ }
3023
+ sourceArtifact = sourceResponse.result;
3024
+ }
3025
+ catch (sourceError) {
3026
+ return {
3027
+ content: [
3028
+ {
3029
+ type: 'text',
3030
+ text: `❌ Failed to fetch artifact from source instance
3031
+
3032
+ 📝 **Error:** ${sourceError instanceof Error ? sourceError.message : String(sourceError)}
3033
+
3034
+ 🛠️ **Manual Clone Process:**
3035
+
3036
+ **Step 1: Export from Source**
3037
+ 1. Log into source instance: ${args.source_instance}
3038
+ 2. Navigate to the ${tableName} table
3039
+ 3. Find record: ${args.sys_id}
3040
+ 4. Export the record (JSON or Update Set XML)
3041
+
3042
+ **Step 2: Import to Target**
3043
+ 1. Log into target instance: ${args.target_instance}
3044
+ 2. Use snow_import_artifact tool with the exported file
3045
+ 3. Or manually import via ServiceNow UI
3046
+
3047
+ 💡 **Why Manual?**
3048
+ Cross-instance cloning requires separate authentication for each instance, which is complex to configure automatically.
3049
+
3050
+ 🔧 **Alternative:** Use ServiceNow's built-in Update Set promotion process for production deployments.`,
3051
+ },
3052
+ ],
3053
+ };
3054
+ }
3055
+ // For actual cross-instance cloning, we'd need:
3056
+ // 1. Separate OAuth configurations for each instance
3057
+ // 2. Network connectivity between instances
3058
+ // 3. Proper field mapping for different instance versions
3059
+ // 4. Dependency resolution for related records
2529
3060
  return {
2530
3061
  content: [
2531
3062
  {
2532
3063
  type: 'text',
2533
- text: `🔄 Artifact cloned successfully!
3064
+ text: `🔄 Cross-Instance Clone Initiated
2534
3065
 
2535
- 📋 Clone Details:
3066
+ 📋 Source Artifact Found:
2536
3067
  - Type: ${args.type}
3068
+ - Name: ${sourceArtifact.name || sourceArtifact.title || 'Unknown'}
3069
+ - Sys ID: ${args.sys_id}
2537
3070
  - Source: ${args.source_instance}
2538
3071
  - Target: ${args.target_instance}
2539
- - Sys ID: ${args.sys_id}
3072
+ - Table: ${tableName}
3073
+
3074
+ ⚠️ **Manual Completion Required**
3075
+
3076
+ Due to security and complexity considerations, cross-instance cloning requires manual completion:
3077
+
3078
+ **Step 1: ✅ Source Verified**
3079
+ Artifact found and accessible in source instance.
3080
+
3081
+ **Step 2: 📋 Export Recommended**
3082
+ Use snow_export_artifact to create a portable export:
3083
+ \`\`\`
3084
+ snow_export_artifact({
3085
+ type: "${args.type}",
3086
+ sys_id: "${args.sys_id}",
3087
+ format: "json"
3088
+ })
3089
+ \`\`\`
3090
+
3091
+ **Step 3: 📥 Import to Target**
3092
+ 1. Transfer the exported file to target instance environment
3093
+ 2. Use snow_import_artifact to import the artifact
3094
+ 3. Test functionality in target instance
3095
+
3096
+ **Step 4: 🔍 Validation**
3097
+ - Verify all dependencies are satisfied
3098
+ - Test artifact functionality
3099
+ - Update any instance-specific configurations
3100
+
3101
+ 💡 **Alternative Methods:**
3102
+ - ServiceNow Update Sets (recommended for production)
3103
+ - ServiceNow Studio (for scoped applications)
3104
+ - ServiceNow Store (for certified applications)
2540
3105
 
2541
- Clone operation completed!`,
3106
+ 🛡️ **Security Note:** Cross-instance operations require careful authentication management and are best done through ServiceNow's official channels.`,
2542
3107
  },
2543
3108
  ],
2544
3109
  };
2545
3110
  }
2546
3111
  catch (error) {
2547
- throw new Error(`Clone operation failed: ${error instanceof Error ? error.message : String(error)}`);
3112
+ this.logger.error('Clone operation failed', error);
3113
+ return {
3114
+ content: [
3115
+ {
3116
+ type: 'text',
3117
+ text: `❌ Clone operation failed
3118
+
3119
+ 📝 **Error:** ${error instanceof Error ? error.message : String(error)}
3120
+
3121
+ 🛠️ **Troubleshooting:**
3122
+ 1. Verify both source and target instances are accessible
3123
+ 2. Check that sys_id exists: ${args.sys_id}
3124
+ 3. Ensure artifact type is correct: ${args.type}
3125
+ 4. Verify authentication for both instances
3126
+
3127
+ 💡 **Manual Alternative:**
3128
+ 1. Export from source: Use snow_export_artifact tool
3129
+ 2. Transfer file between environments
3130
+ 3. Import to target: Use snow_import_artifact tool
3131
+
3132
+ 🔧 **Production Recommendation:**
3133
+ Use ServiceNow's official deployment process:
3134
+ - Update Sets for customizations
3135
+ - Studio for scoped applications
3136
+ - Store for certified applications`,
3137
+ },
3138
+ ],
3139
+ };
2548
3140
  }
2549
3141
  }
2550
3142
  /**
@@ -2636,15 +3228,132 @@ ${inconsistencies.map(inc => `- ${inc.issue}`).join('\n')}
2636
3228
  */
2637
3229
  async getDeploymentDebug(args) {
2638
3230
  try {
3231
+ this.logger.info('Gathering deployment debug information');
3232
+ // Get local session summary
2639
3233
  const sessionSummary = artifact_tracker_js_1.artifactTracker.getSessionSummary();
2640
3234
  const inconsistencies = artifact_tracker_js_1.artifactTracker.findInconsistencies();
3235
+ // Get real ServiceNow system information
3236
+ let serviceNowInfo = {};
3237
+ let authStatus = '❌ Not connected';
3238
+ let systemInfo = 'Unable to retrieve';
3239
+ let updateSetInfo = 'Unable to retrieve';
3240
+ let recentErrors = [];
3241
+ try {
3242
+ // Test ServiceNow connection and get system info
3243
+ const systemInfoResponse = await this.client.get('/api/now/table/sys_properties', {
3244
+ sysparm_query: 'name=glide.servlet.uri^ORname=instance.name^ORname=glide.db.rdbms^ORname=glide.war.production',
3245
+ sysparm_fields: 'name,value'
3246
+ });
3247
+ if (systemInfoResponse?.result) {
3248
+ authStatus = '✅ Connected and authenticated';
3249
+ const properties = systemInfoResponse.result;
3250
+ const propMap = properties.reduce((acc, prop) => {
3251
+ acc[prop.name] = prop.value;
3252
+ return acc;
3253
+ }, {});
3254
+ systemInfo = `- Instance: ${propMap['instance.name'] || 'Unknown'}
3255
+ - URI: ${propMap['glide.servlet.uri'] || 'Unknown'}
3256
+ - Database: ${propMap['glide.db.rdbms'] || 'Unknown'}
3257
+ - Production: ${propMap['glide.war.production'] || 'Unknown'}`;
3258
+ }
3259
+ // Get current user info for permissions
3260
+ const userInfo = await this.client.get('/api/now/table/sys_user', {
3261
+ sysparm_query: 'user_name=' + (process.env.SERVICENOW_USERNAME || 'current_user'),
3262
+ sysparm_limit: 1,
3263
+ sysparm_fields: 'name,user_name,active,locked_out,last_login_time'
3264
+ });
3265
+ let userStatus = 'Unable to retrieve user info';
3266
+ if (userInfo?.result?.[0]) {
3267
+ const user = userInfo.result[0];
3268
+ userStatus = `- User: ${user.name} (${user.user_name})
3269
+ - Status: ${user.active === 'true' ? '✅ Active' : '❌ Inactive'}
3270
+ - Locked: ${user.locked_out === 'true' ? '❌ Yes' : '✅ No'}
3271
+ - Last Login: ${user.last_login_time || 'Unknown'}`;
3272
+ }
3273
+ // Get current Update Set information
3274
+ const currentUpdateSet = await this.client.get('/api/now/table/sys_update_set', {
3275
+ sysparm_query: 'state=build',
3276
+ sysparm_limit: 1,
3277
+ sysparm_fields: 'name,description,state,sys_created_on,sys_updated_on'
3278
+ });
3279
+ if (currentUpdateSet?.result?.[0]) {
3280
+ const updateSet = currentUpdateSet.result[0];
3281
+ updateSetInfo = `- Active Update Set: ${updateSet.name}
3282
+ - Description: ${updateSet.description || 'None'}
3283
+ - State: ${updateSet.state}
3284
+ - Created: ${updateSet.sys_created_on}
3285
+ - Updated: ${updateSet.sys_updated_on}`;
3286
+ }
3287
+ else {
3288
+ updateSetInfo = '⚠️ No active Update Set found (deployment may fail)';
3289
+ }
3290
+ // Get recent system logs/errors (if accessible)
3291
+ try {
3292
+ const systemLogs = await this.client.get('/api/now/table/syslog', {
3293
+ sysparm_query: 'level=error^sys_created_on>=javascript:gs.hoursAgoStart(24)^ORDERBYDESCsys_created_on',
3294
+ sysparm_limit: 5,
3295
+ sysparm_fields: 'message,sys_created_on,source'
3296
+ });
3297
+ if (systemLogs?.result?.length > 0) {
3298
+ recentErrors = systemLogs.result.map((log) => ({
3299
+ message: log.message,
3300
+ time: log.sys_created_on,
3301
+ source: log.source
3302
+ }));
3303
+ }
3304
+ }
3305
+ catch (logError) {
3306
+ // System logs may not be accessible
3307
+ }
3308
+ // Test key table access for deployment operations
3309
+ const tableTests = [
3310
+ { name: 'Service Portal Widgets', table: 'sp_widget', critical: true },
3311
+ { name: 'Workflows', table: 'wf_workflow', critical: true },
3312
+ { name: 'Update Sets', table: 'sys_update_set', critical: true },
3313
+ { name: 'Applications', table: 'sys_app', critical: false },
3314
+ { name: 'Script Includes', table: 'sys_script_include', critical: false }
3315
+ ];
3316
+ const tableAccess = await Promise.allSettled(tableTests.map(async (test) => {
3317
+ try {
3318
+ await this.client.get(`/api/now/table/${test.table}`, { sysparm_limit: 1 });
3319
+ return { ...test, status: '✅ Accessible' };
3320
+ }
3321
+ catch (error) {
3322
+ return { ...test, status: '❌ Access denied', error: error instanceof Error ? error.message : String(error) };
3323
+ }
3324
+ }));
3325
+ serviceNowInfo.tableAccess = tableAccess.map(result => result.status === 'fulfilled' ? result.value : {
3326
+ name: 'Test failed',
3327
+ status: '❌ Error',
3328
+ error: result.reason
3329
+ });
3330
+ serviceNowInfo.userStatus = userStatus;
3331
+ }
3332
+ catch (connectionError) {
3333
+ authStatus = `❌ Connection failed: ${connectionError instanceof Error ? connectionError.message : String(connectionError)}`;
3334
+ }
2641
3335
  return {
2642
3336
  content: [
2643
3337
  {
2644
3338
  type: 'text',
2645
- text: `🐛 Deployment Debug Information:
3339
+ text: `🐛 Comprehensive Deployment Debug Information:
3340
+
3341
+ **🔐 ServiceNow Connection Status:**
3342
+ ${authStatus}
2646
3343
 
2647
- **Session Summary:**
3344
+ **🖥️ ServiceNow System Information:**
3345
+ ${systemInfo}
3346
+
3347
+ **👤 User Information:**
3348
+ ${serviceNowInfo.userStatus || 'Unable to retrieve user info'}
3349
+
3350
+ **📦 Update Set Status:**
3351
+ ${updateSetInfo}
3352
+
3353
+ **🔑 Table Access Permissions:**
3354
+ ${serviceNowInfo.tableAccess ? serviceNowInfo.tableAccess.map((test) => `- ${test.name}: ${test.status}${test.error ? ` (${test.error})` : ''}`).join('\n') : 'Unable to test table access'}
3355
+
3356
+ **💾 Local Session Summary:**
2648
3357
  - Session ID: ${sessionSummary.sessionId}
2649
3358
  - Tracked Artifacts: ${sessionSummary.artifactCount}
2650
3359
  - Status Breakdown:
@@ -2653,25 +3362,38 @@ ${inconsistencies.map(inc => `- ${inc.issue}`).join('\n')}
2653
3362
  - Modified: ${sessionSummary.statusCounts.modified}
2654
3363
  - Error: ${sessionSummary.statusCounts.error}
2655
3364
 
2656
- **Tracked Artifacts:**
2657
- ${sessionSummary.artifacts.map(a => `- ${a.name} (${a.type})
3365
+ **🔍 Tracked Artifacts:**
3366
+ ${sessionSummary.artifacts.length > 0 ? sessionSummary.artifacts.map(a => `- ${a.name} (${a.type})
2658
3367
  Sys ID: ${a.sys_id}
2659
3368
  Status: ${a.status}
2660
3369
  Operations: ${a.operationCount}
2661
- Last Validated: ${a.lastValidated}`).join('\n\n')}
3370
+ Last Validated: ${a.lastValidated}`).join('\n\n') : 'No artifacts currently tracked'}
2662
3371
 
2663
- **Sys_ID Inconsistencies:**
3372
+ **⚠️ Sys_ID Inconsistencies:**
2664
3373
  ${inconsistencies.length === 0 ? '✅ No inconsistencies found' :
2665
3374
  inconsistencies.map(inc => `⚠️ ${inc.issue}
2666
3375
  Conflicting artifacts:
2667
3376
  ${inc.artifacts.map(a => ` - ${a.sys_id} (${a.name})`).join('\n')}`).join('\n\n')}
2668
3377
 
2669
- **Recommendations:**
3378
+ **🚨 Recent System Errors (24h):**
3379
+ ${recentErrors.length === 0 ? '✅ No recent system errors found' :
3380
+ recentErrors.map(error => `- ${error.time}: ${error.message} (${error.source})`).join('\n')}
3381
+
3382
+ **💡 Recommendations:**
3383
+ ${authStatus.includes('❌') ? '- 🔧 Fix ServiceNow connection and authentication' : ''}
3384
+ ${updateSetInfo.includes('⚠️') ? '- 📦 Create or activate an Update Set before deployment' : ''}
3385
+ ${serviceNowInfo.tableAccess?.some((test) => test.status.includes('❌')) ? '- 🔑 Request additional table permissions for full deployment capability' : ''}
2670
3386
  ${sessionSummary.statusCounts.error > 0 ? '- ❌ Fix artifacts in error status before proceeding' : ''}
2671
3387
  ${inconsistencies.length > 0 ? '- ⚠️ Resolve sys_id inconsistencies using snow_validate_sysid' : ''}
2672
3388
  ${sessionSummary.statusCounts.pending > 0 ? '- 📋 Complete pending deployments' : ''}
3389
+ ${recentErrors.length > 0 ? '- 🚨 Review recent system errors in ServiceNow System Logs' : ''}
2673
3390
 
2674
- 💡 Use snow_validate_sysid to verify specific sys_ids before operations.`,
3391
+ 🔧 **Next Steps:**
3392
+ 1. Ensure ServiceNow connection is working
3393
+ 2. Verify Update Set is active and ready
3394
+ 3. Check table permissions for deployment operations
3395
+ 4. Resolve any tracked artifact issues
3396
+ 5. Use snow_validate_sysid to verify specific sys_ids`,
2675
3397
  },
2676
3398
  ],
2677
3399
  };
@@ -2682,7 +3404,21 @@ ${sessionSummary.statusCounts.pending > 0 ? '- 📋 Complete pending deployments
2682
3404
  content: [
2683
3405
  {
2684
3406
  type: 'text',
2685
- text: `❌ Debug error: ${error instanceof Error ? error.message : String(error)}`,
3407
+ text: `❌ Debug information retrieval failed
3408
+
3409
+ 📝 **Error:** ${error instanceof Error ? error.message : String(error)}
3410
+
3411
+ 🛠️ **Fallback Debug Info:**
3412
+ - Local session tracking may be available
3413
+ - Check ServiceNow connection manually
3414
+ - Verify authentication credentials
3415
+ - Try snow_auth_diagnostics for authentication details
3416
+
3417
+ 💡 **Manual Debug:**
3418
+ 1. Test ServiceNow login in browser
3419
+ 2. Check System Update Sets > Local Update Sets
3420
+ 3. Verify table permissions in System Security > Access Control (ACL)
3421
+ 4. Review System Logs > Events for recent errors`,
2686
3422
  },
2687
3423
  ],
2688
3424
  };
@@ -2801,14 +3537,152 @@ This will use your .env credentials to start the OAuth flow and generate access
2801
3537
  ],
2802
3538
  };
2803
3539
  }
2804
- // 🔧 ENHANCED: Try to run diagnostics with better error handling
2805
- let diagnostics;
3540
+ // 🔧 ENHANCED: Run comprehensive real ServiceNow API connectivity tests
3541
+ let diagnostics = { success: false, data: {} };
3542
+ const realApiTests = {};
2806
3543
  try {
2807
- diagnostics = await this.client.validateDeploymentPermissions();
3544
+ // Test 1: Basic System Properties API call
3545
+ try {
3546
+ const systemTest = await this.client.get('/api/now/table/sys_properties', {
3547
+ sysparm_query: 'name=glide.servlet.uri',
3548
+ sysparm_limit: 1
3549
+ });
3550
+ realApiTests.systemPropertiesAccess = {
3551
+ status: '✅ Success',
3552
+ description: 'Can read system properties',
3553
+ details: systemTest?.result ? 'System API accessible' : 'No results returned'
3554
+ };
3555
+ }
3556
+ catch (systemError) {
3557
+ realApiTests.systemPropertiesAccess = {
3558
+ status: '❌ Failed',
3559
+ description: 'Cannot access system properties',
3560
+ error: systemError instanceof Error ? systemError.message : String(systemError)
3561
+ };
3562
+ }
3563
+ // Test 2: User Table Access
3564
+ try {
3565
+ const userTest = await this.client.get('/api/now/table/sys_user', {
3566
+ sysparm_limit: 1,
3567
+ sysparm_fields: 'sys_id,user_name'
3568
+ });
3569
+ realApiTests.userTableAccess = {
3570
+ status: '✅ Success',
3571
+ description: 'Can access user table',
3572
+ details: userTest?.result?.length > 0 ? `Found ${userTest.result.length} user records` : 'No users found'
3573
+ };
3574
+ }
3575
+ catch (userError) {
3576
+ realApiTests.userTableAccess = {
3577
+ status: '❌ Failed',
3578
+ description: 'Cannot access user table',
3579
+ error: userError instanceof Error ? userError.message : String(userError)
3580
+ };
3581
+ }
3582
+ // Test 3: Update Set Table Access (critical for deployments)
3583
+ try {
3584
+ const updateSetTest = await this.client.get('/api/now/table/sys_update_set', {
3585
+ sysparm_limit: 1,
3586
+ sysparm_fields: 'name,state'
3587
+ });
3588
+ realApiTests.updateSetAccess = {
3589
+ status: '✅ Success',
3590
+ description: 'Can access Update Sets (deployment ready)',
3591
+ details: updateSetTest?.result?.length > 0 ? `Found ${updateSetTest.result.length} update sets` : 'No update sets found'
3592
+ };
3593
+ }
3594
+ catch (updateSetError) {
3595
+ realApiTests.updateSetAccess = {
3596
+ status: '❌ Critical',
3597
+ description: 'Cannot access Update Sets - deployments will fail!',
3598
+ error: updateSetError instanceof Error ? updateSetError.message : String(updateSetError)
3599
+ };
3600
+ }
3601
+ // Test 4: Service Portal Widget Access (for widget deployments)
3602
+ try {
3603
+ const widgetTest = await this.client.get('/api/now/table/sp_widget', {
3604
+ sysparm_limit: 1,
3605
+ sysparm_fields: 'name,title'
3606
+ });
3607
+ realApiTests.widgetTableAccess = {
3608
+ status: '✅ Success',
3609
+ description: 'Can access Service Portal widgets',
3610
+ details: widgetTest?.result?.length > 0 ? `Found ${widgetTest.result.length} widgets` : 'No widgets found'
3611
+ };
3612
+ }
3613
+ catch (widgetError) {
3614
+ realApiTests.widgetTableAccess = {
3615
+ status: '⚠️ Limited',
3616
+ description: 'Cannot access Service Portal - widget deployments may fail',
3617
+ error: widgetError instanceof Error ? widgetError.message : String(widgetError)
3618
+ };
3619
+ }
3620
+ // Test 5: Write Permissions Test (create a test record)
3621
+ if (args.run_write_test !== false) {
3622
+ try {
3623
+ // Try to create a test widget to verify write permissions
3624
+ const testWidget = {
3625
+ name: 'snow_flow_connectivity_test',
3626
+ title: 'Snow-Flow Connectivity Test',
3627
+ template: '<div>Test widget - safe to delete</div>',
3628
+ description: 'Temporary test widget created by Snow-Flow MCP diagnostics'
3629
+ };
3630
+ const createResult = await this.client.create('sp_widget', testWidget);
3631
+ if (createResult?.result?.sys_id) {
3632
+ // Immediately delete the test widget
3633
+ try {
3634
+ await this.client.delete(`sp_widget/${createResult.result.sys_id}`);
3635
+ realApiTests.writePermissions = {
3636
+ status: '✅ Full Access',
3637
+ description: 'Can create and delete artifacts - full deployment capability',
3638
+ details: `Successfully created and cleaned up test widget ${createResult.result.sys_id}`
3639
+ };
3640
+ }
3641
+ catch (deleteError) {
3642
+ realApiTests.writePermissions = {
3643
+ status: '⚠️ Partial',
3644
+ description: 'Can create but cannot delete - cleanup may be needed',
3645
+ details: `Created test widget ${createResult.result.sys_id} but failed to delete: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`
3646
+ };
3647
+ }
3648
+ }
3649
+ }
3650
+ catch (writeError) {
3651
+ realApiTests.writePermissions = {
3652
+ status: '❌ Read-Only',
3653
+ description: 'Cannot create artifacts - deployments will fail',
3654
+ error: writeError instanceof Error ? writeError.message : String(writeError)
3655
+ };
3656
+ }
3657
+ }
3658
+ // Determine overall success
3659
+ const successCount = Object.values(realApiTests).filter((test) => test.status.includes('✅')).length;
3660
+ const totalTests = Object.keys(realApiTests).length;
3661
+ diagnostics.success = successCount >= Math.ceil(totalTests * 0.6); // 60% success rate
3662
+ diagnostics.data = {
3663
+ tests: realApiTests,
3664
+ summary: {
3665
+ successCount,
3666
+ totalTests,
3667
+ successRate: Math.round((successCount / totalTests) * 100)
3668
+ },
3669
+ recommendations: [],
3670
+ timestamp: new Date().toISOString(),
3671
+ instance_url: credentials?.instance
3672
+ };
3673
+ // Add specific recommendations based on test results
3674
+ if (realApiTests.updateSetAccess?.status?.includes('❌')) {
3675
+ diagnostics.data.recommendations.push('Critical: Fix Update Set access for deployment capability');
3676
+ }
3677
+ if (realApiTests.writePermissions?.status?.includes('❌')) {
3678
+ diagnostics.data.recommendations.push('Request write permissions for artifact creation');
3679
+ }
3680
+ if (realApiTests.systemPropertiesAccess?.status?.includes('❌')) {
3681
+ diagnostics.data.recommendations.push('Basic API access failed - check authentication and network');
3682
+ }
2808
3683
  }
2809
- catch (apiError) {
2810
- this.logger.error('Failed to run deployment permission validation:', apiError);
2811
- // Return specific error for API failures even with valid credentials
3684
+ catch (comprehensiveError) {
3685
+ this.logger.error('Comprehensive API diagnostics failed:', comprehensiveError);
2812
3686
  return {
2813
3687
  content: [
2814
3688
  {
@@ -2816,15 +3690,15 @@ This will use your .env credentials to start the OAuth flow and generate access
2816
3690
  text: `⚠️ **Authentication Status:** ${authStatus}
2817
3691
  **📍 Credential Source:** ${credentialSource}
2818
3692
 
2819
- **❌ Diagnostic API Call Failed**
3693
+ **❌ ServiceNow API Connectivity Failed**
2820
3694
 
2821
3695
  **Credential Details:**
2822
3696
  - Instance: ${credentials?.instance || 'Unknown'} ${credentials?.instance ? '✅' : '❌'}
2823
3697
  - Client ID: ${credentials?.clientId ? '✅ Present' : '❌ Missing'}
2824
3698
  - Access Token: ${credentials?.accessToken ? '✅ Present' : '❌ Missing'}
2825
3699
 
2826
- **Error Details:**
2827
- ${apiError instanceof Error ? apiError.message : String(apiError)}
3700
+ **API Connectivity Error:**
3701
+ ${comprehensiveError instanceof Error ? comprehensiveError.message : String(comprehensiveError)}
2828
3702
 
2829
3703
  **Possible Causes:**
2830
3704
  1. **ServiceNow instance is down or unreachable**
@@ -2832,18 +3706,25 @@ ${apiError instanceof Error ? apiError.message : String(apiError)}
2832
3706
  3. **Network/firewall issues** blocking API calls
2833
3707
  4. **Invalid instance URL** in credentials
2834
3708
  5. **Insufficient API permissions** for your OAuth application
3709
+ 6. **Instance URL format issues** (check for trailing slashes)
2835
3710
 
2836
3711
  **🔧 Troubleshooting Steps:**
2837
3712
  1. Verify instance URL: https://${credentials?.instance || 'your-instance'}/
2838
- 2. Check if you can access ServiceNow web interface
3713
+ 2. Check ServiceNow web interface accessibility
2839
3714
  3. Re-authenticate: \`snow-flow auth login\`
2840
- 4. Test with simple API call
2841
- 5. Check OAuth application permissions in ServiceNow
3715
+ 4. Test OAuth application permissions in ServiceNow
3716
+ 5. Verify network connectivity and firewall settings
2842
3717
 
2843
3718
  **💡 Alternative Approaches:**
2844
3719
  - Test deployment with: \`snow_validate_deployment\`
2845
3720
  - Check Update Set status: \`snow_update_set_current\`
2846
- - Try manual deployment in ServiceNow web interface`,
3721
+ - Try manual deployment in ServiceNow web interface
3722
+
3723
+ **🔧 OAuth Setup Check:**
3724
+ Ensure your OAuth application in ServiceNow has these permissions:
3725
+ - useraccount (basic user info)
3726
+ - write (create/update records)
3727
+ - admin (system access if needed)`,
2847
3728
  },
2848
3729
  ],
2849
3730
  };