snow-flow 4.5.51 → 4.5.52
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.
|
@@ -27,6 +27,30 @@ class ServiceNowFlowWorkspaceMobileMCP {
|
|
|
27
27
|
this.logger = new mcp_logger_js_1.MCPLogger('ServiceNowFlowWorkspaceMobileMCP');
|
|
28
28
|
this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
|
|
29
29
|
this.setupHandlers();
|
|
30
|
+
this.setupSimpleStability();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Simple stability setup - no complex wrappers
|
|
34
|
+
*/
|
|
35
|
+
setupSimpleStability() {
|
|
36
|
+
// Graceful shutdown on process signals
|
|
37
|
+
process.on('SIGTERM', () => {
|
|
38
|
+
this.logger.info('🛑 Received SIGTERM - shutting down MCP server gracefully');
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
process.on('SIGINT', () => {
|
|
42
|
+
this.logger.info('🛑 Received SIGINT - shutting down MCP server gracefully');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
// Handle uncaught errors (prevents crashes)
|
|
46
|
+
process.on('uncaughtException', (error) => {
|
|
47
|
+
this.logger.error('💥 Uncaught exception in MCP server:', error);
|
|
48
|
+
// Don't exit - just log and continue
|
|
49
|
+
});
|
|
50
|
+
process.on('unhandledRejection', (reason) => {
|
|
51
|
+
this.logger.error('💥 Unhandled promise rejection in MCP server:', reason);
|
|
52
|
+
// Don't exit - just log and continue
|
|
53
|
+
});
|
|
30
54
|
}
|
|
31
55
|
setupHandlers() {
|
|
32
56
|
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
@@ -263,35 +287,6 @@ class ServiceNowFlowWorkspaceMobileMCP {
|
|
|
263
287
|
required: ['workspace_sys_id', 'workspace_type']
|
|
264
288
|
}
|
|
265
289
|
},
|
|
266
|
-
// COMPREHENSIVE TOOL HEALTH CHECKING
|
|
267
|
-
{
|
|
268
|
-
name: 'snow_test_all_workspace_tools',
|
|
269
|
-
description: 'Test all workspace and UI Builder tools to check availability, permissions, and functionality. Provides comprehensive status report with detailed feedback.',
|
|
270
|
-
inputSchema: {
|
|
271
|
-
type: 'object',
|
|
272
|
-
properties: {
|
|
273
|
-
include_ui_builder: { type: 'boolean', default: true, description: 'Test UI Builder tools' },
|
|
274
|
-
include_workspace: { type: 'boolean', default: true, description: 'Test workspace creation tools' },
|
|
275
|
-
include_mobile: { type: 'boolean', default: true, description: 'Test mobile tools' },
|
|
276
|
-
include_flow: { type: 'boolean', default: true, description: 'Test flow tools' },
|
|
277
|
-
detailed_errors: { type: 'boolean', default: true, description: 'Include detailed error information' }
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
name: 'snow_check_plugin_availability',
|
|
283
|
-
description: 'Check availability and licensing status of all ServiceNow plugins required for workspace and UI Builder functionality.',
|
|
284
|
-
inputSchema: {
|
|
285
|
-
type: 'object',
|
|
286
|
-
properties: {
|
|
287
|
-
check_ui_builder: { type: 'boolean', default: true, description: 'Check UI Builder plugin' },
|
|
288
|
-
check_uxf: { type: 'boolean', default: true, description: 'Check Now Experience Framework' },
|
|
289
|
-
check_agent_workspace: { type: 'boolean', default: true, description: 'Check Agent Workspace plugin' },
|
|
290
|
-
check_mobile: { type: 'boolean', default: true, description: 'Check Mobile Publishing' },
|
|
291
|
-
include_recommendations: { type: 'boolean', default: true, description: 'Include setup recommendations' }
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
290
|
// Mobile Tools
|
|
296
291
|
{
|
|
297
292
|
name: 'snow_configure_mobile_app',
|
|
@@ -851,12 +846,6 @@ class ServiceNowFlowWorkspaceMobileMCP {
|
|
|
851
846
|
case 'snow_validate_workspace_configuration':
|
|
852
847
|
result = await this.validateWorkspaceConfiguration(args);
|
|
853
848
|
break;
|
|
854
|
-
case 'snow_test_all_workspace_tools':
|
|
855
|
-
result = await this.testAllWorkspaceTools(args);
|
|
856
|
-
break;
|
|
857
|
-
case 'snow_check_plugin_availability':
|
|
858
|
-
result = await this.checkPluginAvailability(args);
|
|
859
|
-
break;
|
|
860
849
|
// Mobile
|
|
861
850
|
case 'snow_configure_mobile_app':
|
|
862
851
|
result = await this.configureMobileApp(args);
|
|
@@ -1412,59 +1401,20 @@ ${executionList}
|
|
|
1412
1401
|
}
|
|
1413
1402
|
throw new Error(`Failed to configure mobile app: ${response.error}`);
|
|
1414
1403
|
}
|
|
1415
|
-
// VERIFICATION: Confirm mobile app was configured (fix sys_id access)
|
|
1416
|
-
const sys_id = response.data?.result?.sys_id || response.data?.sys_id;
|
|
1417
|
-
if (!sys_id) {
|
|
1418
|
-
return {
|
|
1419
|
-
success: false,
|
|
1420
|
-
error: 'Mobile app configuration succeeded but no sys_id returned in response',
|
|
1421
|
-
debug_info: {
|
|
1422
|
-
has_data: !!response.data,
|
|
1423
|
-
has_result: !!(response.data && response.data.result),
|
|
1424
|
-
response_structure: typeof response.data
|
|
1425
|
-
},
|
|
1426
|
-
suggestion: 'ServiceNow API response format may be different than expected'
|
|
1427
|
-
};
|
|
1428
|
-
}
|
|
1429
|
-
// Note: Mobile app config table name may vary - try common variations
|
|
1430
|
-
let verification = await this.client.getRecord('sys_mobile_app_config', sys_id);
|
|
1431
|
-
if (!verification.success) {
|
|
1432
|
-
verification = await this.client.getRecord('sys_mobile_application', sys_id);
|
|
1433
|
-
}
|
|
1434
|
-
if (!verification.success) {
|
|
1435
|
-
verification = await this.client.getRecord('sys_push_app', sys_id);
|
|
1436
|
-
}
|
|
1437
|
-
if (!verification.success) {
|
|
1438
|
-
return {
|
|
1439
|
-
success: false,
|
|
1440
|
-
error: 'Mobile app configuration reported success but record not found in sys_mobile_application_config table',
|
|
1441
|
-
suggestion: 'Mobile app configuration may have been rolled back due to validation errors',
|
|
1442
|
-
verification_failed: true
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
this.logger.info(`✅ Mobile app configured and verified: ${sys_id}`);
|
|
1446
1404
|
return {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
app_name: args.app_name,
|
|
1461
|
-
authentication_method: args.authentication || 'oauth',
|
|
1462
|
-
enabled_modules: args.enabled_modules || [],
|
|
1463
|
-
offline_tables: args.offline_tables || [],
|
|
1464
|
-
push_notifications: args.push_enabled !== false,
|
|
1465
|
-
verified_in_table: 'sys_mobile_application_config',
|
|
1466
|
-
verification_timestamp: new Date().toISOString()
|
|
1467
|
-
}
|
|
1405
|
+
content: [{
|
|
1406
|
+
type: 'text',
|
|
1407
|
+
text: `✅ Mobile App configured!
|
|
1408
|
+
|
|
1409
|
+
📱 **${args.app_name}**
|
|
1410
|
+
🆔 sys_id: ${response.data.sys_id}
|
|
1411
|
+
🔐 Authentication: ${args.authentication || 'oauth'}
|
|
1412
|
+
📦 Modules: ${args.enabled_modules ? args.enabled_modules.length : 0}
|
|
1413
|
+
💾 Offline Tables: ${args.offline_tables ? args.offline_tables.length : 0}
|
|
1414
|
+
🔔 Push Notifications: ${args.push_enabled !== false ? 'Enabled' : 'Disabled'}
|
|
1415
|
+
|
|
1416
|
+
✨ Mobile app configuration saved!`
|
|
1417
|
+
}]
|
|
1468
1418
|
};
|
|
1469
1419
|
}
|
|
1470
1420
|
catch (error) {
|
|
@@ -1497,58 +1447,20 @@ ${executionList}
|
|
|
1497
1447
|
if (!response.success) {
|
|
1498
1448
|
throw new Error(`Failed to create mobile layout: ${response.error}`);
|
|
1499
1449
|
}
|
|
1500
|
-
// VERIFICATION: Confirm mobile layout was created (fix sys_id access)
|
|
1501
|
-
const sys_id = response.data?.result?.sys_id || response.data?.sys_id;
|
|
1502
|
-
if (!sys_id) {
|
|
1503
|
-
return {
|
|
1504
|
-
success: false,
|
|
1505
|
-
error: 'Mobile layout creation succeeded but no sys_id returned in response',
|
|
1506
|
-
debug_info: {
|
|
1507
|
-
has_data: !!response.data,
|
|
1508
|
-
has_result: !!(response.data && response.data.result),
|
|
1509
|
-
response_structure: typeof response.data
|
|
1510
|
-
},
|
|
1511
|
-
suggestion: 'ServiceNow API response format may be different than expected'
|
|
1512
|
-
};
|
|
1513
|
-
}
|
|
1514
|
-
// Note: Mobile layout table name may vary - try common variations
|
|
1515
|
-
let verification = await this.client.getRecord('sys_mobile_form_layout', sys_id);
|
|
1516
|
-
if (!verification.success) {
|
|
1517
|
-
verification = await this.client.getRecord('sys_mobile_list_layout', sys_id);
|
|
1518
|
-
}
|
|
1519
|
-
if (!verification.success) {
|
|
1520
|
-
verification = await this.client.getRecord('sys_ui_form_section', sys_id);
|
|
1521
|
-
}
|
|
1522
|
-
if (!verification.success) {
|
|
1523
|
-
return {
|
|
1524
|
-
success: false,
|
|
1525
|
-
error: 'Mobile layout creation reported success but record not found in sys_mobile_layout table',
|
|
1526
|
-
suggestion: 'Mobile layout creation may have been rolled back due to validation errors',
|
|
1527
|
-
verification_failed: true
|
|
1528
|
-
};
|
|
1529
|
-
}
|
|
1530
|
-
this.logger.info(`✅ Mobile layout created and verified: ${sys_id}`);
|
|
1531
1450
|
return {
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
name: args.name,
|
|
1546
|
-
table: args.table,
|
|
1547
|
-
type: args.type,
|
|
1548
|
-
fields: args.fields || [],
|
|
1549
|
-
verified_in_table: 'sys_mobile_layout',
|
|
1550
|
-
verification_timestamp: new Date().toISOString()
|
|
1551
|
-
}
|
|
1451
|
+
content: [{
|
|
1452
|
+
type: 'text',
|
|
1453
|
+
text: `✅ Mobile Layout created!
|
|
1454
|
+
|
|
1455
|
+
📱 **${args.name}**
|
|
1456
|
+
🆔 sys_id: ${response.data.sys_id}
|
|
1457
|
+
📋 Table: ${args.table}
|
|
1458
|
+
📊 Type: ${args.type}
|
|
1459
|
+
📝 Fields: ${args.fields ? args.fields.length : 'Default'}
|
|
1460
|
+
🔗 Related Lists: ${args.related_lists ? args.related_lists.length : 0}
|
|
1461
|
+
|
|
1462
|
+
✨ Mobile layout configured!`
|
|
1463
|
+
}]
|
|
1552
1464
|
};
|
|
1553
1465
|
}
|
|
1554
1466
|
catch (error) {
|
|
@@ -1914,30 +1826,9 @@ ${configList}${layoutsText}${offlineText}
|
|
|
1914
1826
|
const query = conditions.join('^');
|
|
1915
1827
|
const pagesResponse = await this.client.searchRecords('sys_ux_page', query, args.limit || 50);
|
|
1916
1828
|
if (!pagesResponse.success) {
|
|
1917
|
-
|
|
1918
|
-
success: false,
|
|
1919
|
-
error: `Failed to discover UI Builder pages: ${pagesResponse.error}`,
|
|
1920
|
-
suggestion: 'UI Builder plugin may not be installed. Check ServiceNow Store for UI Builder plugin.',
|
|
1921
|
-
plugin_required: 'UI Builder',
|
|
1922
|
-
table_tested: 'sys_ux_page'
|
|
1923
|
-
};
|
|
1924
|
-
}
|
|
1925
|
-
const pages = pagesResponse.data.result || [];
|
|
1926
|
-
// Handle no results case
|
|
1927
|
-
if (pages.length === 0) {
|
|
1928
|
-
return {
|
|
1929
|
-
success: true,
|
|
1930
|
-
pages: [],
|
|
1931
|
-
count: 0,
|
|
1932
|
-
message: '📝 No UI Builder pages found',
|
|
1933
|
-
explanation: 'This could mean: 1) No pages exist yet, 2) UI Builder plugin not installed, 3) Insufficient permissions to view pages',
|
|
1934
|
-
suggestions: [
|
|
1935
|
-
'Create your first UI Builder page using snow_create_uib_page',
|
|
1936
|
-
'Check if UI Builder plugin is installed and activated',
|
|
1937
|
-
'Verify you have ui_builder_user or ui_builder_admin roles'
|
|
1938
|
-
]
|
|
1939
|
-
};
|
|
1829
|
+
throw new Error(`Failed to discover UI Builder pages: ${pagesResponse.error}`);
|
|
1940
1830
|
}
|
|
1831
|
+
const pages = pagesResponse.data.result;
|
|
1941
1832
|
// Enrich with additional data if requested
|
|
1942
1833
|
for (const page of pages) {
|
|
1943
1834
|
if (args.include_routing) {
|
|
@@ -1956,29 +1847,13 @@ ${configList}${layoutsText}${offlineText}
|
|
|
1956
1847
|
this.logger.info(`✅ Found ${pages.length} UI Builder pages`);
|
|
1957
1848
|
return {
|
|
1958
1849
|
success: true,
|
|
1959
|
-
verified: true,
|
|
1960
1850
|
pages: pages,
|
|
1961
|
-
count: pages.length
|
|
1962
|
-
query_used: query || 'No filter',
|
|
1963
|
-
message: `✅ Successfully discovered ${pages.length} UI Builder pages`,
|
|
1964
|
-
detailed_confirmation: {
|
|
1965
|
-
operation: 'DISCOVER UI Builder Pages',
|
|
1966
|
-
table_searched: 'sys_ux_page',
|
|
1967
|
-
results_count: pages.length,
|
|
1968
|
-
query_conditions: conditions.join(', ') || 'No conditions',
|
|
1969
|
-
search_timestamp: new Date().toISOString()
|
|
1970
|
-
}
|
|
1851
|
+
count: pages.length
|
|
1971
1852
|
};
|
|
1972
1853
|
}
|
|
1973
1854
|
catch (error) {
|
|
1974
1855
|
this.logger.error('Failed to discover UI Builder pages:', error);
|
|
1975
|
-
|
|
1976
|
-
success: false,
|
|
1977
|
-
error: `Failed to discover UI Builder pages: ${error}`,
|
|
1978
|
-
suggestion: 'UI Builder plugin may not be installed or you may lack permissions',
|
|
1979
|
-
table_tested: 'sys_ux_page',
|
|
1980
|
-
operation_attempted: 'DISCOVER UI Builder Pages'
|
|
1981
|
-
};
|
|
1856
|
+
throw error;
|
|
1982
1857
|
}
|
|
1983
1858
|
}
|
|
1984
1859
|
/**
|
|
@@ -2019,34 +1894,12 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2019
1894
|
await this.client.deleteRecord('sys_ux_lib_source_script', sourceResponse.data.sys_id);
|
|
2020
1895
|
throw new Error(`Failed to create component: ${componentResponse.error}`);
|
|
2021
1896
|
}
|
|
2022
|
-
|
|
2023
|
-
const componentVerification = await this.client.getRecord('sys_ux_lib_component', componentResponse.data.result.sys_id);
|
|
2024
|
-
const sourceVerification = await this.client.getRecord('sys_ux_lib_source_script', sourceResponse.data.result.sys_id);
|
|
2025
|
-
if (!componentVerification.success || !sourceVerification.success) {
|
|
2026
|
-
return {
|
|
2027
|
-
success: false,
|
|
2028
|
-
error: 'Component creation reported success but records not found in tables',
|
|
2029
|
-
suggestion: 'Component creation may have been rolled back due to validation errors',
|
|
2030
|
-
verification_failed: true
|
|
2031
|
-
};
|
|
2032
|
-
}
|
|
2033
|
-
this.logger.info(`✅ UI Builder component created and verified: ${componentResponse.data.result.sys_id}`);
|
|
1897
|
+
this.logger.info('✅ UI Builder component created successfully');
|
|
2034
1898
|
return {
|
|
2035
1899
|
success: true,
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
component_name: args.name,
|
|
2040
|
-
category: args.category || 'custom',
|
|
2041
|
-
created_at: new Date().toISOString(),
|
|
2042
|
-
message: `✅ Custom UI Builder component '${args.name}' created and verified successfully`,
|
|
2043
|
-
detailed_confirmation: {
|
|
2044
|
-
operation: 'CREATE UI Builder Component',
|
|
2045
|
-
component_sys_id: componentResponse.data.result.sys_id,
|
|
2046
|
-
source_script_sys_id: sourceResponse.data.result.sys_id,
|
|
2047
|
-
verified_in_tables: ['sys_ux_lib_component', 'sys_ux_lib_source_script'],
|
|
2048
|
-
verification_timestamp: new Date().toISOString()
|
|
2049
|
-
}
|
|
1900
|
+
component: componentResponse.data,
|
|
1901
|
+
source_script: sourceResponse.data,
|
|
1902
|
+
message: `Custom UI Builder component '${args.name}' created successfully`
|
|
2050
1903
|
};
|
|
2051
1904
|
}
|
|
2052
1905
|
catch (error) {
|
|
@@ -2125,31 +1978,9 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2125
1978
|
const query = conditions.join('^');
|
|
2126
1979
|
const componentsResponse = await this.client.searchRecords('sys_ux_lib_component', query, args.limit || 100);
|
|
2127
1980
|
if (!componentsResponse.success) {
|
|
2128
|
-
|
|
2129
|
-
success: false,
|
|
2130
|
-
error: `Failed to discover UI Builder components: ${componentsResponse.error}`,
|
|
2131
|
-
suggestion: 'UI Builder plugin may not be installed. Check ServiceNow Store for UI Builder plugin.',
|
|
2132
|
-
plugin_required: 'UI Builder',
|
|
2133
|
-
table_tested: 'sys_ux_lib_component'
|
|
2134
|
-
};
|
|
2135
|
-
}
|
|
2136
|
-
const components = componentsResponse.data.result || [];
|
|
2137
|
-
// Handle no results case
|
|
2138
|
-
if (components.length === 0) {
|
|
2139
|
-
return {
|
|
2140
|
-
success: true,
|
|
2141
|
-
components: [],
|
|
2142
|
-
count: 0,
|
|
2143
|
-
message: '📝 No UI Builder components found',
|
|
2144
|
-
explanation: 'This could mean: 1) No custom components exist, 2) UI Builder plugin not installed, 3) Insufficient permissions',
|
|
2145
|
-
query_used: query || 'No filter',
|
|
2146
|
-
suggestions: [
|
|
2147
|
-
'Create your first custom component using snow_create_uib_component',
|
|
2148
|
-
'Check built-in components by removing custom_only filter',
|
|
2149
|
-
'Verify UI Builder plugin is installed and you have proper permissions'
|
|
2150
|
-
]
|
|
2151
|
-
};
|
|
1981
|
+
throw new Error(`Failed to discover components: ${componentsResponse.error}`);
|
|
2152
1982
|
}
|
|
1983
|
+
const components = componentsResponse.data.result;
|
|
2153
1984
|
// Enrich with additional data if requested
|
|
2154
1985
|
for (const component of components) {
|
|
2155
1986
|
if (args.include_source && component.source_script) {
|
|
@@ -2167,35 +1998,13 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2167
1998
|
this.logger.info(`✅ Found ${components.length} UI Builder components`);
|
|
2168
1999
|
return {
|
|
2169
2000
|
success: true,
|
|
2170
|
-
verified: true,
|
|
2171
2001
|
components: components,
|
|
2172
|
-
count: components.length
|
|
2173
|
-
query_used: query || 'No filter',
|
|
2174
|
-
categories_found: [...new Set(components.map(c => c.category))],
|
|
2175
|
-
message: `✅ Successfully discovered ${components.length} UI Builder components`,
|
|
2176
|
-
detailed_confirmation: {
|
|
2177
|
-
operation: 'DISCOVER UI Builder Components',
|
|
2178
|
-
table_searched: 'sys_ux_lib_component',
|
|
2179
|
-
results_count: components.length,
|
|
2180
|
-
query_conditions: conditions.join(', ') || 'No conditions',
|
|
2181
|
-
enrichment_options: {
|
|
2182
|
-
source_included: !!args.include_source,
|
|
2183
|
-
usage_stats_included: !!args.include_usage_stats,
|
|
2184
|
-
dependencies_included: !!args.include_dependencies
|
|
2185
|
-
},
|
|
2186
|
-
search_timestamp: new Date().toISOString()
|
|
2187
|
-
}
|
|
2002
|
+
count: components.length
|
|
2188
2003
|
};
|
|
2189
2004
|
}
|
|
2190
2005
|
catch (error) {
|
|
2191
2006
|
this.logger.error('Failed to discover UI Builder components:', error);
|
|
2192
|
-
|
|
2193
|
-
success: false,
|
|
2194
|
-
error: `Failed to discover UI Builder components: ${error}`,
|
|
2195
|
-
suggestion: 'UI Builder plugin may not be installed or you may lack permissions',
|
|
2196
|
-
table_tested: 'sys_ux_lib_component',
|
|
2197
|
-
operation_attempted: 'DISCOVER UI Builder Components'
|
|
2198
|
-
};
|
|
2007
|
+
throw error;
|
|
2199
2008
|
}
|
|
2200
2009
|
}
|
|
2201
2010
|
/**
|
|
@@ -2257,17 +2066,6 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2257
2066
|
async createUIBDataBroker(args) {
|
|
2258
2067
|
try {
|
|
2259
2068
|
this.logger.info(`🔗 Creating UI Builder data broker: ${args.name}`);
|
|
2260
|
-
// FIRST: Check if UI Builder is available
|
|
2261
|
-
const uiBuilderCheck = await this.client.searchRecords('sys_ux_data_broker', '', 1);
|
|
2262
|
-
if (!uiBuilderCheck.success) {
|
|
2263
|
-
return {
|
|
2264
|
-
success: false,
|
|
2265
|
-
error: 'UI Builder data broker table (sys_ux_data_broker) not accessible',
|
|
2266
|
-
suggestion: 'UI Builder plugin may not be installed or you may lack ui_builder_admin permissions',
|
|
2267
|
-
plugin_required: 'UI Builder',
|
|
2268
|
-
table_tested: 'sys_ux_data_broker'
|
|
2269
|
-
};
|
|
2270
|
-
}
|
|
2271
2069
|
const brokerData = {
|
|
2272
2070
|
name: args.name,
|
|
2273
2071
|
label: args.label,
|
|
@@ -2285,55 +2083,13 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2285
2083
|
};
|
|
2286
2084
|
const response = await this.client.createRecord('sys_ux_data_broker', brokerData);
|
|
2287
2085
|
if (!response.success) {
|
|
2288
|
-
|
|
2289
|
-
success: false,
|
|
2290
|
-
error: `Failed to create data broker: ${response.error || response}`,
|
|
2291
|
-
suggestion: this.getErrorSuggestion(String(response.error || response)),
|
|
2292
|
-
operation_attempted: 'CREATE sys_ux_data_broker',
|
|
2293
|
-
broker_data: brokerData
|
|
2294
|
-
};
|
|
2086
|
+
throw new Error(`Failed to create data broker: ${response.error}`);
|
|
2295
2087
|
}
|
|
2296
|
-
|
|
2297
|
-
const sys_id = response.data?.result?.sys_id || response.data?.sys_id;
|
|
2298
|
-
if (!sys_id) {
|
|
2299
|
-
return {
|
|
2300
|
-
success: false,
|
|
2301
|
-
error: 'Data broker creation succeeded but no sys_id returned in response',
|
|
2302
|
-
debug_info: {
|
|
2303
|
-
has_data: !!response.data,
|
|
2304
|
-
has_result: !!(response.data && response.data.result),
|
|
2305
|
-
response_structure: typeof response.data
|
|
2306
|
-
},
|
|
2307
|
-
suggestion: 'ServiceNow API response format may be different than expected'
|
|
2308
|
-
};
|
|
2309
|
-
}
|
|
2310
|
-
const verification = await this.client.getRecord('sys_ux_data_broker', sys_id);
|
|
2311
|
-
if (!verification.success) {
|
|
2312
|
-
return {
|
|
2313
|
-
success: false,
|
|
2314
|
-
error: 'Data broker creation reported success but record not found in sys_ux_data_broker table',
|
|
2315
|
-
suggestion: 'Data broker creation may have been rolled back due to validation errors',
|
|
2316
|
-
verification_failed: true
|
|
2317
|
-
};
|
|
2318
|
-
}
|
|
2319
|
-
this.logger.info(`✅ UI Builder data broker created and verified: ${sys_id}`);
|
|
2088
|
+
this.logger.info('✅ UI Builder data broker created successfully');
|
|
2320
2089
|
return {
|
|
2321
2090
|
success: true,
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
broker_name: args.name,
|
|
2325
|
-
broker_type: args.type || 'table',
|
|
2326
|
-
target_table: args.table || 'N/A',
|
|
2327
|
-
created_at: new Date().toISOString(),
|
|
2328
|
-
message: `✅ Data broker '${args.name}' created and verified successfully`,
|
|
2329
|
-
detailed_confirmation: {
|
|
2330
|
-
operation: 'CREATE UI Builder Data Broker',
|
|
2331
|
-
sys_id: sys_id,
|
|
2332
|
-
name: args.name,
|
|
2333
|
-
type: args.type || 'table',
|
|
2334
|
-
verified_in_table: 'sys_ux_data_broker',
|
|
2335
|
-
verification_timestamp: new Date().toISOString()
|
|
2336
|
-
}
|
|
2091
|
+
data_broker: response.data,
|
|
2092
|
+
message: `Data broker '${args.name}' created for ${args.type} type`
|
|
2337
2093
|
};
|
|
2338
2094
|
}
|
|
2339
2095
|
catch (error) {
|
|
@@ -2366,32 +2122,11 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2366
2122
|
if (!response.success) {
|
|
2367
2123
|
throw new Error(`Failed to configure data broker: ${response.error}`);
|
|
2368
2124
|
}
|
|
2369
|
-
|
|
2370
|
-
const verification = await this.client.getRecord('sys_ux_data_broker', args.broker_id);
|
|
2371
|
-
if (!verification.success) {
|
|
2372
|
-
return {
|
|
2373
|
-
success: false,
|
|
2374
|
-
error: 'Data broker configuration reported success but record not found in sys_ux_data_broker table',
|
|
2375
|
-
suggestion: 'Data broker may not exist or you may lack permissions to access it',
|
|
2376
|
-
broker_id: args.broker_id,
|
|
2377
|
-
verification_failed: true
|
|
2378
|
-
};
|
|
2379
|
-
}
|
|
2380
|
-
this.logger.info(`✅ UI Builder data broker configured and verified: ${args.broker_id}`);
|
|
2125
|
+
this.logger.info('✅ UI Builder data broker configured successfully');
|
|
2381
2126
|
return {
|
|
2382
2127
|
success: true,
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
updates_applied: Object.keys(updates),
|
|
2386
|
-
configured_at: new Date().toISOString(),
|
|
2387
|
-
message: `✅ Data broker configuration updated and verified successfully`,
|
|
2388
|
-
detailed_confirmation: {
|
|
2389
|
-
operation: 'CONFIGURE UI Builder Data Broker',
|
|
2390
|
-
sys_id: args.broker_id,
|
|
2391
|
-
updates_applied: updates,
|
|
2392
|
-
verified_in_table: 'sys_ux_data_broker',
|
|
2393
|
-
verification_timestamp: new Date().toISOString()
|
|
2394
|
-
}
|
|
2128
|
+
data_broker: response.data,
|
|
2129
|
+
message: 'Data broker configuration updated successfully'
|
|
2395
2130
|
};
|
|
2396
2131
|
}
|
|
2397
2132
|
catch (error) {
|
|
@@ -2612,48 +2347,11 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2612
2347
|
if (!response.success) {
|
|
2613
2348
|
throw new Error(`Failed to create client script: ${response.error}`);
|
|
2614
2349
|
}
|
|
2615
|
-
|
|
2616
|
-
const sys_id = response.data?.result?.sys_id || response.data?.sys_id;
|
|
2617
|
-
if (!sys_id) {
|
|
2618
|
-
return {
|
|
2619
|
-
success: false,
|
|
2620
|
-
error: 'Client script creation succeeded but no sys_id returned in response',
|
|
2621
|
-
debug_info: {
|
|
2622
|
-
has_data: !!response.data,
|
|
2623
|
-
has_result: !!(response.data && response.data.result),
|
|
2624
|
-
response_structure: typeof response.data
|
|
2625
|
-
},
|
|
2626
|
-
suggestion: 'ServiceNow API response format may be different than expected'
|
|
2627
|
-
};
|
|
2628
|
-
}
|
|
2629
|
-
const verification = await this.client.getRecord('sys_ux_client_script', sys_id);
|
|
2630
|
-
if (!verification.success) {
|
|
2631
|
-
return {
|
|
2632
|
-
success: false,
|
|
2633
|
-
error: 'Client script creation reported success but record not found in sys_ux_client_script table',
|
|
2634
|
-
suggestion: 'Client script creation may have been rolled back due to script validation errors',
|
|
2635
|
-
verification_failed: true
|
|
2636
|
-
};
|
|
2637
|
-
}
|
|
2638
|
-
this.logger.info(`✅ UI Builder client script created and verified: ${sys_id}`);
|
|
2350
|
+
this.logger.info('✅ UI Builder client script created successfully');
|
|
2639
2351
|
return {
|
|
2640
2352
|
success: true,
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
script_name: args.name,
|
|
2644
|
-
script_type: args.type,
|
|
2645
|
-
page_id: args.page_id,
|
|
2646
|
-
created_at: new Date().toISOString(),
|
|
2647
|
-
message: `✅ Client script '${args.name}' created and verified successfully`,
|
|
2648
|
-
detailed_confirmation: {
|
|
2649
|
-
operation: 'CREATE UI Builder Client Script',
|
|
2650
|
-
sys_id: sys_id,
|
|
2651
|
-
name: args.name,
|
|
2652
|
-
type: args.type,
|
|
2653
|
-
page_reference: args.page_id,
|
|
2654
|
-
verified_in_table: 'sys_ux_client_script',
|
|
2655
|
-
verification_timestamp: new Date().toISOString()
|
|
2656
|
-
}
|
|
2353
|
+
script: response.data,
|
|
2354
|
+
message: `Client script '${args.name}' created for ${args.type} trigger`
|
|
2657
2355
|
};
|
|
2658
2356
|
}
|
|
2659
2357
|
catch (error) {
|
|
@@ -2715,49 +2413,11 @@ ${configList}${layoutsText}${offlineText}
|
|
|
2715
2413
|
if (!response.success) {
|
|
2716
2414
|
throw new Error(`Failed to create event: ${response.error}`);
|
|
2717
2415
|
}
|
|
2718
|
-
|
|
2719
|
-
const sys_id = response.data?.result?.sys_id || response.data?.sys_id;
|
|
2720
|
-
if (!sys_id) {
|
|
2721
|
-
return {
|
|
2722
|
-
success: false,
|
|
2723
|
-
error: 'Event creation succeeded but no sys_id returned in response',
|
|
2724
|
-
debug_info: {
|
|
2725
|
-
has_data: !!response.data,
|
|
2726
|
-
has_result: !!(response.data && response.data.result),
|
|
2727
|
-
response_structure: typeof response.data
|
|
2728
|
-
},
|
|
2729
|
-
suggestion: 'ServiceNow API response format may be different than expected'
|
|
2730
|
-
};
|
|
2731
|
-
}
|
|
2732
|
-
const verification = await this.client.getRecord('sys_ux_event', sys_id);
|
|
2733
|
-
if (!verification.success) {
|
|
2734
|
-
return {
|
|
2735
|
-
success: false,
|
|
2736
|
-
error: 'Event creation reported success but record not found in sys_ux_event table',
|
|
2737
|
-
suggestion: 'Event creation may have been rolled back due to validation errors',
|
|
2738
|
-
verification_failed: true
|
|
2739
|
-
};
|
|
2740
|
-
}
|
|
2741
|
-
this.logger.info(`✅ UI Builder event created and verified: ${sys_id}`);
|
|
2416
|
+
this.logger.info('✅ UI Builder event created successfully');
|
|
2742
2417
|
return {
|
|
2743
2418
|
success: true,
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
event_name: args.name,
|
|
2747
|
-
event_scope: args.global_event ? 'Global' : 'Component Scoped',
|
|
2748
|
-
component_scope: args.component_scope || 'Not specified',
|
|
2749
|
-
created_at: new Date().toISOString(),
|
|
2750
|
-
message: `✅ Custom event '${args.name}' created and verified successfully`,
|
|
2751
|
-
detailed_confirmation: {
|
|
2752
|
-
operation: 'CREATE UI Builder Event',
|
|
2753
|
-
sys_id: sys_id,
|
|
2754
|
-
name: args.name,
|
|
2755
|
-
global_event: args.global_event || false,
|
|
2756
|
-
bubbles: args.bubbles !== false,
|
|
2757
|
-
cancelable: args.cancelable !== false,
|
|
2758
|
-
verified_in_table: 'sys_ux_event',
|
|
2759
|
-
verification_timestamp: new Date().toISOString()
|
|
2760
|
-
}
|
|
2419
|
+
event: response.data,
|
|
2420
|
+
message: `Custom event '${args.name}' created ${args.global_event ? '(global)' : '(scoped)'}`
|
|
2761
2421
|
};
|
|
2762
2422
|
}
|
|
2763
2423
|
catch (error) {
|
|
@@ -3037,55 +2697,18 @@ ${configList}${layoutsText}${offlineText}
|
|
|
3037
2697
|
};
|
|
3038
2698
|
}
|
|
3039
2699
|
const result = await this.client.createRecord('sys_ux_experience', experienceData);
|
|
3040
|
-
// ENHANCED FEEDBACK SYSTEM
|
|
3041
2700
|
if (result.success && result.data && result.data.result && result.data.result.sys_id) {
|
|
3042
|
-
|
|
3043
|
-
// VERIFICATION: Confirm record actually exists
|
|
3044
|
-
const verification = await this.client.getRecord('sys_ux_experience', sys_id);
|
|
3045
|
-
if (!verification.success) {
|
|
3046
|
-
return {
|
|
3047
|
-
success: false,
|
|
3048
|
-
error: `UX Experience creation reported success but record not found in sys_ux_experience table`,
|
|
3049
|
-
suggestion: 'Record creation may have failed silently or been rolled back due to permissions',
|
|
3050
|
-
reported_sys_id: sys_id,
|
|
3051
|
-
verification_failed: true
|
|
3052
|
-
};
|
|
3053
|
-
}
|
|
3054
|
-
this.logger.info(`✅ UX Experience created and verified with sys_id: ${sys_id}`);
|
|
2701
|
+
this.logger.info(`✅ UX Experience created with sys_id: ${result.data.result.sys_id}`);
|
|
3055
2702
|
return {
|
|
3056
2703
|
success: true,
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
shell_macroponent: shellSysId ? 'Linked to app shell' : 'No shell linked',
|
|
3061
|
-
created_at: new Date().toISOString(),
|
|
3062
|
-
table: 'sys_ux_experience',
|
|
3063
|
-
message: `✅ UX Experience '${args.name}' created and verified successfully`,
|
|
3064
|
-
detailed_confirmation: {
|
|
3065
|
-
operation: 'CREATE UX Experience',
|
|
3066
|
-
sys_id: sys_id,
|
|
3067
|
-
name: args.name,
|
|
3068
|
-
active: true,
|
|
3069
|
-
verified_in_table: 'sys_ux_experience',
|
|
3070
|
-
verification_timestamp: new Date().toISOString()
|
|
3071
|
-
},
|
|
3072
|
-
next_step: `Create App Configuration using experience_sys_id: ${sys_id}`
|
|
2704
|
+
experience_sys_id: result.data.result.sys_id,
|
|
2705
|
+
message: `Experience '${args.name}' created successfully`,
|
|
2706
|
+
next_step: "Create App Configuration using this experience_sys_id"
|
|
3073
2707
|
};
|
|
3074
2708
|
}
|
|
3075
2709
|
else {
|
|
3076
2710
|
const error = (result.data && result.data.error) || (result.error) || 'Unknown error creating experience';
|
|
3077
|
-
|
|
3078
|
-
success: false,
|
|
3079
|
-
error: `Failed to create UX Experience: ${error}`,
|
|
3080
|
-
suggestion: this.getErrorSuggestion(error),
|
|
3081
|
-
operation_attempted: 'CREATE sys_ux_experience',
|
|
3082
|
-
debug_info: {
|
|
3083
|
-
result_success: result.success,
|
|
3084
|
-
has_data: !!(result.data),
|
|
3085
|
-
has_result: !!(result.data && result.data.result),
|
|
3086
|
-
has_sys_id: !!(result.data && result.data.result && result.data.result.sys_id)
|
|
3087
|
-
}
|
|
3088
|
-
};
|
|
2711
|
+
throw new Error(`Failed to create experience: ${error}`);
|
|
3089
2712
|
}
|
|
3090
2713
|
}
|
|
3091
2714
|
catch (error) {
|
|
@@ -3127,43 +2750,17 @@ ${configList}${layoutsText}${offlineText}
|
|
|
3127
2750
|
};
|
|
3128
2751
|
const result = await this.client.createRecord('sys_ux_app_config', configData);
|
|
3129
2752
|
if (result.success && result.data && result.data.result && result.data.result.sys_id) {
|
|
3130
|
-
|
|
3131
|
-
// VERIFICATION: Confirm app config was created
|
|
3132
|
-
const verification = await this.client.getRecord('sys_ux_app_config', sys_id);
|
|
3133
|
-
if (!verification.success) {
|
|
3134
|
-
return {
|
|
3135
|
-
success: false,
|
|
3136
|
-
error: 'App config creation reported success but record not found in sys_ux_app_config table',
|
|
3137
|
-
verification_failed: true
|
|
3138
|
-
};
|
|
3139
|
-
}
|
|
3140
|
-
this.logger.info(`✅ UX App Config created and verified: ${sys_id}`);
|
|
2753
|
+
this.logger.info(`✅ UX App Config created with sys_id: ${result.data.result.sys_id}`);
|
|
3141
2754
|
return {
|
|
3142
2755
|
success: true,
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
linked_experience: args.experience_sys_id,
|
|
3147
|
-
created_at: new Date().toISOString(),
|
|
3148
|
-
message: `✅ App Configuration '${args.name}' created and verified successfully`,
|
|
3149
|
-
detailed_confirmation: {
|
|
3150
|
-
operation: 'CREATE UX App Config',
|
|
3151
|
-
sys_id: sys_id,
|
|
3152
|
-
name: args.name,
|
|
3153
|
-
experience_assoc: args.experience_sys_id,
|
|
3154
|
-
verified_in_table: 'sys_ux_app_config',
|
|
3155
|
-
verification_timestamp: new Date().toISOString()
|
|
3156
|
-
},
|
|
3157
|
-
next_step: `Create Page Macroponent using app_config_sys_id: ${sys_id}`
|
|
2756
|
+
app_config_sys_id: result.data.result.sys_id,
|
|
2757
|
+
message: `App Configuration '${args.name}' created successfully`,
|
|
2758
|
+
next_step: "Create Page Macroponent using this app_config_sys_id"
|
|
3158
2759
|
};
|
|
3159
2760
|
}
|
|
3160
2761
|
else {
|
|
3161
2762
|
const error = (result.data && result.data.error) || (result.error) || 'Unknown error creating app config';
|
|
3162
|
-
|
|
3163
|
-
success: false,
|
|
3164
|
-
error: `Failed to create app config: ${error}`,
|
|
3165
|
-
suggestion: this.getErrorSuggestion(error)
|
|
3166
|
-
};
|
|
2763
|
+
throw new Error(`Failed to create app config: ${error}`);
|
|
3167
2764
|
}
|
|
3168
2765
|
}
|
|
3169
2766
|
catch (error) {
|
|
@@ -3719,226 +3316,6 @@ ${configList}${layoutsText}${offlineText}
|
|
|
3719
3316
|
throw error;
|
|
3720
3317
|
}
|
|
3721
3318
|
}
|
|
3722
|
-
/**
|
|
3723
|
-
* COMPREHENSIVE TOOL HEALTH TESTING
|
|
3724
|
-
* Tests all workspace tools and provides detailed status report
|
|
3725
|
-
*/
|
|
3726
|
-
async testAllWorkspaceTools(args) {
|
|
3727
|
-
try {
|
|
3728
|
-
this.logger.info('🛠️ Starting comprehensive tool health test...');
|
|
3729
|
-
const testResults = {
|
|
3730
|
-
test_timestamp: new Date().toISOString(),
|
|
3731
|
-
tools_tested: 0,
|
|
3732
|
-
tools_working: 0,
|
|
3733
|
-
tools_failing: 0,
|
|
3734
|
-
tools_unclear: 0,
|
|
3735
|
-
detailed_results: [],
|
|
3736
|
-
plugin_status: {},
|
|
3737
|
-
recommendations: []
|
|
3738
|
-
};
|
|
3739
|
-
// Test critical plugins first
|
|
3740
|
-
const pluginTests = [
|
|
3741
|
-
{ name: 'UI Builder', table: 'sys_ux_page', description: 'UI Builder functionality' },
|
|
3742
|
-
{ name: 'Now Experience Framework', table: 'sys_ux_experience', description: 'UX Workspace creation' },
|
|
3743
|
-
{ name: 'Agent Workspace', table: 'sys_ux_app_route', description: 'Configurable Agent Workspaces' },
|
|
3744
|
-
{ name: 'Mobile Publishing', table: 'sys_push_notif_msg', description: 'Mobile app management' },
|
|
3745
|
-
{ name: 'Flow Designer', table: 'sys_hub_flow', description: 'Flow automation' }
|
|
3746
|
-
];
|
|
3747
|
-
for (const plugin of pluginTests) {
|
|
3748
|
-
const pluginTest = await this.client.searchRecords(plugin.table, '', 1);
|
|
3749
|
-
testResults.plugin_status[plugin.name] = {
|
|
3750
|
-
available: pluginTest.success,
|
|
3751
|
-
table: plugin.table,
|
|
3752
|
-
description: plugin.description,
|
|
3753
|
-
status: pluginTest.success ? '✅ Available' : '❌ Not Available'
|
|
3754
|
-
};
|
|
3755
|
-
}
|
|
3756
|
-
// Test individual tools
|
|
3757
|
-
const toolTests = [
|
|
3758
|
-
// UX Experience tools
|
|
3759
|
-
{
|
|
3760
|
-
name: 'snow_create_ux_experience',
|
|
3761
|
-
test: () => this.snow_create_ux_experience({ name: 'Health Test Experience' }),
|
|
3762
|
-
category: 'UX Experience',
|
|
3763
|
-
expects_sys_id: true
|
|
3764
|
-
},
|
|
3765
|
-
// UI Builder tools
|
|
3766
|
-
{
|
|
3767
|
-
name: 'snow_discover_uib_pages',
|
|
3768
|
-
test: () => this.discoverUIBuilderPages({}),
|
|
3769
|
-
category: 'UI Builder',
|
|
3770
|
-
expects_sys_id: false
|
|
3771
|
-
},
|
|
3772
|
-
// Mobile tools
|
|
3773
|
-
{
|
|
3774
|
-
name: 'snow_configure_mobile_app',
|
|
3775
|
-
test: () => this.configureMobileApp({ app_name: 'Health Test App' }),
|
|
3776
|
-
category: 'Mobile',
|
|
3777
|
-
expects_sys_id: true
|
|
3778
|
-
}
|
|
3779
|
-
];
|
|
3780
|
-
for (const toolTest of toolTests) {
|
|
3781
|
-
try {
|
|
3782
|
-
testResults.tools_tested++;
|
|
3783
|
-
const testStart = Date.now();
|
|
3784
|
-
const result = await toolTest.test();
|
|
3785
|
-
const testDuration = Date.now() - testStart;
|
|
3786
|
-
let status = '❌ FAILED';
|
|
3787
|
-
let feedback = 'No response';
|
|
3788
|
-
if (result && result.success === true) {
|
|
3789
|
-
if (toolTest.expects_sys_id && result.sys_id) {
|
|
3790
|
-
status = '✅ WORKING';
|
|
3791
|
-
feedback = `Created record with sys_id: ${result.sys_id}`;
|
|
3792
|
-
testResults.tools_working++;
|
|
3793
|
-
}
|
|
3794
|
-
else if (!toolTest.expects_sys_id) {
|
|
3795
|
-
status = '✅ WORKING';
|
|
3796
|
-
feedback = 'Operation completed successfully';
|
|
3797
|
-
testResults.tools_working++;
|
|
3798
|
-
}
|
|
3799
|
-
else {
|
|
3800
|
-
status = '⚠️ UNCLEAR';
|
|
3801
|
-
feedback = 'Success reported but no sys_id returned';
|
|
3802
|
-
testResults.tools_unclear++;
|
|
3803
|
-
}
|
|
3804
|
-
}
|
|
3805
|
-
else if (result && result.success === false) {
|
|
3806
|
-
status = '❌ FAILED';
|
|
3807
|
-
feedback = result.error || 'Unknown error';
|
|
3808
|
-
testResults.tools_failing++;
|
|
3809
|
-
}
|
|
3810
|
-
else {
|
|
3811
|
-
status = '⚠️ UNCLEAR';
|
|
3812
|
-
feedback = 'No clear success/failure indication';
|
|
3813
|
-
testResults.tools_unclear++;
|
|
3814
|
-
}
|
|
3815
|
-
testResults.detailed_results.push({
|
|
3816
|
-
tool: toolTest.name,
|
|
3817
|
-
category: toolTest.category,
|
|
3818
|
-
status: status,
|
|
3819
|
-
feedback: feedback,
|
|
3820
|
-
execution_time_ms: testDuration,
|
|
3821
|
-
expects_sys_id: toolTest.expects_sys_id,
|
|
3822
|
-
actual_result: result
|
|
3823
|
-
});
|
|
3824
|
-
}
|
|
3825
|
-
catch (error) {
|
|
3826
|
-
testResults.tools_tested++;
|
|
3827
|
-
testResults.tools_failing++;
|
|
3828
|
-
testResults.detailed_results.push({
|
|
3829
|
-
tool: toolTest.name,
|
|
3830
|
-
category: toolTest.category,
|
|
3831
|
-
status: '❌ FAILED',
|
|
3832
|
-
feedback: `Exception: ${error}`,
|
|
3833
|
-
execution_time_ms: 0,
|
|
3834
|
-
error_type: 'EXCEPTION'
|
|
3835
|
-
});
|
|
3836
|
-
}
|
|
3837
|
-
}
|
|
3838
|
-
// Generate recommendations
|
|
3839
|
-
if (testResults.tools_working === 0) {
|
|
3840
|
-
testResults.recommendations.push('No tools are working - check authentication and instance setup');
|
|
3841
|
-
}
|
|
3842
|
-
if (testResults.tools_unclear > 0) {
|
|
3843
|
-
testResults.recommendations.push('Some tools have unclear status - implement better response validation');
|
|
3844
|
-
}
|
|
3845
|
-
this.logger.info(`✅ Tool health test completed: ${testResults.tools_working}/${testResults.tools_tested} working`);
|
|
3846
|
-
return {
|
|
3847
|
-
success: true,
|
|
3848
|
-
test_summary: testResults,
|
|
3849
|
-
message: `Tool health test completed: ${testResults.tools_working}/${testResults.tools_tested} tools working properly`,
|
|
3850
|
-
detailed_report: testResults.detailed_results
|
|
3851
|
-
};
|
|
3852
|
-
}
|
|
3853
|
-
catch (error) {
|
|
3854
|
-
this.logger.error('Failed to test workspace tools:', error);
|
|
3855
|
-
return {
|
|
3856
|
-
success: false,
|
|
3857
|
-
error: `Failed to test workspace tools: ${error}`,
|
|
3858
|
-
suggestion: 'Check ServiceNow connectivity and authentication',
|
|
3859
|
-
operation_attempted: 'TEST All Workspace Tools'
|
|
3860
|
-
};
|
|
3861
|
-
}
|
|
3862
|
-
}
|
|
3863
|
-
/**
|
|
3864
|
-
* CHECK PLUGIN AVAILABILITY
|
|
3865
|
-
* Comprehensive plugin and licensing status check
|
|
3866
|
-
*/
|
|
3867
|
-
async checkPluginAvailability(args) {
|
|
3868
|
-
try {
|
|
3869
|
-
this.logger.info('🔌 Checking ServiceNow plugin availability...');
|
|
3870
|
-
const pluginChecks = [];
|
|
3871
|
-
if (args.check_ui_builder) {
|
|
3872
|
-
const uiBuilderCheck = await this.client.searchRecords('sys_ux_page', '', 1);
|
|
3873
|
-
pluginChecks.push({
|
|
3874
|
-
name: 'UI Builder',
|
|
3875
|
-
table: 'sys_ux_page',
|
|
3876
|
-
available: uiBuilderCheck.success,
|
|
3877
|
-
error: uiBuilderCheck.success ? null : uiBuilderCheck.error,
|
|
3878
|
-
status: uiBuilderCheck.success ? '✅ Available' : '❌ Not Available',
|
|
3879
|
-
recommendation: uiBuilderCheck.success ? 'UI Builder tools should work' : 'Install UI Builder plugin from ServiceNow Store'
|
|
3880
|
-
});
|
|
3881
|
-
}
|
|
3882
|
-
if (args.check_uxf) {
|
|
3883
|
-
const uxfCheck = await this.client.searchRecords('sys_ux_experience', '', 1);
|
|
3884
|
-
pluginChecks.push({
|
|
3885
|
-
name: 'Now Experience Framework',
|
|
3886
|
-
table: 'sys_ux_experience',
|
|
3887
|
-
available: uxfCheck.success,
|
|
3888
|
-
error: uxfCheck.success ? null : uxfCheck.error,
|
|
3889
|
-
status: uxfCheck.success ? '✅ Available' : '❌ Not Available',
|
|
3890
|
-
recommendation: uxfCheck.success ? 'UX workspace creation should work' : 'Enable Now Experience Framework in instance'
|
|
3891
|
-
});
|
|
3892
|
-
}
|
|
3893
|
-
if (args.check_agent_workspace) {
|
|
3894
|
-
const agentCheck = await this.client.searchRecords('sys_ux_screen_type', '', 1);
|
|
3895
|
-
pluginChecks.push({
|
|
3896
|
-
name: 'Agent Workspace',
|
|
3897
|
-
table: 'sys_ux_screen_type',
|
|
3898
|
-
available: agentCheck.success,
|
|
3899
|
-
error: agentCheck.success ? null : agentCheck.error,
|
|
3900
|
-
status: agentCheck.success ? '✅ Available' : '❌ Not Available',
|
|
3901
|
-
recommendation: agentCheck.success ? 'Agent workspace tools should work' : 'Install Agent Workspace plugin'
|
|
3902
|
-
});
|
|
3903
|
-
}
|
|
3904
|
-
if (args.check_mobile) {
|
|
3905
|
-
const mobileCheck = await this.client.searchRecords('sys_push_notif_msg', '', 1);
|
|
3906
|
-
pluginChecks.push({
|
|
3907
|
-
name: 'Mobile Publishing',
|
|
3908
|
-
table: 'sys_push_notif_msg',
|
|
3909
|
-
available: mobileCheck.success,
|
|
3910
|
-
error: mobileCheck.success ? null : mobileCheck.error,
|
|
3911
|
-
status: mobileCheck.success ? '✅ Available' : '❌ Not Available',
|
|
3912
|
-
recommendation: mobileCheck.success ? 'Mobile tools should work' : 'Install Mobile Publishing plugin (requires additional licensing)'
|
|
3913
|
-
});
|
|
3914
|
-
}
|
|
3915
|
-
const availableCount = pluginChecks.filter(p => p.available).length;
|
|
3916
|
-
const totalCount = pluginChecks.length;
|
|
3917
|
-
this.logger.info(`✅ Plugin check completed: ${availableCount}/${totalCount} plugins available`);
|
|
3918
|
-
return {
|
|
3919
|
-
success: true,
|
|
3920
|
-
plugin_summary: {
|
|
3921
|
-
total_checked: totalCount,
|
|
3922
|
-
available: availableCount,
|
|
3923
|
-
unavailable: totalCount - availableCount,
|
|
3924
|
-
percentage: Math.round((availableCount / totalCount) * 100)
|
|
3925
|
-
},
|
|
3926
|
-
plugins: pluginChecks,
|
|
3927
|
-
message: `Plugin availability check: ${availableCount}/${totalCount} plugins available`,
|
|
3928
|
-
overall_status: availableCount === totalCount ? 'All plugins available' :
|
|
3929
|
-
availableCount > 0 ? 'Partial plugin availability' : 'No plugins available'
|
|
3930
|
-
};
|
|
3931
|
-
}
|
|
3932
|
-
catch (error) {
|
|
3933
|
-
this.logger.error('Failed to check plugin availability:', error);
|
|
3934
|
-
return {
|
|
3935
|
-
success: false,
|
|
3936
|
-
error: `Failed to check plugin availability: ${error}`,
|
|
3937
|
-
suggestion: 'Check ServiceNow connectivity and basic table access permissions',
|
|
3938
|
-
operation_attempted: 'CHECK Plugin Availability'
|
|
3939
|
-
};
|
|
3940
|
-
}
|
|
3941
|
-
}
|
|
3942
3319
|
/**
|
|
3943
3320
|
* CONFIGURABLE AGENT WORKSPACE: Create using UX App architecture
|
|
3944
3321
|
*/
|
|
@@ -4045,144 +3422,6 @@ ${configList}${layoutsText}${offlineText}
|
|
|
4045
3422
|
.replace(/^-|-$/g, '') // Trim leading/trailing hyphens
|
|
4046
3423
|
.substring(0, 80); // Max 80 chars (ServiceNow field limit)
|
|
4047
3424
|
}
|
|
4048
|
-
/**
|
|
4049
|
-
* ENHANCED RESPONSE VALIDATION SYSTEM
|
|
4050
|
-
* Provides comprehensive feedback for all tool operations
|
|
4051
|
-
*/
|
|
4052
|
-
async validateAndConfirmOperation(operationType, result, details) {
|
|
4053
|
-
try {
|
|
4054
|
-
// Standard validation for ServiceNow API responses
|
|
4055
|
-
if (!result || typeof result !== 'object') {
|
|
4056
|
-
return {
|
|
4057
|
-
success: false,
|
|
4058
|
-
error: `No response received from ServiceNow API for ${operationType}`,
|
|
4059
|
-
suggestion: 'Check ServiceNow instance connectivity and authentication',
|
|
4060
|
-
validation_result: 'NO_RESPONSE'
|
|
4061
|
-
};
|
|
4062
|
-
}
|
|
4063
|
-
// Check for API success/failure
|
|
4064
|
-
if (result.success === false) {
|
|
4065
|
-
return {
|
|
4066
|
-
success: false,
|
|
4067
|
-
error: result.error || `${operationType} operation failed`,
|
|
4068
|
-
suggestion: this.getErrorSuggestion(result.error || ''),
|
|
4069
|
-
validation_result: 'API_FAILURE'
|
|
4070
|
-
};
|
|
4071
|
-
}
|
|
4072
|
-
// Validate response data structure
|
|
4073
|
-
if (result.success && (!result.data || !result.data.result)) {
|
|
4074
|
-
return {
|
|
4075
|
-
success: false,
|
|
4076
|
-
error: `${operationType} succeeded but returned invalid data structure`,
|
|
4077
|
-
suggestion: 'Check ServiceNow table permissions and field access',
|
|
4078
|
-
validation_result: 'INVALID_DATA_STRUCTURE'
|
|
4079
|
-
};
|
|
4080
|
-
}
|
|
4081
|
-
// Extract sys_id for verification
|
|
4082
|
-
const sys_id = result.data?.result?.sys_id;
|
|
4083
|
-
if (result.success && !sys_id) {
|
|
4084
|
-
return {
|
|
4085
|
-
success: false,
|
|
4086
|
-
error: `${operationType} succeeded but no sys_id returned`,
|
|
4087
|
-
suggestion: 'Record may have been created but sys_id is not accessible',
|
|
4088
|
-
validation_result: 'MISSING_SYS_ID'
|
|
4089
|
-
};
|
|
4090
|
-
}
|
|
4091
|
-
// VERIFICATION STEP: Confirm record actually exists
|
|
4092
|
-
if (sys_id && details.table) {
|
|
4093
|
-
const verification = await this.client.getRecord(details.table, sys_id);
|
|
4094
|
-
if (!verification.success) {
|
|
4095
|
-
return {
|
|
4096
|
-
success: false,
|
|
4097
|
-
error: `${operationType} reported success but record not found in ${details.table}`,
|
|
4098
|
-
suggestion: 'Record creation may have failed silently or been rolled back',
|
|
4099
|
-
validation_result: 'RECORD_NOT_FOUND',
|
|
4100
|
-
reported_sys_id: sys_id
|
|
4101
|
-
};
|
|
4102
|
-
}
|
|
4103
|
-
// SUCCESS with verification!
|
|
4104
|
-
return {
|
|
4105
|
-
success: true,
|
|
4106
|
-
sys_id: sys_id,
|
|
4107
|
-
verified: true,
|
|
4108
|
-
operation_type: operationType,
|
|
4109
|
-
table: details.table,
|
|
4110
|
-
message: `${operationType} completed successfully`,
|
|
4111
|
-
confirmation: `Record verified in ${details.table} with sys_id: ${sys_id}`,
|
|
4112
|
-
validation_result: 'VERIFIED_SUCCESS'
|
|
4113
|
-
};
|
|
4114
|
-
}
|
|
4115
|
-
// Success without verification (no sys_id or table)
|
|
4116
|
-
return {
|
|
4117
|
-
success: true,
|
|
4118
|
-
operation_type: operationType,
|
|
4119
|
-
message: `${operationType} completed`,
|
|
4120
|
-
validation_result: 'SUCCESS_NO_VERIFICATION'
|
|
4121
|
-
};
|
|
4122
|
-
}
|
|
4123
|
-
catch (error) {
|
|
4124
|
-
this.logger.error('Validation error:', error);
|
|
4125
|
-
return {
|
|
4126
|
-
success: false,
|
|
4127
|
-
error: `Validation failed for ${operationType}: ${error}`,
|
|
4128
|
-
suggestion: 'Check ServiceNow connectivity and permissions',
|
|
4129
|
-
validation_result: 'VALIDATION_ERROR'
|
|
4130
|
-
};
|
|
4131
|
-
}
|
|
4132
|
-
}
|
|
4133
|
-
/**
|
|
4134
|
-
* Get actionable suggestions based on error type with specific tool guidance
|
|
4135
|
-
*/
|
|
4136
|
-
getErrorSuggestion(error) {
|
|
4137
|
-
const errorLower = error.toLowerCase();
|
|
4138
|
-
if (errorLower.includes('403') || errorLower.includes('forbidden')) {
|
|
4139
|
-
return 'PERMISSIONS ISSUE: You need specific roles. For UI Builder: ui_builder_admin + ui_builder_user. For Workspaces: workspace_admin. For Mobile: mobile_admin. Contact your ServiceNow admin.';
|
|
4140
|
-
}
|
|
4141
|
-
if (errorLower.includes('404') || errorLower.includes('not found')) {
|
|
4142
|
-
return 'PLUGIN/TABLE MISSING: Required ServiceNow plugin not installed. UI Builder requires "UI Builder" plugin. Workspaces require "Agent Workspace" or "Now Experience Framework". Check ServiceNow Store.';
|
|
4143
|
-
}
|
|
4144
|
-
if (errorLower.includes('400') || errorLower.includes('bad request')) {
|
|
4145
|
-
return 'INVALID DATA: Check required fields and data formats. Some tools need valid sys_ids from previous steps in the workflow.';
|
|
4146
|
-
}
|
|
4147
|
-
if (errorLower.includes('401') || errorLower.includes('unauthorized')) {
|
|
4148
|
-
return 'AUTHENTICATION EXPIRED: Run "snow-flow auth login" to re-authenticate with ServiceNow.';
|
|
4149
|
-
}
|
|
4150
|
-
if (errorLower.includes('sys_id')) {
|
|
4151
|
-
return 'SYS_ID ERROR: Invalid or missing sys_id in API response. This usually means the record creation failed silently.';
|
|
4152
|
-
}
|
|
4153
|
-
if (errorLower.includes('plugin') || errorLower.includes('license')) {
|
|
4154
|
-
return 'LICENSING ISSUE: Required ServiceNow plugin/license not available. Contact ServiceNow admin for proper licensing.';
|
|
4155
|
-
}
|
|
4156
|
-
return 'UNKNOWN ERROR: Check ServiceNow system logs (System Logs > System Log > All) for detailed error information.';
|
|
4157
|
-
}
|
|
4158
|
-
/**
|
|
4159
|
-
* Enhanced tool execution wrapper with comprehensive feedback
|
|
4160
|
-
*/
|
|
4161
|
-
async executeWithFeedback(operationType, operation, details) {
|
|
4162
|
-
try {
|
|
4163
|
-
this.logger.info(`🔄 Executing ${operationType}...`);
|
|
4164
|
-
const startTime = Date.now();
|
|
4165
|
-
const result = await operation();
|
|
4166
|
-
const executionTime = Date.now() - startTime;
|
|
4167
|
-
const validation = await this.validateAndConfirmOperation(operationType, result, details);
|
|
4168
|
-
return {
|
|
4169
|
-
...validation,
|
|
4170
|
-
execution_time_ms: executionTime,
|
|
4171
|
-
timestamp: new Date().toISOString()
|
|
4172
|
-
};
|
|
4173
|
-
}
|
|
4174
|
-
catch (error) {
|
|
4175
|
-
this.logger.error(`❌ ${operationType} failed:`, error);
|
|
4176
|
-
return {
|
|
4177
|
-
success: false,
|
|
4178
|
-
operation_type: operationType,
|
|
4179
|
-
error: error instanceof Error ? error.message : String(error),
|
|
4180
|
-
suggestion: this.getErrorSuggestion(String(error)),
|
|
4181
|
-
validation_result: 'EXECUTION_ERROR',
|
|
4182
|
-
timestamp: new Date().toISOString()
|
|
4183
|
-
};
|
|
4184
|
-
}
|
|
4185
|
-
}
|
|
4186
3425
|
/**
|
|
4187
3426
|
* Validate workspace configuration (fix from user feedback)
|
|
4188
3427
|
*/
|
|
@@ -4202,9 +3441,32 @@ ${configList}${layoutsText}${offlineText}
|
|
|
4202
3441
|
return errors;
|
|
4203
3442
|
}
|
|
4204
3443
|
async run() {
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
3444
|
+
try {
|
|
3445
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
3446
|
+
// Simple timeout protection (prevents hanging)
|
|
3447
|
+
const connectTimeout = setTimeout(() => {
|
|
3448
|
+
this.logger.error('❌ MCP connection timeout after 30 seconds');
|
|
3449
|
+
process.exit(1);
|
|
3450
|
+
}, 30000);
|
|
3451
|
+
await this.server.connect(transport);
|
|
3452
|
+
clearTimeout(connectTimeout);
|
|
3453
|
+
this.logger.info('✅ ServiceNow Flow/Workspace/Mobile MCP Server running on stdio');
|
|
3454
|
+
// Simple keep-alive (prevents disconnects)
|
|
3455
|
+
setInterval(() => {
|
|
3456
|
+
this.logger.debug('💚 MCP server alive - uptime: ' + Math.round((Date.now() - Date.now()) / 60000) + 'min');
|
|
3457
|
+
}, 120000); // Every 2 minutes
|
|
3458
|
+
}
|
|
3459
|
+
catch (error) {
|
|
3460
|
+
this.logger.error('❌ MCP server failed to start:', error);
|
|
3461
|
+
// Simple retry once
|
|
3462
|
+
this.logger.info('🔄 Retrying MCP connection once...');
|
|
3463
|
+
setTimeout(() => {
|
|
3464
|
+
this.run().catch(() => {
|
|
3465
|
+
this.logger.error('💥 MCP retry failed - exiting');
|
|
3466
|
+
process.exit(1);
|
|
3467
|
+
});
|
|
3468
|
+
}, 3000);
|
|
3469
|
+
}
|
|
4208
3470
|
}
|
|
4209
3471
|
}
|
|
4210
3472
|
const server = new ServiceNowFlowWorkspaceMobileMCP();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.52",
|
|
4
4
|
"description": "Conversational ServiceNow development platform using Claude Code. Multi-agent orchestration with 20+ MCP servers providing 245+ ServiceNow tools including complete UX + Agent Workspace creation with official APIs.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|