snow-flow 3.0.4 → 3.0.5
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 +216 -268
- 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,245 @@ 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 Table API
|
|
7328
|
+
* Works for all ServiceNow artifacts via consistent table lookup
|
|
7327
7329
|
*/
|
|
7328
|
-
async
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
}
|
|
7330
|
+
async universalArtifactVerification(artifactType, identifier, table) {
|
|
7331
|
+
this.logger.info('Universal verification starting', { artifactType, identifier, table });
|
|
7332
|
+
// Get table name if not provided
|
|
7333
|
+
const targetTable = table || this.getTableForArtifactType(artifactType);
|
|
7334
|
+
let query = '';
|
|
7335
|
+
let searchField = '';
|
|
7336
|
+
let searchValue = '';
|
|
7337
|
+
// Determine search strategy
|
|
7338
|
+
if (typeof identifier === 'string') {
|
|
7339
|
+
// String identifier - try name first, then sys_id format
|
|
7340
|
+
if (identifier.length === 32 && !identifier.includes(' ')) {
|
|
7341
|
+
query = `sys_id=${identifier}`;
|
|
7342
|
+
searchField = 'sys_id';
|
|
7343
|
+
searchValue = identifier;
|
|
7343
7344
|
}
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7345
|
+
else {
|
|
7346
|
+
query = `name=${identifier}^ORid=${identifier}`;
|
|
7347
|
+
searchField = 'name';
|
|
7348
|
+
searchValue = identifier;
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
else {
|
|
7352
|
+
// Object identifier
|
|
7353
|
+
if (identifier.sys_id) {
|
|
7354
|
+
query = `sys_id=${identifier.sys_id}`;
|
|
7355
|
+
searchField = 'sys_id';
|
|
7356
|
+
searchValue = identifier.sys_id;
|
|
7357
|
+
}
|
|
7358
|
+
else if (identifier.name) {
|
|
7359
|
+
query = `name=${identifier.name}^ORid=${identifier.name}`;
|
|
7360
|
+
searchField = 'name';
|
|
7361
|
+
searchValue = identifier.name;
|
|
7362
|
+
}
|
|
7363
|
+
else {
|
|
7364
|
+
throw new Error('Invalid identifier - must provide sys_id or name');
|
|
7347
7365
|
}
|
|
7348
7366
|
}
|
|
7349
|
-
return { exists: false, method: 'all_strategies_failed' };
|
|
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) {
|
|
7361
7367
|
try {
|
|
7368
|
+
this.logger.info(`Querying table: ${targetTable} with query: ${query}`);
|
|
7369
|
+
// Use the standard Table API for verification
|
|
7362
7370
|
const response = await this.client.makeRequest({
|
|
7363
7371
|
method: 'GET',
|
|
7364
|
-
url:
|
|
7372
|
+
url: `/api/now/table/${targetTable}`,
|
|
7365
7373
|
params: {
|
|
7366
|
-
sysparm_query:
|
|
7367
|
-
|
|
7374
|
+
sysparm_query: query,
|
|
7375
|
+
sysparm_limit: 5,
|
|
7376
|
+
sysparm_fields: 'sys_id,name,title,sys_created_on,sys_updated_on,sys_created_by'
|
|
7368
7377
|
}
|
|
7369
7378
|
});
|
|
7370
|
-
if (response?.
|
|
7379
|
+
if (response?.result && Array.isArray(response.result) && response.result.length > 0) {
|
|
7380
|
+
const artifact = response.result[0];
|
|
7381
|
+
this.logger.info('✅ Universal verification SUCCESS', {
|
|
7382
|
+
artifactType,
|
|
7383
|
+
table: targetTable,
|
|
7384
|
+
sys_id: artifact.sys_id,
|
|
7385
|
+
name: artifact.name || artifact.title,
|
|
7386
|
+
found_via: searchField
|
|
7387
|
+
});
|
|
7371
7388
|
return {
|
|
7372
7389
|
exists: true,
|
|
7373
|
-
sys_id:
|
|
7374
|
-
name:
|
|
7375
|
-
|
|
7376
|
-
|
|
7390
|
+
sys_id: artifact.sys_id,
|
|
7391
|
+
name: artifact.name || artifact.title,
|
|
7392
|
+
artifact: artifact,
|
|
7393
|
+
table: targetTable,
|
|
7394
|
+
method: 'universal_table_api',
|
|
7395
|
+
search_method: searchField,
|
|
7396
|
+
completenessScore: this.calculateArtifactCompleteness(artifact),
|
|
7397
|
+
metadata: {
|
|
7398
|
+
created_on: artifact.sys_created_on,
|
|
7399
|
+
updated_on: artifact.sys_updated_on,
|
|
7400
|
+
created_by: artifact.sys_created_by,
|
|
7401
|
+
total_found: response.result.length
|
|
7402
|
+
}
|
|
7403
|
+
};
|
|
7404
|
+
}
|
|
7405
|
+
else {
|
|
7406
|
+
this.logger.warn('Universal verification: No results found', {
|
|
7407
|
+
artifactType,
|
|
7408
|
+
table: targetTable,
|
|
7409
|
+
query,
|
|
7410
|
+
response_count: response?.result?.length || 0
|
|
7411
|
+
});
|
|
7412
|
+
return {
|
|
7413
|
+
exists: false,
|
|
7414
|
+
method: 'universal_table_api',
|
|
7415
|
+
search_method: searchField,
|
|
7416
|
+
table: targetTable,
|
|
7417
|
+
debug: {
|
|
7418
|
+
query_used: query,
|
|
7419
|
+
response_count: response?.result?.length || 0,
|
|
7420
|
+
response_structure: response ? 'valid' : 'invalid'
|
|
7421
|
+
}
|
|
7377
7422
|
};
|
|
7378
7423
|
}
|
|
7379
7424
|
}
|
|
7380
7425
|
catch (error) {
|
|
7381
|
-
|
|
7426
|
+
this.logger.error('Universal verification error', {
|
|
7427
|
+
artifactType,
|
|
7428
|
+
table: targetTable,
|
|
7429
|
+
query,
|
|
7430
|
+
error: error.message
|
|
7431
|
+
});
|
|
7432
|
+
throw new Error(`Universal verification failed: ${error.message}`);
|
|
7382
7433
|
}
|
|
7383
|
-
return { exists: false };
|
|
7384
7434
|
}
|
|
7385
7435
|
/**
|
|
7386
|
-
*
|
|
7436
|
+
* Calculate artifact completeness score based on available fields
|
|
7387
7437
|
*/
|
|
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
|
-
|
|
7438
|
+
calculateArtifactCompleteness(artifact) {
|
|
7439
|
+
let score = 0;
|
|
7440
|
+
const maxScore = 100;
|
|
7441
|
+
// Essential fields (25 points each)
|
|
7442
|
+
if (artifact.sys_id)
|
|
7443
|
+
score += 25;
|
|
7444
|
+
if (artifact.name)
|
|
7445
|
+
score += 25;
|
|
7446
|
+
// Important metadata (12.5 points each)
|
|
7447
|
+
if (artifact.sys_created_on)
|
|
7448
|
+
score += 12.5;
|
|
7449
|
+
if (artifact.sys_updated_on)
|
|
7450
|
+
score += 12.5;
|
|
7451
|
+
if (artifact.sys_created_by)
|
|
7452
|
+
score += 12.5;
|
|
7453
|
+
// Additional content indicator (12.5 points)
|
|
7454
|
+
if (artifact.title || artifact.description || artifact.template)
|
|
7455
|
+
score += 12.5;
|
|
7456
|
+
return Math.min(score, maxScore);
|
|
7457
|
+
}
|
|
7458
|
+
/**
|
|
7459
|
+
* Get ServiceNow table name for artifact type
|
|
7460
|
+
*/
|
|
7461
|
+
getTableForArtifactType(artifactType) {
|
|
7462
|
+
const ARTIFACT_TABLES = {
|
|
7463
|
+
'widget': 'sp_widget',
|
|
7464
|
+
'flow': 'sys_hub_flow',
|
|
7465
|
+
'script': 'sys_script_include',
|
|
7466
|
+
'script_include': 'sys_script_include',
|
|
7467
|
+
'business_rule': 'sys_script',
|
|
7468
|
+
'workflow': 'wf_workflow',
|
|
7469
|
+
'application': 'sys_app',
|
|
7470
|
+
'ui_action': 'sys_ui_action',
|
|
7471
|
+
'ui_page': 'sys_ui_page',
|
|
7472
|
+
'processor': 'sys_processor',
|
|
7473
|
+
'portal_page': 'sp_page',
|
|
7474
|
+
'page': 'sp_page',
|
|
7475
|
+
'dashboard': 'sp_page',
|
|
7476
|
+
'report': 'sys_report',
|
|
7477
|
+
'table': 'sys_db_object',
|
|
7478
|
+
'field': 'sys_dictionary',
|
|
7479
|
+
'acl': 'sys_security_acl',
|
|
7480
|
+
'role': 'sys_user_role'
|
|
7481
|
+
};
|
|
7482
|
+
const table = ARTIFACT_TABLES[artifactType.toLowerCase()];
|
|
7483
|
+
if (!table) {
|
|
7484
|
+
this.logger.warn(`Unknown artifact type: ${artifactType}, using sys_metadata as fallback`);
|
|
7485
|
+
return 'sys_metadata';
|
|
7413
7486
|
}
|
|
7414
|
-
return
|
|
7487
|
+
return table;
|
|
7415
7488
|
}
|
|
7416
7489
|
/**
|
|
7417
|
-
*
|
|
7490
|
+
* Universal verification method that can handle all artifact types by sys_id
|
|
7491
|
+
* Especially useful when we know the sys_id from deployment responses
|
|
7418
7492
|
*/
|
|
7419
|
-
async
|
|
7493
|
+
async verifyArtifactBySysId(sys_id, artifactType, table) {
|
|
7494
|
+
// Determine table from artifact type if not provided
|
|
7495
|
+
const targetTable = table || (artifactType ? this.getTableForArtifactType(artifactType) : null);
|
|
7496
|
+
if (!targetTable) {
|
|
7497
|
+
throw new Error('Either table or artifactType must be provided');
|
|
7498
|
+
}
|
|
7420
7499
|
try {
|
|
7421
|
-
|
|
7500
|
+
this.logger.info(`Verifying artifact by sys_id: ${sys_id} in table: ${targetTable}`);
|
|
7422
7501
|
const response = await this.client.makeRequest({
|
|
7423
7502
|
method: 'GET',
|
|
7424
|
-
url:
|
|
7503
|
+
url: `/api/now/table/${targetTable}/${sys_id}`,
|
|
7425
7504
|
params: {
|
|
7426
|
-
|
|
7505
|
+
sysparm_fields: 'sys_id,name,title,sys_created_on,sys_updated_on,sys_created_by,state'
|
|
7427
7506
|
}
|
|
7428
7507
|
});
|
|
7429
7508
|
if (response?.result) {
|
|
7509
|
+
const artifact = response.result;
|
|
7510
|
+
this.logger.info('✅ Sys_id verification SUCCESS', {
|
|
7511
|
+
sys_id: artifact.sys_id,
|
|
7512
|
+
name: artifact.name || artifact.title,
|
|
7513
|
+
table: targetTable,
|
|
7514
|
+
state: artifact.state
|
|
7515
|
+
});
|
|
7430
7516
|
return {
|
|
7431
7517
|
exists: true,
|
|
7432
|
-
sys_id:
|
|
7433
|
-
name:
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
method: '
|
|
7518
|
+
sys_id: artifact.sys_id,
|
|
7519
|
+
name: artifact.name || artifact.title,
|
|
7520
|
+
artifact: artifact,
|
|
7521
|
+
table: targetTable,
|
|
7522
|
+
method: 'universal_sys_id_lookup',
|
|
7523
|
+
completenessScore: this.calculateArtifactCompleteness(artifact),
|
|
7524
|
+
metadata: {
|
|
7525
|
+
created_on: artifact.sys_created_on,
|
|
7526
|
+
updated_on: artifact.sys_updated_on,
|
|
7527
|
+
created_by: artifact.sys_created_by,
|
|
7528
|
+
state: artifact.state
|
|
7529
|
+
}
|
|
7530
|
+
};
|
|
7531
|
+
}
|
|
7532
|
+
else {
|
|
7533
|
+
this.logger.warn('Sys_id verification: Artifact not found', {
|
|
7534
|
+
sys_id,
|
|
7535
|
+
table: targetTable
|
|
7536
|
+
});
|
|
7537
|
+
return {
|
|
7538
|
+
exists: false,
|
|
7539
|
+
method: 'universal_sys_id_lookup',
|
|
7540
|
+
table: targetTable,
|
|
7541
|
+
debug: {
|
|
7542
|
+
sys_id_checked: sys_id,
|
|
7543
|
+
response_structure: 'no_result'
|
|
7544
|
+
}
|
|
7437
7545
|
};
|
|
7438
7546
|
}
|
|
7439
7547
|
}
|
|
7440
7548
|
catch (error) {
|
|
7441
|
-
|
|
7549
|
+
this.logger.error('Sys_id verification error', {
|
|
7550
|
+
sys_id,
|
|
7551
|
+
table: targetTable,
|
|
7552
|
+
error: error.message
|
|
7553
|
+
});
|
|
7554
|
+
throw new Error(`Sys_id verification failed: ${error.message}`);
|
|
7442
7555
|
}
|
|
7443
|
-
return { exists: false };
|
|
7444
7556
|
}
|
|
7445
7557
|
/**
|
|
7446
|
-
* Check if
|
|
7558
|
+
* Check if artifact exists before attempting deployment (Universal)
|
|
7447
7559
|
*/
|
|
7448
|
-
async
|
|
7560
|
+
async checkArtifactExists(artifactType, identifier) {
|
|
7449
7561
|
try {
|
|
7450
|
-
const verificationResult = await this.
|
|
7562
|
+
const verificationResult = await this.universalArtifactVerification(artifactType, identifier);
|
|
7451
7563
|
return {
|
|
7452
7564
|
exists: verificationResult.exists,
|
|
7453
|
-
|
|
7565
|
+
artifact: verificationResult.exists ? verificationResult : undefined
|
|
7454
7566
|
};
|
|
7455
7567
|
}
|
|
7456
7568
|
catch (error) {
|
|
@@ -7458,170 +7570,6 @@ Use individual deployment tools like \`snow_deploy_${args.type}\` with manual co
|
|
|
7458
7570
|
return { exists: false };
|
|
7459
7571
|
}
|
|
7460
7572
|
}
|
|
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
7573
|
/**
|
|
7626
7574
|
* Sleep utility for retry delays
|
|
7627
7575
|
*/
|
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.5",
|
|
4
|
+
"description": "Snow-Flow v3.0.5: UNIVERSAL VERIFICATION SYSTEM! Replaces all artifact-specific endpoints with robust Table API verification. Works universally for widgets, flows, scripts, and all ServiceNow artifacts. Eliminates false positives from missing endpoints. 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": {
|