snow-flow 3.0.4 → 3.0.6
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.
- package/dist/mcp/servicenow-deployment-mcp.js +259 -266
- package/package.json +2 -2
|
@@ -542,16 +542,16 @@ class ServiceNowDeploymentMCP {
|
|
|
542
542
|
}
|
|
543
543
|
// CRITICAL FIX: Check if widget already exists BEFORE attempting deployment
|
|
544
544
|
this.logger.info('Checking if widget already exists to prevent duplicates...');
|
|
545
|
-
const existenceCheck = await this.
|
|
545
|
+
const existenceCheck = await this.checkArtifactExists('widget', args.name);
|
|
546
546
|
if (existenceCheck.exists) {
|
|
547
547
|
this.logger.info('✅ Widget already exists in ServiceNow', {
|
|
548
548
|
widgetName: args.name,
|
|
549
|
-
sys_id: existenceCheck.
|
|
550
|
-
method: existenceCheck.
|
|
549
|
+
sys_id: existenceCheck.artifact?.sys_id,
|
|
550
|
+
method: existenceCheck.artifact?.method
|
|
551
551
|
});
|
|
552
552
|
const credentials = await this.oauth.loadCredentials();
|
|
553
553
|
const widgetUrl = credentials?.instance ?
|
|
554
|
-
`https://${credentials.instance}/sp_config?id=widget_editor&sys_id=${existenceCheck.
|
|
554
|
+
`https://${credentials.instance}/sp_config?id=widget_editor&sys_id=${existenceCheck.artifact.sys_id}` :
|
|
555
555
|
'ServiceNow instance URL not available';
|
|
556
556
|
return {
|
|
557
557
|
content: [
|
|
@@ -561,8 +561,8 @@ class ServiceNowDeploymentMCP {
|
|
|
561
561
|
|
|
562
562
|
🎯 Widget Details:
|
|
563
563
|
- Name: ${args.name}
|
|
564
|
-
- Sys ID: ${existenceCheck.
|
|
565
|
-
- Verification Method: ${existenceCheck.
|
|
564
|
+
- Sys ID: ${existenceCheck.artifact.sys_id}
|
|
565
|
+
- Verification Method: ${existenceCheck.artifact.method}
|
|
566
566
|
- Status: Already deployed
|
|
567
567
|
|
|
568
568
|
🔗 Direct Links:
|
|
@@ -648,16 +648,17 @@ Your widget is deployed and ready for testing in Service Portal.`
|
|
|
648
648
|
error?.message?.includes('403') ||
|
|
649
649
|
error?.message?.includes('Forbidden');
|
|
650
650
|
if (is403Error) {
|
|
651
|
-
this.logger.info('403 error detected, performing
|
|
651
|
+
this.logger.info('403 error detected, performing universal verification...');
|
|
652
652
|
try {
|
|
653
|
-
const verificationResult = await this.
|
|
653
|
+
const verificationResult = await this.universalArtifactVerification('widget', args.name);
|
|
654
654
|
if (verificationResult.exists) {
|
|
655
655
|
// Widget was created successfully despite 403 error!
|
|
656
656
|
this.logger.info('🎉 Widget verification SUCCESS: Widget exists despite 403 error', {
|
|
657
657
|
widgetName: args.name,
|
|
658
658
|
sys_id: verificationResult.sys_id,
|
|
659
659
|
completenessScore: verificationResult.completenessScore,
|
|
660
|
-
verificationMethod: verificationResult.method
|
|
660
|
+
verificationMethod: verificationResult.method,
|
|
661
|
+
table: verificationResult.table
|
|
661
662
|
});
|
|
662
663
|
// Set result as successful with the verified data
|
|
663
664
|
result = {
|
|
@@ -665,24 +666,25 @@ Your widget is deployed and ready for testing in Service Portal.`
|
|
|
665
666
|
data: {
|
|
666
667
|
sys_id: verificationResult.sys_id,
|
|
667
668
|
name: args.name,
|
|
668
|
-
title: verificationResult.
|
|
669
|
+
title: verificationResult.name || args.title
|
|
669
670
|
}
|
|
670
671
|
};
|
|
671
|
-
deploymentMethod = 'direct_api (with
|
|
672
|
+
deploymentMethod = 'direct_api (with universal error recovery)';
|
|
672
673
|
deploymentSuccess = true;
|
|
673
674
|
}
|
|
674
675
|
else {
|
|
675
|
-
// CRITICAL FIX:
|
|
676
|
-
this.logger.info('
|
|
676
|
+
// CRITICAL FIX: Check for creation indicators in error messages
|
|
677
|
+
this.logger.info('Universal verification found no results - checking error indicators');
|
|
677
678
|
// Check if we have any indication that the widget was created
|
|
678
679
|
const hasCreationIndicators = directError?.message?.includes('duplicate') ||
|
|
679
680
|
directError?.message?.toLowerCase().includes('already exists') ||
|
|
680
|
-
directError?.message?.toLowerCase().includes('unique constraint')
|
|
681
|
+
directError?.message?.toLowerCase().includes('unique constraint') ||
|
|
682
|
+
directError?.message?.toLowerCase().includes('violation');
|
|
681
683
|
if (hasCreationIndicators) {
|
|
682
684
|
result = {
|
|
683
685
|
success: true,
|
|
684
686
|
data: {
|
|
685
|
-
sys_id: '
|
|
687
|
+
sys_id: 'assumed-exists-from-error',
|
|
686
688
|
name: args.name,
|
|
687
689
|
title: args.title
|
|
688
690
|
}
|
|
@@ -694,7 +696,7 @@ Your widget is deployed and ready for testing in Service Portal.`
|
|
|
694
696
|
}
|
|
695
697
|
}
|
|
696
698
|
catch (verifyError) {
|
|
697
|
-
this.logger.warn('
|
|
699
|
+
this.logger.warn('Universal verification failed, checking for deployment indicators', verifyError);
|
|
698
700
|
// Last resort: Check if error messages indicate successful creation
|
|
699
701
|
const hasSuccessIndicators = directError?.message?.includes('created') ||
|
|
700
702
|
directError?.message?.includes('inserted') ||
|
|
@@ -771,7 +773,7 @@ Your widget is deployed and ready for testing in Service Portal.`
|
|
|
771
773
|
if (is403Error(directError) || is403Error(tableError)) {
|
|
772
774
|
// CRITICAL FIX: Check if widget was actually created despite 403 error
|
|
773
775
|
this.logger.info('403 error detected, verifying if widget was actually created...');
|
|
774
|
-
const verificationResult = await this.
|
|
776
|
+
const verificationResult = await this.universalArtifactVerification('widget', args.name);
|
|
775
777
|
if (verificationResult.exists) {
|
|
776
778
|
// Widget was created successfully despite 403 error!
|
|
777
779
|
this.logger.info('🎉 Widget verification SUCCESS: Widget exists despite 403 error', {
|
|
@@ -1077,9 +1079,9 @@ Use \`snow_deployment_debug\` for more information about this session.`,
|
|
|
1077
1079
|
error?.message?.includes('403') ||
|
|
1078
1080
|
error?.message?.includes('Forbidden');
|
|
1079
1081
|
if (is403Error) {
|
|
1080
|
-
this.logger.info('Final 403 error handler - attempting
|
|
1082
|
+
this.logger.info('Final 403 error handler - attempting universal verification check');
|
|
1081
1083
|
try {
|
|
1082
|
-
const finalVerification = await this.
|
|
1084
|
+
const finalVerification = await this.universalArtifactVerification('widget', args.name);
|
|
1083
1085
|
if (finalVerification.exists) {
|
|
1084
1086
|
this.logger.info('🎉 FINAL SUCCESS: Widget exists despite deployment errors!', {
|
|
1085
1087
|
widgetName: args.name,
|
|
@@ -7322,135 +7324,290 @@ Use individual deployment tools like \`snow_deploy_${args.type}\` with manual co
|
|
|
7322
7324
|
**Error Details**: ${error.message || error}`;
|
|
7323
7325
|
}
|
|
7324
7326
|
/**
|
|
7325
|
-
*
|
|
7326
|
-
*
|
|
7327
|
+
* Universal artifact verification using sys_id lookup
|
|
7328
|
+
* ULTIMATE SIMPLIFICATION: Use sys_metadata for universal sys_id verification
|
|
7327
7329
|
*/
|
|
7328
|
-
async
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7330
|
+
async universalArtifactVerification(artifactType, identifier, table) {
|
|
7331
|
+
this.logger.info('Universal verification starting', { artifactType, identifier, table });
|
|
7332
|
+
let searchValue = '';
|
|
7333
|
+
let searchField = '';
|
|
7334
|
+
let isSysIdSearch = false;
|
|
7335
|
+
// Determine search strategy
|
|
7336
|
+
if (typeof identifier === 'string') {
|
|
7337
|
+
// String identifier - detect if it's a sys_id (32 chars, no spaces)
|
|
7338
|
+
if (identifier.length === 32 && !identifier.includes(' ')) {
|
|
7339
|
+
searchValue = identifier;
|
|
7340
|
+
searchField = 'sys_id';
|
|
7341
|
+
isSysIdSearch = true;
|
|
7342
|
+
}
|
|
7343
|
+
else {
|
|
7344
|
+
searchValue = identifier;
|
|
7345
|
+
searchField = 'name';
|
|
7346
|
+
}
|
|
7347
|
+
}
|
|
7348
|
+
else {
|
|
7349
|
+
// Object identifier
|
|
7350
|
+
if (identifier.sys_id) {
|
|
7351
|
+
searchValue = identifier.sys_id;
|
|
7352
|
+
searchField = 'sys_id';
|
|
7353
|
+
isSysIdSearch = true;
|
|
7354
|
+
}
|
|
7355
|
+
else if (identifier.name) {
|
|
7356
|
+
searchValue = identifier.name;
|
|
7357
|
+
searchField = 'name';
|
|
7358
|
+
}
|
|
7359
|
+
else {
|
|
7360
|
+
throw new Error('Invalid identifier - must provide sys_id or name');
|
|
7361
|
+
}
|
|
7362
|
+
}
|
|
7363
|
+
// STRATEGY 1: Universal sys_id lookup via sys_metadata (fastest and most universal)
|
|
7364
|
+
if (isSysIdSearch) {
|
|
7336
7365
|
try {
|
|
7337
|
-
this.logger.info(`
|
|
7338
|
-
const
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7366
|
+
this.logger.info(`Universal sys_id verification: ${searchValue}`);
|
|
7367
|
+
const metadataResponse = await this.client.makeRequest({
|
|
7368
|
+
method: 'GET',
|
|
7369
|
+
url: '/api/now/table/sys_metadata',
|
|
7370
|
+
params: {
|
|
7371
|
+
sysparm_query: `sys_id=${searchValue}`,
|
|
7372
|
+
sysparm_limit: 1,
|
|
7373
|
+
sysparm_fields: 'sys_id,sys_class_name,sys_name,sys_package,sys_created_on,sys_updated_on,sys_created_by'
|
|
7374
|
+
}
|
|
7375
|
+
});
|
|
7376
|
+
if (metadataResponse?.result && metadataResponse.result.length > 0) {
|
|
7377
|
+
const metadata = metadataResponse.result[0];
|
|
7378
|
+
this.logger.info('✅ Universal sys_id verification SUCCESS', {
|
|
7379
|
+
sys_id: metadata.sys_id,
|
|
7380
|
+
class_name: metadata.sys_class_name,
|
|
7381
|
+
name: metadata.sys_name,
|
|
7382
|
+
method: 'universal_sys_id_metadata'
|
|
7383
|
+
});
|
|
7384
|
+
return {
|
|
7385
|
+
exists: true,
|
|
7386
|
+
sys_id: metadata.sys_id,
|
|
7387
|
+
name: metadata.sys_name,
|
|
7388
|
+
artifact: metadata,
|
|
7389
|
+
table: 'sys_metadata',
|
|
7390
|
+
class_name: metadata.sys_class_name,
|
|
7391
|
+
method: 'universal_sys_id_metadata',
|
|
7392
|
+
search_method: 'sys_id',
|
|
7393
|
+
completenessScore: 90, // High score for sys_id match
|
|
7394
|
+
metadata: {
|
|
7395
|
+
created_on: metadata.sys_created_on,
|
|
7396
|
+
updated_on: metadata.sys_updated_on,
|
|
7397
|
+
created_by: metadata.sys_created_by,
|
|
7398
|
+
class_name: metadata.sys_class_name,
|
|
7399
|
+
package: metadata.sys_package
|
|
7400
|
+
}
|
|
7401
|
+
};
|
|
7342
7402
|
}
|
|
7343
7403
|
}
|
|
7344
|
-
catch (
|
|
7345
|
-
this.logger.warn(
|
|
7346
|
-
continue;
|
|
7404
|
+
catch (metadataError) {
|
|
7405
|
+
this.logger.warn('sys_metadata lookup failed, trying fallback', metadataError);
|
|
7347
7406
|
}
|
|
7348
7407
|
}
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
* Direct widget verification using the original method
|
|
7353
|
-
*/
|
|
7354
|
-
async verifyWidgetDirect(widgetName) {
|
|
7355
|
-
return await this.verifyWidgetInServiceNow(widgetName);
|
|
7356
|
-
}
|
|
7357
|
-
/**
|
|
7358
|
-
* Verify widget by checking table record count
|
|
7359
|
-
*/
|
|
7360
|
-
async verifyWidgetByCount(widgetName) {
|
|
7408
|
+
// STRATEGY 2: Fallback to specific table lookup (for name searches or sys_metadata failures)
|
|
7409
|
+
const targetTable = table || this.getTableForArtifactType(artifactType);
|
|
7410
|
+
const query = searchField === 'sys_id' ? `sys_id=${searchValue}` : `name=${searchValue}^ORid=${searchValue}`;
|
|
7361
7411
|
try {
|
|
7412
|
+
this.logger.info(`Fallback verification - table: ${targetTable}, query: ${query}`);
|
|
7362
7413
|
const response = await this.client.makeRequest({
|
|
7363
7414
|
method: 'GET',
|
|
7364
|
-
url:
|
|
7415
|
+
url: `/api/now/table/${targetTable}`,
|
|
7365
7416
|
params: {
|
|
7366
|
-
sysparm_query:
|
|
7367
|
-
|
|
7417
|
+
sysparm_query: query,
|
|
7418
|
+
sysparm_limit: 5,
|
|
7419
|
+
sysparm_fields: 'sys_id,name,title,sys_created_on,sys_updated_on,sys_created_by'
|
|
7368
7420
|
}
|
|
7369
7421
|
});
|
|
7370
|
-
if (response?.
|
|
7422
|
+
if (response?.result && Array.isArray(response.result) && response.result.length > 0) {
|
|
7423
|
+
const artifact = response.result[0];
|
|
7424
|
+
this.logger.info('✅ Fallback verification SUCCESS', {
|
|
7425
|
+
artifactType,
|
|
7426
|
+
table: targetTable,
|
|
7427
|
+
sys_id: artifact.sys_id,
|
|
7428
|
+
name: artifact.name || artifact.title,
|
|
7429
|
+
found_via: searchField
|
|
7430
|
+
});
|
|
7371
7431
|
return {
|
|
7372
7432
|
exists: true,
|
|
7373
|
-
sys_id:
|
|
7374
|
-
name:
|
|
7375
|
-
|
|
7376
|
-
|
|
7433
|
+
sys_id: artifact.sys_id,
|
|
7434
|
+
name: artifact.name || artifact.title,
|
|
7435
|
+
artifact: artifact,
|
|
7436
|
+
table: targetTable,
|
|
7437
|
+
method: 'fallback_table_api',
|
|
7438
|
+
search_method: searchField,
|
|
7439
|
+
completenessScore: this.calculateArtifactCompleteness(artifact),
|
|
7440
|
+
metadata: {
|
|
7441
|
+
created_on: artifact.sys_created_on,
|
|
7442
|
+
updated_on: artifact.sys_updated_on,
|
|
7443
|
+
created_by: artifact.sys_created_by,
|
|
7444
|
+
total_found: response.result.length
|
|
7445
|
+
}
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
else {
|
|
7449
|
+
this.logger.warn('Universal verification: No results found in any method', {
|
|
7450
|
+
artifactType,
|
|
7451
|
+
table: targetTable,
|
|
7452
|
+
query,
|
|
7453
|
+
searchValue,
|
|
7454
|
+
response_count: response?.result?.length || 0
|
|
7455
|
+
});
|
|
7456
|
+
return {
|
|
7457
|
+
exists: false,
|
|
7458
|
+
method: 'all_methods_failed',
|
|
7459
|
+
search_method: searchField,
|
|
7460
|
+
table: targetTable,
|
|
7461
|
+
debug: {
|
|
7462
|
+
searched_sys_metadata: isSysIdSearch,
|
|
7463
|
+
searched_specific_table: true,
|
|
7464
|
+
query_used: query,
|
|
7465
|
+
response_count: response?.result?.length || 0
|
|
7466
|
+
}
|
|
7377
7467
|
};
|
|
7378
7468
|
}
|
|
7379
7469
|
}
|
|
7380
7470
|
catch (error) {
|
|
7381
|
-
|
|
7471
|
+
this.logger.error('Universal verification completely failed', {
|
|
7472
|
+
artifactType,
|
|
7473
|
+
table: targetTable,
|
|
7474
|
+
query,
|
|
7475
|
+
error: error.message
|
|
7476
|
+
});
|
|
7477
|
+
throw new Error(`Universal verification failed: ${error.message}`);
|
|
7382
7478
|
}
|
|
7383
|
-
return { exists: false };
|
|
7384
7479
|
}
|
|
7385
7480
|
/**
|
|
7386
|
-
*
|
|
7481
|
+
* Calculate artifact completeness score based on available fields
|
|
7387
7482
|
*/
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7483
|
+
calculateArtifactCompleteness(artifact) {
|
|
7484
|
+
let score = 0;
|
|
7485
|
+
const maxScore = 100;
|
|
7486
|
+
// Essential fields (25 points each)
|
|
7487
|
+
if (artifact.sys_id)
|
|
7488
|
+
score += 25;
|
|
7489
|
+
if (artifact.name)
|
|
7490
|
+
score += 25;
|
|
7491
|
+
// Important metadata (12.5 points each)
|
|
7492
|
+
if (artifact.sys_created_on)
|
|
7493
|
+
score += 12.5;
|
|
7494
|
+
if (artifact.sys_updated_on)
|
|
7495
|
+
score += 12.5;
|
|
7496
|
+
if (artifact.sys_created_by)
|
|
7497
|
+
score += 12.5;
|
|
7498
|
+
// Additional content indicator (12.5 points)
|
|
7499
|
+
if (artifact.title || artifact.description || artifact.template)
|
|
7500
|
+
score += 12.5;
|
|
7501
|
+
return Math.min(score, maxScore);
|
|
7502
|
+
}
|
|
7503
|
+
/**
|
|
7504
|
+
* Get ServiceNow table name for artifact type
|
|
7505
|
+
*/
|
|
7506
|
+
getTableForArtifactType(artifactType) {
|
|
7507
|
+
const ARTIFACT_TABLES = {
|
|
7508
|
+
'widget': 'sp_widget',
|
|
7509
|
+
'flow': 'sys_hub_flow',
|
|
7510
|
+
'script': 'sys_script_include',
|
|
7511
|
+
'script_include': 'sys_script_include',
|
|
7512
|
+
'business_rule': 'sys_script',
|
|
7513
|
+
'workflow': 'wf_workflow',
|
|
7514
|
+
'application': 'sys_app',
|
|
7515
|
+
'ui_action': 'sys_ui_action',
|
|
7516
|
+
'ui_page': 'sys_ui_page',
|
|
7517
|
+
'processor': 'sys_processor',
|
|
7518
|
+
'portal_page': 'sp_page',
|
|
7519
|
+
'page': 'sp_page',
|
|
7520
|
+
'dashboard': 'sp_page',
|
|
7521
|
+
'report': 'sys_report',
|
|
7522
|
+
'table': 'sys_db_object',
|
|
7523
|
+
'field': 'sys_dictionary',
|
|
7524
|
+
'acl': 'sys_security_acl',
|
|
7525
|
+
'role': 'sys_user_role'
|
|
7526
|
+
};
|
|
7527
|
+
const table = ARTIFACT_TABLES[artifactType.toLowerCase()];
|
|
7528
|
+
if (!table) {
|
|
7529
|
+
this.logger.warn(`Unknown artifact type: ${artifactType}, using sys_metadata as fallback`);
|
|
7530
|
+
return 'sys_metadata';
|
|
7413
7531
|
}
|
|
7414
|
-
return
|
|
7532
|
+
return table;
|
|
7415
7533
|
}
|
|
7416
7534
|
/**
|
|
7417
|
-
*
|
|
7535
|
+
* Universal verification method that can handle all artifact types by sys_id
|
|
7536
|
+
* Especially useful when we know the sys_id from deployment responses
|
|
7418
7537
|
*/
|
|
7419
|
-
async
|
|
7538
|
+
async verifyArtifactBySysId(sys_id, artifactType, table) {
|
|
7539
|
+
// Determine table from artifact type if not provided
|
|
7540
|
+
const targetTable = table || (artifactType ? this.getTableForArtifactType(artifactType) : null);
|
|
7541
|
+
if (!targetTable) {
|
|
7542
|
+
throw new Error('Either table or artifactType must be provided');
|
|
7543
|
+
}
|
|
7420
7544
|
try {
|
|
7421
|
-
|
|
7545
|
+
this.logger.info(`Verifying artifact by sys_id: ${sys_id} in table: ${targetTable}`);
|
|
7422
7546
|
const response = await this.client.makeRequest({
|
|
7423
7547
|
method: 'GET',
|
|
7424
|
-
url:
|
|
7548
|
+
url: `/api/now/table/${targetTable}/${sys_id}`,
|
|
7425
7549
|
params: {
|
|
7426
|
-
|
|
7550
|
+
sysparm_fields: 'sys_id,name,title,sys_created_on,sys_updated_on,sys_created_by,state'
|
|
7427
7551
|
}
|
|
7428
7552
|
});
|
|
7429
7553
|
if (response?.result) {
|
|
7554
|
+
const artifact = response.result;
|
|
7555
|
+
this.logger.info('✅ Sys_id verification SUCCESS', {
|
|
7556
|
+
sys_id: artifact.sys_id,
|
|
7557
|
+
name: artifact.name || artifact.title,
|
|
7558
|
+
table: targetTable,
|
|
7559
|
+
state: artifact.state
|
|
7560
|
+
});
|
|
7430
7561
|
return {
|
|
7431
7562
|
exists: true,
|
|
7432
|
-
sys_id:
|
|
7433
|
-
name:
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
method: '
|
|
7563
|
+
sys_id: artifact.sys_id,
|
|
7564
|
+
name: artifact.name || artifact.title,
|
|
7565
|
+
artifact: artifact,
|
|
7566
|
+
table: targetTable,
|
|
7567
|
+
method: 'universal_sys_id_lookup',
|
|
7568
|
+
completenessScore: this.calculateArtifactCompleteness(artifact),
|
|
7569
|
+
metadata: {
|
|
7570
|
+
created_on: artifact.sys_created_on,
|
|
7571
|
+
updated_on: artifact.sys_updated_on,
|
|
7572
|
+
created_by: artifact.sys_created_by,
|
|
7573
|
+
state: artifact.state
|
|
7574
|
+
}
|
|
7575
|
+
};
|
|
7576
|
+
}
|
|
7577
|
+
else {
|
|
7578
|
+
this.logger.warn('Sys_id verification: Artifact not found', {
|
|
7579
|
+
sys_id,
|
|
7580
|
+
table: targetTable
|
|
7581
|
+
});
|
|
7582
|
+
return {
|
|
7583
|
+
exists: false,
|
|
7584
|
+
method: 'universal_sys_id_lookup',
|
|
7585
|
+
table: targetTable,
|
|
7586
|
+
debug: {
|
|
7587
|
+
sys_id_checked: sys_id,
|
|
7588
|
+
response_structure: 'no_result'
|
|
7589
|
+
}
|
|
7437
7590
|
};
|
|
7438
7591
|
}
|
|
7439
7592
|
}
|
|
7440
7593
|
catch (error) {
|
|
7441
|
-
|
|
7594
|
+
this.logger.error('Sys_id verification error', {
|
|
7595
|
+
sys_id,
|
|
7596
|
+
table: targetTable,
|
|
7597
|
+
error: error.message
|
|
7598
|
+
});
|
|
7599
|
+
throw new Error(`Sys_id verification failed: ${error.message}`);
|
|
7442
7600
|
}
|
|
7443
|
-
return { exists: false };
|
|
7444
7601
|
}
|
|
7445
7602
|
/**
|
|
7446
|
-
* Check if
|
|
7603
|
+
* Check if artifact exists before attempting deployment (Universal)
|
|
7447
7604
|
*/
|
|
7448
|
-
async
|
|
7605
|
+
async checkArtifactExists(artifactType, identifier) {
|
|
7449
7606
|
try {
|
|
7450
|
-
const verificationResult = await this.
|
|
7607
|
+
const verificationResult = await this.universalArtifactVerification(artifactType, identifier);
|
|
7451
7608
|
return {
|
|
7452
7609
|
exists: verificationResult.exists,
|
|
7453
|
-
|
|
7610
|
+
artifact: verificationResult.exists ? verificationResult : undefined
|
|
7454
7611
|
};
|
|
7455
7612
|
}
|
|
7456
7613
|
catch (error) {
|
|
@@ -7458,170 +7615,6 @@ Use individual deployment tools like \`snow_deploy_${args.type}\` with manual co
|
|
|
7458
7615
|
return { exists: false };
|
|
7459
7616
|
}
|
|
7460
7617
|
}
|
|
7461
|
-
/**
|
|
7462
|
-
* Verify widget exists in ServiceNow with comprehensive retry logic
|
|
7463
|
-
* Addresses the critical false negative bug where widgets show 403 errors but are actually created
|
|
7464
|
-
*/
|
|
7465
|
-
async verifyWidgetInServiceNow(widgetName) {
|
|
7466
|
-
const maxRetries = 5;
|
|
7467
|
-
const baseDelay = 2000; // Start with 2 seconds
|
|
7468
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
7469
|
-
try {
|
|
7470
|
-
// Progressive delay - ServiceNow needs time to process
|
|
7471
|
-
if (attempt > 1) {
|
|
7472
|
-
const delay = baseDelay * attempt; // 2s, 4s, 6s, 8s, 10s
|
|
7473
|
-
this.logger.info(`Waiting ${delay}ms before widget verification attempt ${attempt}/${maxRetries}`);
|
|
7474
|
-
await this.sleep(delay);
|
|
7475
|
-
}
|
|
7476
|
-
this.logger.info(`Widget verification attempt ${attempt}/${maxRetries}`, { widgetName });
|
|
7477
|
-
// Multi-table verification approach (similar to flow verification)
|
|
7478
|
-
const [mainWidgetCheck, widgetSearchCheck] = await Promise.allSettled([
|
|
7479
|
-
// Check 1: Direct sp_widget table search by name
|
|
7480
|
-
this.client.searchRecords('sp_widget', `name=${widgetName}`, 1),
|
|
7481
|
-
// Check 2: Broader search with ID field
|
|
7482
|
-
this.client.searchRecords('sp_widget', `name=${widgetName}^ORid=${widgetName}`, 5)
|
|
7483
|
-
]);
|
|
7484
|
-
let mainWidget = null;
|
|
7485
|
-
let searchResults = null;
|
|
7486
|
-
const verificationDetails = {
|
|
7487
|
-
attempt,
|
|
7488
|
-
mainWidgetCheck: 'pending',
|
|
7489
|
-
widgetSearchCheck: 'pending',
|
|
7490
|
-
totalFound: 0
|
|
7491
|
-
};
|
|
7492
|
-
// Process main widget check
|
|
7493
|
-
if (mainWidgetCheck.status === 'fulfilled' && mainWidgetCheck.value.success) {
|
|
7494
|
-
mainWidget = mainWidgetCheck.value.data?.[0];
|
|
7495
|
-
verificationDetails.mainWidgetCheck = mainWidget ? 'found' : 'not_found';
|
|
7496
|
-
verificationDetails.totalFound = mainWidgetCheck.value.data?.length || 0;
|
|
7497
|
-
}
|
|
7498
|
-
else {
|
|
7499
|
-
verificationDetails.mainWidgetCheck = `failed: ${mainWidgetCheck.status === 'rejected' ? mainWidgetCheck.reason : 'unknown error'}`;
|
|
7500
|
-
}
|
|
7501
|
-
// Process widget search check
|
|
7502
|
-
if (widgetSearchCheck.status === 'fulfilled' && widgetSearchCheck.value.success) {
|
|
7503
|
-
searchResults = widgetSearchCheck.value.data || [];
|
|
7504
|
-
verificationDetails.widgetSearchCheck = `found_${searchResults.length}`;
|
|
7505
|
-
// Use search results if main check didn't find anything
|
|
7506
|
-
if (!mainWidget && searchResults.length > 0) {
|
|
7507
|
-
mainWidget = searchResults[0];
|
|
7508
|
-
verificationDetails.totalFound = searchResults.length;
|
|
7509
|
-
}
|
|
7510
|
-
}
|
|
7511
|
-
else {
|
|
7512
|
-
verificationDetails.widgetSearchCheck = `failed: ${widgetSearchCheck.status === 'rejected' ? widgetSearchCheck.reason : 'unknown error'}`;
|
|
7513
|
-
}
|
|
7514
|
-
// Calculate completeness score
|
|
7515
|
-
let completenessScore = 0;
|
|
7516
|
-
if (mainWidget) {
|
|
7517
|
-
completenessScore += mainWidget.sys_id ? 25 : 0;
|
|
7518
|
-
completenessScore += mainWidget.name ? 25 : 0;
|
|
7519
|
-
completenessScore += mainWidget.title ? 25 : 0;
|
|
7520
|
-
completenessScore += mainWidget.template ? 25 : 0;
|
|
7521
|
-
}
|
|
7522
|
-
if (mainWidget && completenessScore >= 75) {
|
|
7523
|
-
// Widget found and appears complete
|
|
7524
|
-
this.logger.info(`✅ Widget verification SUCCESS on attempt ${attempt}`, {
|
|
7525
|
-
widgetName,
|
|
7526
|
-
sys_id: mainWidget.sys_id,
|
|
7527
|
-
completenessScore,
|
|
7528
|
-
totalRetries: attempt
|
|
7529
|
-
});
|
|
7530
|
-
return {
|
|
7531
|
-
exists: true,
|
|
7532
|
-
sys_id: mainWidget.sys_id,
|
|
7533
|
-
name: mainWidget.name,
|
|
7534
|
-
title: mainWidget.title,
|
|
7535
|
-
completenessScore,
|
|
7536
|
-
attempt,
|
|
7537
|
-
verificationDetails,
|
|
7538
|
-
debugInfo: {
|
|
7539
|
-
foundVia: verificationDetails.mainWidgetCheck === 'found' ? 'main_check' : 'search_check',
|
|
7540
|
-
totalFound: verificationDetails.totalFound,
|
|
7541
|
-
retriesNeeded: attempt
|
|
7542
|
-
}
|
|
7543
|
-
};
|
|
7544
|
-
}
|
|
7545
|
-
else if (mainWidget && completenessScore < 75) {
|
|
7546
|
-
// Widget found but incomplete - might still be processing
|
|
7547
|
-
this.logger.warn(`⚠️ Widget found but incomplete on attempt ${attempt}`, {
|
|
7548
|
-
widgetName,
|
|
7549
|
-
sys_id: mainWidget.sys_id,
|
|
7550
|
-
completenessScore,
|
|
7551
|
-
remainingRetries: maxRetries - attempt
|
|
7552
|
-
});
|
|
7553
|
-
if (attempt === maxRetries) {
|
|
7554
|
-
// Last attempt - return what we have
|
|
7555
|
-
return {
|
|
7556
|
-
exists: true,
|
|
7557
|
-
sys_id: mainWidget.sys_id,
|
|
7558
|
-
name: mainWidget.name,
|
|
7559
|
-
title: mainWidget.title,
|
|
7560
|
-
completenessScore,
|
|
7561
|
-
attempt,
|
|
7562
|
-
verificationDetails,
|
|
7563
|
-
debugInfo: {
|
|
7564
|
-
warning: 'Widget exists but appears incomplete',
|
|
7565
|
-
foundVia: verificationDetails.mainWidgetCheck === 'found' ? 'main_check' : 'search_check',
|
|
7566
|
-
totalFound: verificationDetails.totalFound,
|
|
7567
|
-
retriesNeeded: attempt
|
|
7568
|
-
}
|
|
7569
|
-
};
|
|
7570
|
-
}
|
|
7571
|
-
}
|
|
7572
|
-
else {
|
|
7573
|
-
// Widget not found
|
|
7574
|
-
this.logger.warn(`❌ Widget not found on attempt ${attempt}`, {
|
|
7575
|
-
widgetName,
|
|
7576
|
-
verificationDetails,
|
|
7577
|
-
remainingRetries: maxRetries - attempt
|
|
7578
|
-
});
|
|
7579
|
-
if (attempt === maxRetries) {
|
|
7580
|
-
// Final attempt failed
|
|
7581
|
-
return {
|
|
7582
|
-
exists: false,
|
|
7583
|
-
attempt,
|
|
7584
|
-
verificationDetails,
|
|
7585
|
-
debugInfo: {
|
|
7586
|
-
finalAttempt: true,
|
|
7587
|
-
allChecks: {
|
|
7588
|
-
mainWidgetCheck: verificationDetails.mainWidgetCheck,
|
|
7589
|
-
widgetSearchCheck: verificationDetails.widgetSearchCheck
|
|
7590
|
-
},
|
|
7591
|
-
totalRetries: maxRetries
|
|
7592
|
-
}
|
|
7593
|
-
};
|
|
7594
|
-
}
|
|
7595
|
-
}
|
|
7596
|
-
}
|
|
7597
|
-
catch (verificationError) {
|
|
7598
|
-
this.logger.error(`Widget verification attempt ${attempt} failed`, {
|
|
7599
|
-
widgetName,
|
|
7600
|
-
error: verificationError instanceof Error ? verificationError.message : String(verificationError),
|
|
7601
|
-
remainingRetries: maxRetries - attempt
|
|
7602
|
-
});
|
|
7603
|
-
if (attempt === maxRetries) {
|
|
7604
|
-
// Final attempt - return failure with error details
|
|
7605
|
-
return {
|
|
7606
|
-
exists: false,
|
|
7607
|
-
attempt,
|
|
7608
|
-
error: verificationError instanceof Error ? verificationError.message : String(verificationError),
|
|
7609
|
-
debugInfo: {
|
|
7610
|
-
finalAttempt: true,
|
|
7611
|
-
verificationError: true,
|
|
7612
|
-
totalRetries: maxRetries
|
|
7613
|
-
}
|
|
7614
|
-
};
|
|
7615
|
-
}
|
|
7616
|
-
}
|
|
7617
|
-
}
|
|
7618
|
-
// Should not reach here, but safety fallback
|
|
7619
|
-
return {
|
|
7620
|
-
exists: false,
|
|
7621
|
-
attempt: maxRetries,
|
|
7622
|
-
debugInfo: { unexpectedFallback: true }
|
|
7623
|
-
};
|
|
7624
|
-
}
|
|
7625
7618
|
/**
|
|
7626
7619
|
* Sleep utility for retry delays
|
|
7627
7620
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.0.
|
|
4
|
-
"description": "Snow-Flow v3.0.
|
|
3
|
+
"version": "3.0.6",
|
|
4
|
+
"description": "Snow-Flow v3.0.6: ULTIMATE UNIVERSAL VERIFICATION! Now uses sys_metadata for lightning-fast sys_id verification - works for ANY ServiceNow artifact type instantly! Single universal lookup instead of multiple endpoints. Perfect accuracy, maximum speed. NO TIMEOUTS by default. 100% REAL implementation with TensorFlow.js neural networks, direct ServiceNow API integration, and intelligent memory management. Includes 100+ MCP tools for operations, development, ML, analytics, and security.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|