snow-flow 3.0.9 → 3.0.13
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/claude-flow.bat +0 -0
- package/claude-flow.ps1 +0 -0
- package/dist/mcp/intelligent-reporting-mcp.d.ts +7 -0
- package/dist/mcp/intelligent-reporting-mcp.js +379 -0
- package/dist/mcp/servicenow-automation-mcp.js +0 -0
- package/dist/mcp/servicenow-deployment-mcp.js +0 -0
- package/dist/mcp/servicenow-integration-mcp.js +0 -0
- package/dist/mcp/servicenow-mcp-server.js +0 -0
- package/dist/mcp/servicenow-operations-mcp.js +0 -0
- package/dist/mcp/servicenow-platform-development-mcp.js +0 -0
- package/dist/mcp/servicenow-progressive-indexer.js +0 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.js +280 -29
- package/dist/mcp/servicenow-security-compliance-mcp.js +0 -0
- package/dist/mcp/servicenow-update-set-mcp.js +0 -0
- package/dist/mcp/start-all-mcp-servers.js +0 -0
- package/dist/mcp/start-servicenow-mcp.js +0 -0
- package/dist/services/widget-deployment-service.d.ts +2 -1
- package/dist/services/widget-deployment-service.js +17 -16
- package/dist/utils/anti-mock-data-validator.d.ts +66 -0
- package/dist/utils/anti-mock-data-validator.js +316 -0
- package/dist/utils/servicenow-eventual-consistency.d.ts +120 -0
- package/dist/utils/servicenow-eventual-consistency.js +220 -0
- package/memory/agents/README.md +1 -1
- package/memory/claude-flow-data.json +1 -1
- package/memory/sessions/README.md +1 -1
- package/package.json +4 -3
- package/.mcp.json +0 -22
- package/claude-flow.config.json +0 -20
- package/dist/agents/app-creator.agent.d.ts +0 -55
- package/dist/agents/app-creator.agent.js +0 -1292
- package/dist/agents/base/base-snow-agent.d.ts +0 -75
- package/dist/agents/base/base-snow-agent.js +0 -169
- package/dist/agents/base-snow-agent.d.ts +0 -63
- package/dist/agents/base-snow-agent.js +0 -296
- package/dist/agents/coordinator.d.ts +0 -200
- package/dist/agents/coordinator.js +0 -777
- package/dist/agents/flow-builder-agent.d.ts +0 -18
- package/dist/agents/flow-builder-agent.js +0 -197
- package/dist/agents/queen-403-handler.d.ts +0 -47
- package/dist/agents/queen-403-handler.js +0 -175
- package/dist/agents/queen-agent-example.d.ts +0 -23
- package/dist/agents/queen-agent-example.js +0 -240
- package/dist/agents/queen-agent.test.d.ts +0 -6
- package/dist/agents/script-generator.agent.d.ts +0 -32
- package/dist/agents/script-generator.agent.js +0 -772
- package/dist/agents/script-writer-agent.d.ts +0 -22
- package/dist/agents/script-writer-agent.js +0 -695
- package/dist/agents/security-agent.d.ts +0 -23
- package/dist/agents/security-agent.js +0 -619
- package/dist/agents/specialists/automation-specialist.agent.d.ts +0 -44
- package/dist/agents/specialists/automation-specialist.agent.js +0 -204
- package/dist/agents/specialists/data-specialist.agent.d.ts +0 -165
- package/dist/agents/specialists/data-specialist.agent.js +0 -484
- package/dist/agents/specialists/integration-specialist.agent.d.ts +0 -227
- package/dist/agents/specialists/integration-specialist.agent.js +0 -725
- package/dist/agents/specialists/reporting-specialist.agent.d.ts +0 -54
- package/dist/agents/specialists/reporting-specialist.agent.js +0 -193
- package/dist/agents/specialists/security-specialist.agent.d.ts +0 -85
- package/dist/agents/specialists/security-specialist.agent.js +0 -309
- package/dist/agents/teams/adaptive/adaptive-coordinator.agent.d.ts +0 -111
- package/dist/agents/teams/adaptive/adaptive-coordinator.agent.js +0 -383
- package/dist/agents/teams/base-team.d.ts +0 -72
- package/dist/agents/teams/base-team.js +0 -253
- package/dist/agents/teams/team-types.d.ts +0 -265
- package/dist/agents/teams/team-types.js +0 -3
- package/dist/agents/teams/widget/widget-architect.agent.d.ts +0 -61
- package/dist/agents/teams/widget/widget-architect.agent.js +0 -436
- package/dist/agents/teams/widget/widget-backend.agent.d.ts +0 -74
- package/dist/agents/teams/widget/widget-backend.agent.js +0 -1531
- package/dist/agents/teams/widget/widget-frontend.agent.d.ts +0 -67
- package/dist/agents/teams/widget/widget-frontend.agent.js +0 -1014
- package/dist/agents/teams/widget/widget-platform.agent.d.ts +0 -90
- package/dist/agents/teams/widget/widget-platform.agent.js +0 -1190
- package/dist/agents/teams/widget/widget-uiux.agent.d.ts +0 -107
- package/dist/agents/teams/widget/widget-uiux.agent.js +0 -1033
- package/dist/agents/test-agent.d.ts +0 -26
- package/dist/agents/test-agent.js +0 -734
- package/dist/agents/test-agents.d.ts +0 -7
- package/dist/agents/test-agents.js +0 -64
- package/dist/agents/ui-builder.agent.d.ts +0 -50
- package/dist/agents/ui-builder.agent.js +0 -1539
- package/dist/agents/widget-builder.agent.d.ts +0 -32
- package/dist/agents/widget-builder.agent.js +0 -439
- package/dist/agents/widget-creator-agent.d.ts +0 -18
- package/dist/agents/widget-creator-agent.js +0 -498
- package/dist/agents/workflow-designer.agent.d.ts +0 -31
- package/dist/agents/workflow-designer.agent.js +0 -583
- package/dist/api/error-handling.d.ts +0 -325
- package/dist/api/error-handling.js +0 -1488
- package/dist/api/flow-designer-api.d.ts +0 -167
- package/dist/api/flow-designer-api.js +0 -554
- package/dist/api/natural-language-mapper.d.ts +0 -124
- package/dist/api/natural-language-mapper.js +0 -501
- package/dist/api/performance-optimizer.d.ts +0 -240
- package/dist/api/performance-optimizer.js +0 -706
- package/dist/api/transaction-manager.d.ts +0 -189
- package/dist/api/transaction-manager.js +0 -576
- package/dist/assembly/team-assembler.d.ts +0 -140
- package/dist/assembly/team-assembler.js +0 -502
- package/dist/benchmark-performance.d.ts +0 -41
- package/dist/benchmark-performance.js +0 -230
- package/dist/cli/snow-flow-cli-integration.d.ts +0 -30
- package/dist/cli/snow-flow-cli-integration.js +0 -396
- package/dist/coordination/coordination-engine.d.ts +0 -41
- package/dist/coordination/coordination-engine.js +0 -324
- package/dist/coordination/coordination.test.d.ts +0 -6
- package/dist/coordination/example.d.ts +0 -31
- package/dist/coordination/example.js +0 -394
- package/dist/coordination/execution-patterns.d.ts +0 -43
- package/dist/coordination/execution-patterns.js +0 -507
- package/dist/coordination/factory.d.ts +0 -94
- package/dist/coordination/factory.js +0 -433
- package/dist/coordination/index.d.ts +0 -71
- package/dist/coordination/index.js +0 -135
- package/dist/coordination/progress-monitor.d.ts +0 -71
- package/dist/coordination/progress-monitor.js +0 -505
- package/dist/coordination/quality-gates.d.ts +0 -124
- package/dist/coordination/quality-gates.js +0 -577
- package/dist/coordination/shared-memory.d.ts +0 -39
- package/dist/coordination/shared-memory.js +0 -289
- package/dist/coordination/task-dependencies.d.ts +0 -50
- package/dist/coordination/task-dependencies.js +0 -407
- package/dist/coordination/team-coordinator.d.ts +0 -59
- package/dist/coordination/team-coordinator.js +0 -550
- package/dist/coordination/types.d.ts +0 -152
- package/dist/coordination/types.js +0 -3
- package/dist/mcp/mcp-wrapper.d.ts +0 -8
- package/dist/mcp/mcp-wrapper.js +0 -77
- package/dist/mcp/servicenow-flow-composer-enhanced.js +0 -396
- package/dist/mcp/servicenow-flow-composer-mcp.d.ts +0 -7
- package/dist/mcp/servicenow-flow-composer-mcp.js +0 -3103
- package/dist/mcp/servicenow-graph-memory-mcp.d.ts +0 -7
- package/dist/mcp/servicenow-intelligent-mcp.d.ts +0 -143
- package/dist/mcp/servicenow-intelligent-mcp.js +0 -4156
- package/dist/mcp/servicenow-xml-flow-mcp.d.ts +0 -53
- package/dist/mcp/servicenow-xml-flow-mcp.js +0 -1704
- package/dist/mcp/singleton-check.js +0 -31
- package/dist/mcp/test-simple-mcp.d.ts +0 -6
- package/dist/mcp/test-simple-mcp.js +0 -63
- package/dist/memory/hierarchical-memory-system.d.ts +0 -90
- package/dist/memory/hierarchical-memory-system.js +0 -400
- package/dist/memory/index.d.ts +0 -9
- package/dist/memory/index.js +0 -20
- package/dist/memory/mcp-integration-example.d.ts +0 -6
- package/dist/memory/mcp-integration-example.js +0 -281
- package/dist/memory/memory-client.d.ts +0 -199
- package/dist/memory/memory-client.js +0 -364
- package/dist/memory/memory-manager.d.ts +0 -29
- package/dist/memory/memory-manager.js +0 -280
- package/dist/memory/memory-operations.d.ts +0 -179
- package/dist/memory/memory-operations.js +0 -691
- package/dist/memory/memory-system.d.ts +0 -153
- package/dist/memory/memory-system.js +0 -651
- package/dist/memory/memory-test.d.ts +0 -6
- package/dist/memory/memory-test.js +0 -161
- package/dist/memory/snow-flow-memory-patterns.d.ts +0 -213
- package/dist/memory/snow-flow-memory-patterns.js +0 -200
- package/dist/memory/snow-memory.d.ts +0 -54
- package/dist/memory/snow-memory.js +0 -301
- package/dist/memory/swarm-memory.d.ts +0 -135
- package/dist/memory/swarm-memory.js +0 -378
- package/dist/optimization/flow-performance-optimizer.js +0 -723
- package/dist/orchestration/discovery/service-discovery.d.ts +0 -81
- package/dist/orchestration/discovery/service-discovery.js +0 -808
- package/dist/orchestration/distributed-orchestrator.d.ts +0 -131
- package/dist/orchestration/distributed-orchestrator.js +0 -712
- package/dist/orchestration/distribution/task-distribution-engine.d.ts +0 -53
- package/dist/orchestration/distribution/task-distribution-engine.js +0 -586
- package/dist/orchestration/flow-update-orchestrator.js +0 -648
- package/dist/orchestration/interfaces/distributed-orchestration.interface.d.ts +0 -606
- package/dist/orchestration/interfaces/distributed-orchestration.interface.js +0 -65
- package/dist/orchestration/protocols/mcpx-protocol.d.ts +0 -71
- package/dist/orchestration/protocols/mcpx-protocol.js +0 -668
- package/dist/orchestration/state/distributed-state-manager.d.ts +0 -89
- package/dist/orchestration/state/distributed-state-manager.js +0 -716
- package/dist/orchestrator/flow-composer.d.ts +0 -105
- package/dist/orchestrator/flow-composer.js +0 -404
- package/dist/orchestrator/flow-pattern-templates.d.ts +0 -260
- package/dist/orchestrator/flow-pattern-templates.js +0 -908
- package/dist/orchestrator/flow-subflow-decision-engine.d.ts +0 -202
- package/dist/orchestrator/flow-subflow-decision-engine.js +0 -769
- package/dist/orchestrator/flow-validation-engine.d.ts +0 -169
- package/dist/orchestrator/flow-validation-engine.js +0 -913
- package/dist/orchestrator/snow-orchestrator.d.ts +0 -49
- package/dist/orchestrator/snow-orchestrator.js +0 -235
- package/dist/orchestrator/subflow-creation-handler.d.ts +0 -230
- package/dist/orchestrator/subflow-creation-handler.js +0 -791
- package/dist/patterns/adaptive-patterns.d.ts +0 -140
- package/dist/patterns/adaptive-patterns.js +0 -549
- package/dist/queen/advanced-integration-test.d.ts +0 -48
- package/dist/queen/advanced-integration-test.js +0 -473
- package/dist/queen/integration-example.d.ts +0 -82
- package/dist/queen/integration-example.js +0 -219
- package/dist/queen/integration-test.d.ts +0 -72
- package/dist/queen/integration-test.js +0 -563
- package/dist/queen/mock-mcp-client.d.ts +0 -71
- package/dist/queen/mock-mcp-client.js +0 -317
- package/dist/queen/run-integration-tests.d.ts +0 -9
- package/dist/queen/run-integration-tests.js +0 -27
- package/dist/sparc/coordinators/adaptive-coordinator.d.ts +0 -54
- package/dist/sparc/coordinators/adaptive-coordinator.js +0 -367
- package/dist/sparc/coordinators/team-coordinator.d.ts +0 -66
- package/dist/sparc/coordinators/team-coordinator.js +0 -402
- package/dist/sparc/modes/team-modes.d.ts +0 -33
- package/dist/sparc/modes/team-modes.js +0 -399
- package/dist/sparc/teams/application-team.d.ts +0 -73
- package/dist/sparc/teams/application-team.js +0 -463
- package/dist/sparc/teams/flow-team.d.ts +0 -67
- package/dist/sparc/teams/flow-team.js +0 -373
- package/dist/sparc/teams/widget-team.d.ts +0 -61
- package/dist/sparc/teams/widget-team.js +0 -280
- package/dist/specialists/app-specialists.d.ts +0 -93
- package/dist/specialists/app-specialists.js +0 -1639
- package/dist/specialists/base-specialist.d.ts +0 -19
- package/dist/specialists/base-specialist.js +0 -54
- package/dist/specialists/flow-specialists.d.ts +0 -113
- package/dist/specialists/flow-specialists.js +0 -1787
- package/dist/specialists/individual-specialists.d.ts +0 -67
- package/dist/specialists/individual-specialists.js +0 -632
- package/dist/specialists/widget-specialists.d.ts +0 -70
- package/dist/specialists/widget-specialists.js +0 -1264
- package/dist/src/utils/agent-detector.js +0 -655
- package/dist/teams/adaptive-team.d.ts +0 -81
- package/dist/teams/adaptive-team.js +0 -1153
- package/dist/teams/application-team.d.ts +0 -30
- package/dist/teams/application-team.js +0 -547
- package/dist/teams/base-team.d.ts +0 -55
- package/dist/teams/base-team.js +0 -243
- package/dist/teams/flow-team.d.ts +0 -28
- package/dist/teams/flow-team.js +0 -525
- package/dist/teams/widget-team.d.ts +0 -26
- package/dist/teams/widget-team.js +0 -459
- package/dist/templates/flow-template-system.js +0 -625
- package/dist/test-fetch-incidents.d.ts +0 -2
- package/dist/test-fetch-incidents.js +0 -84
- package/dist/test-incident-access.d.ts +0 -2
- package/dist/test-incident-access.js +0 -72
- package/dist/test-iphone-flow.js +0 -189
- package/dist/test-limit-problem.d.ts +0 -2
- package/dist/test-limit-problem.js +0 -60
- package/dist/test-ml-batch-fix.d.ts +0 -2
- package/dist/test-ml-batch-fix.js +0 -104
- package/dist/test-ml-batch.d.ts +0 -2
- package/dist/test-ml-batch.js +0 -87
- package/dist/test-ml-query.d.ts +0 -2
- package/dist/test-ml-query.js +0 -100
- package/dist/test-ml-training-fix.d.ts +0 -12
- package/dist/test-ml-training-fix.js +0 -113
- package/dist/test-ml-training.d.ts +0 -2
- package/dist/test-ml-training.js +0 -32
- package/dist/test-operations-query.d.ts +0 -2
- package/dist/test-operations-query.js +0 -84
- package/dist/test-performance-query.d.ts +0 -2
- package/dist/test-performance-query.js +0 -52
- package/dist/test-singleton-protection.d.ts +0 -8
- package/dist/test-singleton-protection.js +0 -110
- package/dist/test-smart-limits.d.ts +0 -13
- package/dist/test-smart-limits.js +0 -100
- package/dist/test-snow-query-incidents.d.ts +0 -2
- package/dist/test-snow-query-incidents.js +0 -66
- package/dist/test-universal-query.d.ts +0 -2
- package/dist/test-universal-query.js +0 -106
- package/dist/testing/flow-testing-automation.js +0 -641
- package/dist/utils/complete-flow-xml-generator.js +0 -1285
- package/dist/utils/file-storage-fallback.d.ts +0 -62
- package/dist/utils/file-storage-fallback.js +0 -289
- package/dist/utils/flow-api-discovery.d.ts +0 -151
- package/dist/utils/flow-api-discovery.js +0 -439
- package/dist/utils/flow-examples.js +0 -720
- package/dist/utils/flow-structure-builder.js +0 -677
- package/dist/utils/flow-xml-generator.d.ts +0 -41
- package/dist/utils/flow-xml-generator.js +0 -258
- package/dist/utils/improved-flow-xml-generator.js +0 -820
- package/dist/utils/mcp-process-manager.backup.d.ts +0 -58
- package/dist/utils/mcp-process-manager.backup.js +0 -220
- package/dist/utils/mcp-singleton-enforcer.d.ts +0 -36
- package/dist/utils/mcp-singleton-enforcer.js +0 -201
- package/dist/utils/mcp-timeout-fix.d.ts +0 -53
- package/dist/utils/mcp-timeout-fix.js +0 -221
- package/dist/utils/migrate-claude-flow.d.ts +0 -22
- package/dist/utils/migrate-claude-flow.js +0 -120
- package/dist/utils/scope-utils.d.ts +0 -72
- package/dist/utils/scope-utils.js +0 -386
- package/dist/utils/snow-oauth-old.d.ts +0 -65
- package/dist/utils/snow-oauth-old.js +0 -345
- package/dist/utils/xml-first-flow-generator.js +0 -513
- package/memory/servicenow_artifacts/000d9224c895221055906c7518aa2d3d.json +0 -30
- package/memory/servicenow_artifacts/0196b66173303010e46b4a2214f6a7a2.json +0 -36
- package/memory/servicenow_artifacts/125e5d1d837e2a102a7ea130ceaad397.json +0 -30
- package/memory/servicenow_artifacts/7637c1f2b7112210a5e5911cde11a972.json +0 -30
- package/memory/servicenow_artifacts/default_documentation_tables_1754056582292.json +0 -55
- package/memory/servicenow_artifacts/default_documentation_tables_1754057477189.json +0 -55
- package/memory/update-set-sessions/01f82af583faea102a7ea130ceaad3d4.json +0 -9
- package/memory/update-set-sessions/27718fb983faea102a7ea130ceaad34b.json +0 -9
- package/memory/update-set-sessions/412e9bf6833e22502a7ea130ceaad30a.json +0 -8
- package/memory/update-set-sessions/66fc5a79837aea102a7ea130ceaad3ab.json +0 -9
- package/memory/update-set-sessions/71a30ff5837eea102a7ea130ceaad37f.json +0 -9
- package/memory/update-set-sessions/74fba27983faea102a7ea130ceaad3bd.json +0 -9
- package/memory/update-set-sessions/a0b147b5837eea102a7ea130ceaad344.json +0 -58
- package/memory/update-set-sessions/b13f5eb983baea102a7ea130ceaad33e.json +0 -9
- package/reports/swarm-auto-centralized-1752649029776.json +0 -13
- package/src/memory/README.md +0 -240
|
@@ -1,3103 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/**
|
|
4
|
-
* ServiceNow Flow Composer MCP Server
|
|
5
|
-
* Natural language flow creation with multi-artifact orchestration
|
|
6
|
-
*/
|
|
7
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
-
if (k2 === undefined) k2 = k;
|
|
9
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
-
}
|
|
13
|
-
Object.defineProperty(o, k2, desc);
|
|
14
|
-
}) : (function(o, m, k, k2) {
|
|
15
|
-
if (k2 === undefined) k2 = k;
|
|
16
|
-
o[k2] = m[k];
|
|
17
|
-
}));
|
|
18
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
-
}) : function(o, v) {
|
|
21
|
-
o["default"] = v;
|
|
22
|
-
});
|
|
23
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
-
var ownKeys = function(o) {
|
|
25
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
-
var ar = [];
|
|
27
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
-
return ar;
|
|
29
|
-
};
|
|
30
|
-
return ownKeys(o);
|
|
31
|
-
};
|
|
32
|
-
return function (mod) {
|
|
33
|
-
if (mod && mod.__esModule) return mod;
|
|
34
|
-
var result = {};
|
|
35
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
-
__setModuleDefault(result, mod);
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
})();
|
|
40
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
42
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
43
|
-
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
44
|
-
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
45
|
-
const snow_oauth_js_1 = require("../utils/snow-oauth.js");
|
|
46
|
-
const logger_js_1 = require("../utils/logger.js");
|
|
47
|
-
const flow_composer_js_1 = require("../orchestrator/flow-composer.js");
|
|
48
|
-
const complete_flow_xml_generator_js_1 = require("../utils/complete-flow-xml-generator.js");
|
|
49
|
-
const update_set_importer_js_1 = require("../utils/update-set-importer.js");
|
|
50
|
-
const mcp_tool_registry_js_1 = require("../utils/mcp-tool-registry.js");
|
|
51
|
-
const deployment_metadata_handler_js_1 = require("../utils/deployment-metadata-handler.js");
|
|
52
|
-
class ServiceNowFlowComposerMCP {
|
|
53
|
-
constructor() {
|
|
54
|
-
this.server = new index_js_1.Server({
|
|
55
|
-
name: 'servicenow-flow-composer-enhanced',
|
|
56
|
-
version: '2.0.0',
|
|
57
|
-
description: 'Enhanced Flow Composer with Complete Solution - Fixes all critical issues: empty flows, tool registry mapping, and metadata failures',
|
|
58
|
-
}, {
|
|
59
|
-
capabilities: {
|
|
60
|
-
tools: {},
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
this.client = new servicenow_client_js_1.ServiceNowClient();
|
|
64
|
-
this.oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
65
|
-
this.logger = new logger_js_1.Logger('ServiceNowFlowComposerMCP');
|
|
66
|
-
this.composer = new flow_composer_js_1.EnhancedFlowComposer();
|
|
67
|
-
this.setupHandlers();
|
|
68
|
-
}
|
|
69
|
-
setupHandlers() {
|
|
70
|
-
this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
71
|
-
tools: [
|
|
72
|
-
{
|
|
73
|
-
name: 'snow_create_flow',
|
|
74
|
-
description: '🚀 ENHANCED FLOW TOOL v2.0 - Creates COMPLETE flows with ALL features working! Uses CompleteFlowXMLGenerator for proper v2 tables, Base64+gzip encoding, and full metadata. Fixes all deployment issues. ZERO MANUAL STEPS!',
|
|
75
|
-
inputSchema: {
|
|
76
|
-
type: 'object',
|
|
77
|
-
properties: {
|
|
78
|
-
instruction: {
|
|
79
|
-
type: 'string',
|
|
80
|
-
description: 'Natural language instruction for the flow (e.g., "maak een flow waarbij we het script include gebruiken waar we de localizatie met LLMs gebruiken om dan de berichten van het support desk mee te vertalen naar engels en deze op te slaan in een tabel aan de hand van een business rule")'
|
|
81
|
-
},
|
|
82
|
-
deploy_immediately: {
|
|
83
|
-
type: 'boolean',
|
|
84
|
-
description: '⚠️ DEPLOYMENT MODE - true: Deploy REAL flow to ServiceNow immediately | false: Planning mode only',
|
|
85
|
-
default: true
|
|
86
|
-
},
|
|
87
|
-
create_missing_artifacts: {
|
|
88
|
-
type: 'boolean',
|
|
89
|
-
description: 'Create missing artifacts as fallbacks',
|
|
90
|
-
default: true
|
|
91
|
-
},
|
|
92
|
-
scope_preference: {
|
|
93
|
-
type: 'string',
|
|
94
|
-
enum: ['global', 'application', 'auto'],
|
|
95
|
-
description: 'Preferred deployment scope',
|
|
96
|
-
default: 'auto'
|
|
97
|
-
},
|
|
98
|
-
enable_intelligent_analysis: {
|
|
99
|
-
type: 'boolean',
|
|
100
|
-
description: 'Enable intelligent flow vs subflow analysis',
|
|
101
|
-
default: true
|
|
102
|
-
},
|
|
103
|
-
validation_level: {
|
|
104
|
-
type: 'string',
|
|
105
|
-
enum: ['basic', 'standard', 'comprehensive'],
|
|
106
|
-
description: 'Level of validation to perform',
|
|
107
|
-
default: 'standard'
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
required: ['instruction'],
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
name: 'snow_analyze_flow_instruction',
|
|
115
|
-
description: 'AUTONOMOUS analysis - understands complex requirements, identifies all needed artifacts, plans optimal flow structure. SELF-LEARNING from patterns.',
|
|
116
|
-
inputSchema: {
|
|
117
|
-
type: 'object',
|
|
118
|
-
properties: {
|
|
119
|
-
instruction: {
|
|
120
|
-
type: 'string',
|
|
121
|
-
description: 'Natural language instruction to analyze'
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
required: ['instruction'],
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: 'snow_discover_flow_artifacts',
|
|
129
|
-
description: 'AUTONOMOUS discovery - finds all required artifacts, creates missing ones, ensures compatibility. INTELLIGENT DEPENDENCY RESOLUTION!',
|
|
130
|
-
inputSchema: {
|
|
131
|
-
type: 'object',
|
|
132
|
-
properties: {
|
|
133
|
-
instruction: {
|
|
134
|
-
type: 'string',
|
|
135
|
-
description: 'Natural language instruction'
|
|
136
|
-
},
|
|
137
|
-
artifact_types: {
|
|
138
|
-
type: 'array',
|
|
139
|
-
items: {
|
|
140
|
-
type: 'string',
|
|
141
|
-
enum: ['script_include', 'business_rule', 'table', 'widget', 'ui_script']
|
|
142
|
-
},
|
|
143
|
-
description: 'Specific artifact types to search for'
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
required: ['instruction'],
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
name: 'snow_preview_flow_structure',
|
|
151
|
-
description: 'Preview the flow structure before deployment',
|
|
152
|
-
inputSchema: {
|
|
153
|
-
type: 'object',
|
|
154
|
-
properties: {
|
|
155
|
-
instruction: {
|
|
156
|
-
type: 'string',
|
|
157
|
-
description: 'Natural language instruction'
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
required: ['instruction'],
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
name: 'snow_deploy_composed_flow',
|
|
165
|
-
description: 'Deploy a previously composed flow with all its artifacts',
|
|
166
|
-
inputSchema: {
|
|
167
|
-
type: 'object',
|
|
168
|
-
properties: {
|
|
169
|
-
flow_instruction: {
|
|
170
|
-
type: 'object',
|
|
171
|
-
description: 'Previously composed flow instruction object'
|
|
172
|
-
},
|
|
173
|
-
validation_required: {
|
|
174
|
-
type: 'boolean',
|
|
175
|
-
description: 'Validate all artifacts before deployment',
|
|
176
|
-
default: true
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
required: ['flow_instruction'],
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
name: 'snow_intelligent_flow_analysis',
|
|
184
|
-
description: 'INTELLIGENT ANALYSIS - Performs comprehensive flow vs subflow analysis with decision rationale and recommendations',
|
|
185
|
-
inputSchema: {
|
|
186
|
-
type: 'object',
|
|
187
|
-
properties: {
|
|
188
|
-
instruction: {
|
|
189
|
-
type: 'string',
|
|
190
|
-
description: 'Natural language instruction to analyze'
|
|
191
|
-
},
|
|
192
|
-
include_templates: {
|
|
193
|
-
type: 'boolean',
|
|
194
|
-
description: 'Include template matching analysis',
|
|
195
|
-
default: true
|
|
196
|
-
},
|
|
197
|
-
include_validation: {
|
|
198
|
-
type: 'boolean',
|
|
199
|
-
description: 'Include validation analysis',
|
|
200
|
-
default: true
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
required: ['instruction'],
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
name: 'snow_scope_optimization',
|
|
208
|
-
description: 'SCOPE OPTIMIZATION - Analyzes and recommends optimal deployment scope with fallback strategies',
|
|
209
|
-
inputSchema: {
|
|
210
|
-
type: 'object',
|
|
211
|
-
properties: {
|
|
212
|
-
artifact_type: {
|
|
213
|
-
type: 'string',
|
|
214
|
-
description: 'Type of artifact to analyze'
|
|
215
|
-
},
|
|
216
|
-
artifact_data: {
|
|
217
|
-
type: 'object',
|
|
218
|
-
description: 'Artifact data for analysis'
|
|
219
|
-
},
|
|
220
|
-
environment_type: {
|
|
221
|
-
type: 'string',
|
|
222
|
-
enum: ['development', 'testing', 'production'],
|
|
223
|
-
description: 'Target environment type',
|
|
224
|
-
default: 'development'
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
required: ['artifact_type', 'artifact_data'],
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
name: 'snow_template_matching',
|
|
232
|
-
description: 'TEMPLATE MATCHING - Finds and applies best matching flow templates for common patterns',
|
|
233
|
-
inputSchema: {
|
|
234
|
-
type: 'object',
|
|
235
|
-
properties: {
|
|
236
|
-
instruction: {
|
|
237
|
-
type: 'string',
|
|
238
|
-
description: 'Natural language instruction'
|
|
239
|
-
},
|
|
240
|
-
template_categories: {
|
|
241
|
-
type: 'array',
|
|
242
|
-
items: {
|
|
243
|
-
type: 'string',
|
|
244
|
-
enum: ['approval', 'fulfillment', 'notification', 'integration', 'utility']
|
|
245
|
-
},
|
|
246
|
-
description: 'Template categories to search'
|
|
247
|
-
},
|
|
248
|
-
minimum_confidence: {
|
|
249
|
-
type: 'number',
|
|
250
|
-
description: 'Minimum confidence threshold for template matching',
|
|
251
|
-
default: 0.6
|
|
252
|
-
},
|
|
253
|
-
},
|
|
254
|
-
required: ['instruction'],
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
name: 'snow_performance_analysis',
|
|
259
|
-
description: '🚀 BUG-007 FIX: PERFORMANCE ANALYSIS - Analyzes flows for performance bottlenecks and provides database index recommendations',
|
|
260
|
-
inputSchema: {
|
|
261
|
-
type: 'object',
|
|
262
|
-
properties: {
|
|
263
|
-
flow_definition: {
|
|
264
|
-
type: 'object',
|
|
265
|
-
description: 'Flow definition to analyze for performance'
|
|
266
|
-
},
|
|
267
|
-
table_name: {
|
|
268
|
-
type: 'string',
|
|
269
|
-
description: 'Specific table to analyze (optional)'
|
|
270
|
-
},
|
|
271
|
-
include_database_indexes: {
|
|
272
|
-
type: 'boolean',
|
|
273
|
-
description: 'Include database index recommendations',
|
|
274
|
-
default: true
|
|
275
|
-
},
|
|
276
|
-
include_code_analysis: {
|
|
277
|
-
type: 'boolean',
|
|
278
|
-
description: 'Include flow script performance analysis',
|
|
279
|
-
default: true
|
|
280
|
-
},
|
|
281
|
-
detailed_report: {
|
|
282
|
-
type: 'boolean',
|
|
283
|
-
description: 'Generate detailed performance report',
|
|
284
|
-
default: false
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
required: ['flow_definition'],
|
|
288
|
-
},
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
name: 'snow_comprehensive_requirements_analysis',
|
|
292
|
-
description: '🚀 BUG-006 FIX: MULTI-PASS REQUIREMENTS ANALYSIS - Comprehensive 4-pass analysis to ensure no requirements are missed',
|
|
293
|
-
inputSchema: {
|
|
294
|
-
type: 'object',
|
|
295
|
-
properties: {
|
|
296
|
-
objective: {
|
|
297
|
-
type: 'string',
|
|
298
|
-
description: 'The objective or requirement to analyze comprehensively (e.g., "iPhone provisioning workflow for new employees")'
|
|
299
|
-
},
|
|
300
|
-
include_dependencies: {
|
|
301
|
-
type: 'boolean',
|
|
302
|
-
description: 'Include dependency analysis (pass 2)',
|
|
303
|
-
default: true
|
|
304
|
-
},
|
|
305
|
-
include_context_analysis: {
|
|
306
|
-
type: 'boolean',
|
|
307
|
-
description: 'Include context and implication analysis (pass 3)',
|
|
308
|
-
default: true
|
|
309
|
-
},
|
|
310
|
-
include_validation: {
|
|
311
|
-
type: 'boolean',
|
|
312
|
-
description: 'Include validation and completeness check (pass 4)',
|
|
313
|
-
default: true
|
|
314
|
-
},
|
|
315
|
-
detailed_report: {
|
|
316
|
-
type: 'boolean',
|
|
317
|
-
description: 'Generate detailed multi-pass analysis report',
|
|
318
|
-
default: false
|
|
319
|
-
}
|
|
320
|
-
},
|
|
321
|
-
required: ['objective'],
|
|
322
|
-
},
|
|
323
|
-
},
|
|
324
|
-
],
|
|
325
|
-
}));
|
|
326
|
-
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
327
|
-
const { name, arguments: args } = request.params;
|
|
328
|
-
try {
|
|
329
|
-
switch (name) {
|
|
330
|
-
case 'snow_create_flow':
|
|
331
|
-
return await this.createFlow(args);
|
|
332
|
-
case 'snow_analyze_flow_instruction':
|
|
333
|
-
return await this.analyzeFlowInstruction(args);
|
|
334
|
-
case 'snow_discover_flow_artifacts':
|
|
335
|
-
return await this.discoverFlowArtifacts(args);
|
|
336
|
-
case 'snow_preview_flow_structure':
|
|
337
|
-
return await this.previewFlowStructure(args);
|
|
338
|
-
case 'snow_deploy_composed_flow':
|
|
339
|
-
return await this.deployComposedFlow(args);
|
|
340
|
-
case 'snow_intelligent_flow_analysis':
|
|
341
|
-
return await this.intelligentFlowAnalysis(args);
|
|
342
|
-
case 'snow_scope_optimization':
|
|
343
|
-
return await this.scopeOptimization(args);
|
|
344
|
-
case 'snow_template_matching':
|
|
345
|
-
return await this.templateMatching(args);
|
|
346
|
-
case 'snow_performance_analysis':
|
|
347
|
-
return await this.performanceAnalysis(args);
|
|
348
|
-
case 'snow_comprehensive_requirements_analysis':
|
|
349
|
-
return await this.comprehensiveRequirementsAnalysis(args);
|
|
350
|
-
default:
|
|
351
|
-
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
catch (error) {
|
|
355
|
-
this.logger.error(`Tool execution failed: ${name}`, error);
|
|
356
|
-
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, error instanceof Error ? error.message : String(error));
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
async createFlow(args) {
|
|
361
|
-
console.log('🎯 INTELLIGENT FLOW CREATION STARTED');
|
|
362
|
-
console.log('📝 Instruction:', args.instruction);
|
|
363
|
-
// Input validation
|
|
364
|
-
if (!args.instruction || typeof args.instruction !== 'string' || args.instruction.trim().length === 0) {
|
|
365
|
-
return {
|
|
366
|
-
content: [
|
|
367
|
-
{
|
|
368
|
-
type: 'text',
|
|
369
|
-
text: '❌ Invalid Input: Instruction is required and must be a non-empty string.\n\nPlease provide a clear, descriptive instruction for your flow.',
|
|
370
|
-
},
|
|
371
|
-
],
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
if (args.instruction.length > 2000) {
|
|
375
|
-
return {
|
|
376
|
-
content: [
|
|
377
|
-
{
|
|
378
|
-
type: 'text',
|
|
379
|
-
text: '❌ Invalid Input: Instruction is too long (maximum 2000 characters).\n\nPlease provide a more concise instruction.',
|
|
380
|
-
},
|
|
381
|
-
],
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
// Check authentication first
|
|
385
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
386
|
-
if (!isAuth) {
|
|
387
|
-
return {
|
|
388
|
-
content: [
|
|
389
|
-
{
|
|
390
|
-
type: 'text',
|
|
391
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
392
|
-
},
|
|
393
|
-
],
|
|
394
|
-
};
|
|
395
|
-
}
|
|
396
|
-
try {
|
|
397
|
-
this.logger.info('🧠 Starting intelligent flow creation', { instruction: args.instruction });
|
|
398
|
-
// 🧠 STEP 1: Parse natural language instruction intelligently
|
|
399
|
-
const parsedIntent = await this.parseFlowInstruction(args.instruction);
|
|
400
|
-
console.log('🧠 Parsed intent:', parsedIntent);
|
|
401
|
-
// 🧠 STEP 2: Find matching templates based on intent
|
|
402
|
-
const templateMatch = await this.findBestTemplate(parsedIntent);
|
|
403
|
-
console.log('🧠 Template match:', templateMatch);
|
|
404
|
-
// 🧠 STEP 3: Discover required artifacts
|
|
405
|
-
const artifacts = await this.discoverRequiredArtifacts(parsedIntent);
|
|
406
|
-
console.log('🧠 Discovered artifacts:', artifacts);
|
|
407
|
-
// 🧠 STEP 4: Generate complete flow definition
|
|
408
|
-
const flowDefinition = await this.generateFlowDefinition(parsedIntent, templateMatch, artifacts);
|
|
409
|
-
console.log('🧠 Generated flow definition:', JSON.stringify(flowDefinition, null, 2));
|
|
410
|
-
// 🧠 STEP 5: Deploy using XML-first approach for maximum reliability
|
|
411
|
-
let deploymentResult = null;
|
|
412
|
-
let xmlResult = null; // 🔴 FIX: Declare outside try block to avoid scope issues
|
|
413
|
-
let performanceAnalysis = null; // 🚀 BUG-007 FIX: Performance analysis results
|
|
414
|
-
if (args.deploy_immediately !== false) {
|
|
415
|
-
console.log('🚀 DEPLOYING flow using XML-first approach...');
|
|
416
|
-
try {
|
|
417
|
-
// 🚀 ENHANCED: Use CompleteFlowXMLGenerator for proper flow generation
|
|
418
|
-
// 🔒 BUG-004 FIX: Apply SECURE DEFAULTS - NEVER allow public access by default
|
|
419
|
-
const SECURE_FLOW_DEFAULTS = {
|
|
420
|
-
run_as: 'user', // Always run as user, not system
|
|
421
|
-
accessible_from: 'package_private', // NEVER public by default
|
|
422
|
-
requires_authentication: true,
|
|
423
|
-
requires_role: true
|
|
424
|
-
};
|
|
425
|
-
// Convert to CompleteFlowDefinition format with ENFORCED secure defaults
|
|
426
|
-
const completeFlowDef = {
|
|
427
|
-
name: parsedIntent.flowName,
|
|
428
|
-
description: parsedIntent.description,
|
|
429
|
-
table: parsedIntent.table,
|
|
430
|
-
trigger_type: this.mapTriggerTypeToXML(parsedIntent.trigger.type),
|
|
431
|
-
trigger_condition: parsedIntent.trigger.condition || '',
|
|
432
|
-
activities: this.convertActivitiesToCompleteFormat(flowDefinition.activities || []),
|
|
433
|
-
// 🛡️ SECURITY: These defaults CANNOT be overridden accidentally
|
|
434
|
-
run_as: SECURE_FLOW_DEFAULTS.run_as,
|
|
435
|
-
accessible_from: SECURE_FLOW_DEFAULTS.accessible_from,
|
|
436
|
-
category: 'custom',
|
|
437
|
-
tags: ['auto-generated', 'enhanced']
|
|
438
|
-
};
|
|
439
|
-
// 🔒 Log security configuration for audit trail
|
|
440
|
-
this.logger.info('🛡️ Applying secure flow defaults', {
|
|
441
|
-
flowName: parsedIntent.flowName,
|
|
442
|
-
accessible_from: completeFlowDef.accessible_from,
|
|
443
|
-
run_as: completeFlowDef.run_as,
|
|
444
|
-
table: completeFlowDef.table,
|
|
445
|
-
trigger_type: completeFlowDef.trigger_type
|
|
446
|
-
});
|
|
447
|
-
console.log('🔒 SECURITY: Flow created with secure defaults:');
|
|
448
|
-
console.log(` • Access Level: ${completeFlowDef.accessible_from} (secure)`);
|
|
449
|
-
console.log(` • Run As: ${completeFlowDef.run_as} (secure)`);
|
|
450
|
-
console.log(` • Authentication: Required`);
|
|
451
|
-
console.log(` • Role-based Access: Required`);
|
|
452
|
-
// Generate production-ready XML with CompleteFlowXMLGenerator
|
|
453
|
-
xmlResult = (0, complete_flow_xml_generator_js_1.generateCompleteFlowXML)(completeFlowDef);
|
|
454
|
-
console.log('✅ XML generated:', xmlResult.filePath);
|
|
455
|
-
// 🚀 BUG-007 FIX: Performance analysis and recommendations
|
|
456
|
-
const { PerformanceRecommendationsEngine } = await Promise.resolve().then(() => __importStar(require('../intelligence/performance-recommendations-engine.js')));
|
|
457
|
-
const performanceEngine = new PerformanceRecommendationsEngine();
|
|
458
|
-
console.log('🔍 Running performance analysis...');
|
|
459
|
-
performanceAnalysis = await performanceEngine.analyzeFlowPerformance(xmlFlowDef);
|
|
460
|
-
if (performanceAnalysis.summary.criticalIssues > 0) {
|
|
461
|
-
console.log(`⚠️ PERFORMANCE: ${performanceAnalysis.summary.criticalIssues} critical issues found`);
|
|
462
|
-
console.log(`📈 Potential improvement: ${performanceAnalysis.summary.estimatedImprovementPercent}%`);
|
|
463
|
-
// Show top 3 most critical recommendations
|
|
464
|
-
const topRecommendations = [
|
|
465
|
-
...performanceAnalysis.databaseIndexes.filter(idx => idx.priority === 'critical').slice(0, 2),
|
|
466
|
-
...performanceAnalysis.performanceRecommendations.filter(rec => rec.impact === 'high').slice(0, 1)
|
|
467
|
-
];
|
|
468
|
-
if (topRecommendations.length > 0) {
|
|
469
|
-
console.log('🎯 Top performance recommendations:');
|
|
470
|
-
topRecommendations.forEach((rec, i) => {
|
|
471
|
-
if ('fields' in rec) {
|
|
472
|
-
// Database index recommendation
|
|
473
|
-
console.log(` ${i + 1}. INDEX: ${rec.table} (${rec.fields.join(', ')}) - ${rec.reason}`);
|
|
474
|
-
console.log(` 💻 ${rec.createStatement}`);
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
// Performance recommendation
|
|
478
|
-
console.log(` ${i + 1}. ${rec.type.toUpperCase()}: ${rec.description}`);
|
|
479
|
-
console.log(` 💡 ${rec.recommendation}`);
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
console.log('✅ Performance analysis: No critical issues detected');
|
|
486
|
-
}
|
|
487
|
-
// 🔴 CRITICAL FIX: Auto-deploy with INTEGRATED verification
|
|
488
|
-
// SNOW-001: Verification is now MANDATORY within each deployment strategy
|
|
489
|
-
const deployResult = await this.deployWithFallback(xmlResult.filePath, flowDefinition);
|
|
490
|
-
// 🔴 FIXED: No duplicate verification needed - it's integrated into deployment strategies
|
|
491
|
-
// deployResult.verification contains the comprehensive verification results
|
|
492
|
-
// Success with integrated verification
|
|
493
|
-
deploymentResult = {
|
|
494
|
-
success: true,
|
|
495
|
-
method: deployResult.strategy,
|
|
496
|
-
xml_file: xmlResult.filePath,
|
|
497
|
-
message: `✅ Flow deployed via ${deployResult.strategy} and verified in ServiceNow!`,
|
|
498
|
-
flow_sys_id: deployResult.verification.sys_id,
|
|
499
|
-
flow_url: deployResult.verification.url,
|
|
500
|
-
verification_score: deployResult.verification.completeness_score,
|
|
501
|
-
verification_details: {
|
|
502
|
-
has_flow: true,
|
|
503
|
-
has_snapshot: deployResult.verification.has_snapshot,
|
|
504
|
-
has_trigger: deployResult.verification.has_trigger,
|
|
505
|
-
attempts_needed: deployResult.verification.verification_attempt,
|
|
506
|
-
deployment_verified: deployResult.deployment_verified
|
|
507
|
-
},
|
|
508
|
-
snow_001_fix: 'Deployment includes mandatory verification - no false positives possible'
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
catch (xmlError) {
|
|
512
|
-
console.error('❌ XML deployment failed:', xmlError);
|
|
513
|
-
// Extract detailed error information
|
|
514
|
-
let errorDetails = 'Unknown error';
|
|
515
|
-
if (xmlError instanceof Error) {
|
|
516
|
-
errorDetails = xmlError.message;
|
|
517
|
-
// Check for specific error types
|
|
518
|
-
if (xmlError.message.includes('400')) {
|
|
519
|
-
errorDetails = 'ServiceNow rejected the request. Check permissions and Update Set.';
|
|
520
|
-
}
|
|
521
|
-
else if (xmlError.message.includes('401') || xmlError.message.includes('403')) {
|
|
522
|
-
errorDetails = 'Authentication failed. Run: snow-flow auth login';
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
deploymentResult = {
|
|
526
|
-
success: false,
|
|
527
|
-
error: errorDetails,
|
|
528
|
-
xml_generated: xmlResult !== null, // 🔴 FIX: Check if XML was actually generated
|
|
529
|
-
xml_path: xmlResult?.filePath,
|
|
530
|
-
deployment_failed: true,
|
|
531
|
-
manual_steps: this.generateManualImportGuide(xmlResult?.filePath || ''),
|
|
532
|
-
fallback_instructions: 'Use snow-flow deploy-xml command for manual deployment'
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
const credentials = await this.oauth.loadCredentials();
|
|
537
|
-
const flowUrl = `https://${credentials?.instance}/flow-designer/flow/${parsedIntent.flowName}`;
|
|
538
|
-
// 🔴 BUG-001 FIX: Return structured data with sys_id and all identifiers
|
|
539
|
-
const flowSysId = deploymentResult?.verification?.sys_id || deploymentResult?.sys_id || null;
|
|
540
|
-
const actualFlowUrl = flowSysId ?
|
|
541
|
-
`https://${credentials?.instance}/flow-designer/designer/${flowSysId}` :
|
|
542
|
-
flowUrl;
|
|
543
|
-
const structuredResult = {
|
|
544
|
-
success: deploymentResult?.success || false,
|
|
545
|
-
flow: {
|
|
546
|
-
sys_id: flowSysId,
|
|
547
|
-
name: parsedIntent.flowName,
|
|
548
|
-
table: parsedIntent.table,
|
|
549
|
-
trigger_type: parsedIntent.trigger.type,
|
|
550
|
-
active: true,
|
|
551
|
-
description: parsedIntent.description,
|
|
552
|
-
url: actualFlowUrl,
|
|
553
|
-
api_endpoint: flowSysId ?
|
|
554
|
-
`https://${credentials?.instance}/api/now/table/sys_hub_flow/${flowSysId}` : null
|
|
555
|
-
},
|
|
556
|
-
deployment: {
|
|
557
|
-
method: deploymentResult?.deployment_method || 'XML Update Set',
|
|
558
|
-
xml_file: xmlResult?.file || deploymentResult?.xml_path || null,
|
|
559
|
-
update_set_id: deploymentResult?.update_set_id || null,
|
|
560
|
-
success: deploymentResult?.success || false,
|
|
561
|
-
error: deploymentResult?.error || null
|
|
562
|
-
},
|
|
563
|
-
analysis: {
|
|
564
|
-
intents: parsedIntent.intents,
|
|
565
|
-
template: templateMatch?.name || 'Custom implementation',
|
|
566
|
-
confidence: templateMatch?.confidence || 0,
|
|
567
|
-
activities_count: flowDefinition.activities?.length || 0,
|
|
568
|
-
variables_count: flowDefinition.variables?.length || 0
|
|
569
|
-
},
|
|
570
|
-
// 🚀 BUG-007 FIX: Performance analysis results
|
|
571
|
-
performance: {
|
|
572
|
-
database_indexes: performanceAnalysis?.databaseIndexes || [],
|
|
573
|
-
recommendations: performanceAnalysis?.performanceRecommendations || [],
|
|
574
|
-
summary: {
|
|
575
|
-
critical_issues: performanceAnalysis?.summary?.criticalIssues || 0,
|
|
576
|
-
estimated_improvement_percent: performanceAnalysis?.summary?.estimatedImprovementPercent || 0,
|
|
577
|
-
top_actions: performanceAnalysis?.summary?.recommendedActions || []
|
|
578
|
-
},
|
|
579
|
-
report_available: true
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
// Log structured result for debugging
|
|
583
|
-
this.logger.info('🔴 BUG-001 FIX: Returning structured flow data', structuredResult);
|
|
584
|
-
return {
|
|
585
|
-
content: [
|
|
586
|
-
{
|
|
587
|
-
type: 'text',
|
|
588
|
-
text: deploymentResult?.success ?
|
|
589
|
-
`✅ FLOW SUCCESSFULLY CREATED AND DEPLOYED!
|
|
590
|
-
|
|
591
|
-
🚀 **VERIFIED DEPLOYMENT** - Flow is now live in ServiceNow!
|
|
592
|
-
|
|
593
|
-
🆔 **Flow Identifiers** (BUG-001 FIX):
|
|
594
|
-
- **Sys ID**: ${structuredResult.flow.sys_id}
|
|
595
|
-
- **Name**: ${structuredResult.flow.name}
|
|
596
|
-
- **API Endpoint**: ${structuredResult.flow.api_endpoint}
|
|
597
|
-
|
|
598
|
-
🔗 **Direct Access**: ${structuredResult.flow.url}` :
|
|
599
|
-
deploymentResult?.deployment_failed ?
|
|
600
|
-
`⚠️ FLOW XML GENERATED BUT DEPLOYMENT FAILED
|
|
601
|
-
|
|
602
|
-
❌ **Deployment Error**: ${deploymentResult.error}
|
|
603
|
-
|
|
604
|
-
🆔 **Flow Details** (BUG-001 FIX):
|
|
605
|
-
- **Name**: ${structuredResult.flow.name}
|
|
606
|
-
- **Table**: ${structuredResult.flow.table}
|
|
607
|
-
- **Sys ID**: ${structuredResult.flow.sys_id || 'Not yet available'}
|
|
608
|
-
|
|
609
|
-
📁 **XML File**: ${deploymentResult.xml_path}
|
|
610
|
-
|
|
611
|
-
📋 **Manual Import Steps**:
|
|
612
|
-
${deploymentResult.manual_steps || '1. Navigate to System Update Sets > Retrieved Update Sets\n2. Import Update Set from XML\n3. Preview and Commit'}` :
|
|
613
|
-
`🎯 FLOW CREATED WITH XML-FIRST APPROACH!
|
|
614
|
-
|
|
615
|
-
${args.deploy_immediately !== false ? `🚀 **DEPLOYMENT STATUS** - Processing...` : `📋 **PLANNING MODE** - Flow structure generated`}
|
|
616
|
-
|
|
617
|
-
🆔 **Flow Identifiers** (BUG-001 FIX):
|
|
618
|
-
- **Sys ID**: ${structuredResult.flow.sys_id || 'Pending deployment'}
|
|
619
|
-
- **Name**: ${structuredResult.flow.name}
|
|
620
|
-
- **Table**: ${structuredResult.flow.table}
|
|
621
|
-
- **API Endpoint**: ${structuredResult.flow.api_endpoint || 'Not yet available'}
|
|
622
|
-
|
|
623
|
-
🧠 **Intelligent Analysis:**
|
|
624
|
-
- **Flow Name**: ${parsedIntent.flowName}
|
|
625
|
-
- **Primary Table**: ${parsedIntent.table}
|
|
626
|
-
- **Trigger Type**: ${parsedIntent.trigger.type}
|
|
627
|
-
- **Intent Categories**: ${parsedIntent.intents.join(', ')}
|
|
628
|
-
- **Template Match**: ${templateMatch?.name || 'Custom implementation'}
|
|
629
|
-
- **Confidence**: ${templateMatch?.confidence ? Math.round(templateMatch.confidence * 100) + '%' : 'N/A'}
|
|
630
|
-
|
|
631
|
-
📋 **Flow Structure:**
|
|
632
|
-
- **Activities**: ${flowDefinition.activities?.length || 0} intelligent actions
|
|
633
|
-
- **Variables**: ${flowDefinition.variables?.length || 0} dynamic inputs/outputs
|
|
634
|
-
- **Error Handling**: ${flowDefinition.error_handling?.length || 0} safety measures
|
|
635
|
-
- **Artifacts Used**: ${artifacts.existing.length} found, ${artifacts.created.length} created
|
|
636
|
-
|
|
637
|
-
🚀 **XML-First Deployment:**
|
|
638
|
-
${deploymentResult ? (deploymentResult.success ?
|
|
639
|
-
`✅ Successfully deployed using XML-first approach!
|
|
640
|
-
- **Method**: Production-ready Update Set XML
|
|
641
|
-
- **XML File**: ${deploymentResult.xml_file}
|
|
642
|
-
- **Status**: Imported → Previewed → Committed ✅` :
|
|
643
|
-
`❌ Auto-deployment failed: ${deploymentResult.error}
|
|
644
|
-
- **Fallback**: ${deploymentResult.fallback_instructions}`) : '⏳ Ready for deployment'}
|
|
645
|
-
|
|
646
|
-
🔗 **ServiceNow Access:**
|
|
647
|
-
- Flow Designer: ${actualFlowUrl}
|
|
648
|
-
- Flow Designer Home: https://${credentials?.instance}/flow-designer
|
|
649
|
-
|
|
650
|
-
🧠 **NEW Features (v1.3.24):**
|
|
651
|
-
- Structured flow data with sys_id (BUG-001 FIX) ✅
|
|
652
|
-
- XML-first approach for maximum reliability ✅
|
|
653
|
-
- Automatic Update Set deployment ✅
|
|
654
|
-
- Zero manual steps required ✅
|
|
655
|
-
- Production-ready Flow Designer format ✅
|
|
656
|
-
- Intelligent error handling & fallbacks ✅
|
|
657
|
-
|
|
658
|
-
Your flow is now ${structuredResult.success ? 'live' : 'ready'} in ServiceNow Flow Designer! 🎉`,
|
|
659
|
-
},
|
|
660
|
-
],
|
|
661
|
-
// 🔴 BUG-001 FIX: Include structured data in response
|
|
662
|
-
...structuredResult
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
catch (error) {
|
|
666
|
-
this.logger.error('❌ Intelligent flow creation failed:', error);
|
|
667
|
-
return this.handleServiceNowError(error, 'Intelligent Flow Creation');
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* 🛡️ Check if user is trying to make flow public and warn them about security
|
|
672
|
-
*/
|
|
673
|
-
checkSecurityIntent(instruction) {
|
|
674
|
-
const warnings = [];
|
|
675
|
-
const lowerInstruction = instruction.toLowerCase();
|
|
676
|
-
const publicKeywords = [
|
|
677
|
-
'public', 'publicly', 'everyone', 'anyone', 'all users',
|
|
678
|
-
'no authentication', 'without login', 'guest access',
|
|
679
|
-
'anonymous', 'unauthenticated', 'open access'
|
|
680
|
-
];
|
|
681
|
-
const hasPublicIntent = publicKeywords.some(keyword => lowerInstruction.includes(keyword));
|
|
682
|
-
if (hasPublicIntent) {
|
|
683
|
-
warnings.push('⚠️ SECURITY WARNING: Public access detected in request');
|
|
684
|
-
warnings.push('🔒 For security, flows default to package_private access');
|
|
685
|
-
warnings.push('💡 To make public, explicitly override accessible_from in config');
|
|
686
|
-
warnings.push('🛡️ Consider using role-based access instead of public access');
|
|
687
|
-
}
|
|
688
|
-
return { hasPublicIntent, warnings };
|
|
689
|
-
}
|
|
690
|
-
/**
|
|
691
|
-
* 🧠 INTELLIGENT NATURAL LANGUAGE PARSING
|
|
692
|
-
* Analyzes instruction to understand flow intent, trigger, and requirements
|
|
693
|
-
*/
|
|
694
|
-
async parseFlowInstruction(instruction) {
|
|
695
|
-
console.log('🧠 Parsing flow instruction intelligently...');
|
|
696
|
-
// 🔒 BUG-004 FIX: Check for security concerns first
|
|
697
|
-
const securityCheck = this.checkSecurityIntent(instruction);
|
|
698
|
-
if (securityCheck.warnings.length > 0) {
|
|
699
|
-
securityCheck.warnings.forEach(warning => console.log(warning));
|
|
700
|
-
this.logger.warn('🔒 Security warning in flow instruction', {
|
|
701
|
-
instruction,
|
|
702
|
-
hasPublicIntent: securityCheck.hasPublicIntent
|
|
703
|
-
});
|
|
704
|
-
}
|
|
705
|
-
const words = instruction.toLowerCase();
|
|
706
|
-
// 🎯 Intent Analysis - What is the user trying to achieve?
|
|
707
|
-
const intents = [];
|
|
708
|
-
if (words.includes('approval') || words.includes('goedkeuring'))
|
|
709
|
-
intents.push('approval');
|
|
710
|
-
if (words.includes('notification') || words.includes('email') || words.includes('mail'))
|
|
711
|
-
intents.push('notification');
|
|
712
|
-
if (words.includes('incident') || words.includes('problem'))
|
|
713
|
-
intents.push('incident_management');
|
|
714
|
-
if (words.includes('request') || words.includes('aanvraag'))
|
|
715
|
-
intents.push('request_fulfillment');
|
|
716
|
-
if (words.includes('user') || words.includes('gebruiker'))
|
|
717
|
-
intents.push('user_management');
|
|
718
|
-
if (words.includes('task') || words.includes('taak'))
|
|
719
|
-
intents.push('task_management');
|
|
720
|
-
if (words.includes('data') || words.includes('record') || words.includes('save'))
|
|
721
|
-
intents.push('data_processing');
|
|
722
|
-
if (words.includes('integrate') || words.includes('api'))
|
|
723
|
-
intents.push('integration');
|
|
724
|
-
// Default if no specific intent found
|
|
725
|
-
if (intents.length === 0)
|
|
726
|
-
intents.push('general_automation');
|
|
727
|
-
// 🔴 BUG-003 FIX: Enhanced table detection with context awareness
|
|
728
|
-
let table = 'incident'; // default
|
|
729
|
-
// Priority-based table detection - more specific terms override generic ones
|
|
730
|
-
if (words.includes('incident') && (words.includes('management') || words.includes('priority') || words.includes('severity'))) {
|
|
731
|
-
table = 'incident'; // Explicitly keep incident table when incident context is strong
|
|
732
|
-
}
|
|
733
|
-
else if (words.includes('change') && words.includes('request')) {
|
|
734
|
-
table = 'change_request';
|
|
735
|
-
}
|
|
736
|
-
else if (words.includes('user') || words.includes('gebruiker')) {
|
|
737
|
-
table = 'sys_user';
|
|
738
|
-
}
|
|
739
|
-
else if (words.includes('request') || words.includes('aanvraag')) {
|
|
740
|
-
table = 'sc_request';
|
|
741
|
-
}
|
|
742
|
-
else if (words.includes('task') || words.includes('sc_task')) {
|
|
743
|
-
table = 'sc_task';
|
|
744
|
-
}
|
|
745
|
-
else if (words.includes('problem')) {
|
|
746
|
-
table = 'problem';
|
|
747
|
-
}
|
|
748
|
-
else if (words.includes('catalog')) {
|
|
749
|
-
table = 'sc_cat_item';
|
|
750
|
-
}
|
|
751
|
-
// Log table detection for debugging
|
|
752
|
-
console.log(`🔴 BUG-003: Table detected as '${table}' from instruction: "${instruction}"`);
|
|
753
|
-
// 🎯 Trigger Analysis - When should the flow run?
|
|
754
|
-
const trigger = {
|
|
755
|
-
type: 'manual', // default
|
|
756
|
-
table: table,
|
|
757
|
-
condition: ''
|
|
758
|
-
};
|
|
759
|
-
if (words.includes('when') || words.includes('created') || words.includes('new')) {
|
|
760
|
-
trigger.type = 'record_created';
|
|
761
|
-
trigger.condition = 'state=1'; // New state
|
|
762
|
-
}
|
|
763
|
-
if (words.includes('updated') || words.includes('changed')) {
|
|
764
|
-
trigger.type = 'record_updated';
|
|
765
|
-
trigger.condition = 'state!=6'; // Not closed
|
|
766
|
-
}
|
|
767
|
-
if (words.includes('schedule') || words.includes('daily') || words.includes('hourly')) {
|
|
768
|
-
trigger.type = 'scheduled';
|
|
769
|
-
}
|
|
770
|
-
// 🎯 Flow Name Generation - Intelligent naming
|
|
771
|
-
let flowName = 'Custom Flow';
|
|
772
|
-
if (intents.includes('approval'))
|
|
773
|
-
flowName = 'Approval Workflow';
|
|
774
|
-
if (intents.includes('incident_management'))
|
|
775
|
-
flowName = 'Incident Management Flow';
|
|
776
|
-
if (intents.includes('request_fulfillment'))
|
|
777
|
-
flowName = 'Request Fulfillment Process';
|
|
778
|
-
if (intents.includes('notification'))
|
|
779
|
-
flowName = 'Notification Service';
|
|
780
|
-
if (intents.includes('user_management'))
|
|
781
|
-
flowName = 'User Management Process';
|
|
782
|
-
if (intents.includes('data_processing'))
|
|
783
|
-
flowName = 'Data Processing Flow';
|
|
784
|
-
if (intents.includes('integration'))
|
|
785
|
-
flowName = 'Integration Flow';
|
|
786
|
-
// 🎯 Data Flow Analysis - What data needs to move between steps?
|
|
787
|
-
const dataFlow = [];
|
|
788
|
-
if (words.includes('translate') || words.includes('vertalen'))
|
|
789
|
-
dataFlow.push('translation_data');
|
|
790
|
-
if (words.includes('email') || words.includes('mail'))
|
|
791
|
-
dataFlow.push('email_recipients');
|
|
792
|
-
if (words.includes('user') || words.includes('gebruiker'))
|
|
793
|
-
dataFlow.push('user_details');
|
|
794
|
-
if (words.includes('incident'))
|
|
795
|
-
dataFlow.push('incident_details');
|
|
796
|
-
if (words.includes('request'))
|
|
797
|
-
dataFlow.push('request_details');
|
|
798
|
-
const parsed = {
|
|
799
|
-
flowName,
|
|
800
|
-
description: instruction,
|
|
801
|
-
table,
|
|
802
|
-
trigger,
|
|
803
|
-
intents,
|
|
804
|
-
dataFlow,
|
|
805
|
-
complexity: intents.length > 2 ? 'high' : intents.length > 1 ? 'medium' : 'simple',
|
|
806
|
-
language: words.includes('vertalen') || words.includes('dutch') ? 'multilingual' : 'english'
|
|
807
|
-
};
|
|
808
|
-
console.log('🧠 Parsed intent:', parsed);
|
|
809
|
-
return parsed;
|
|
810
|
-
}
|
|
811
|
-
/**
|
|
812
|
-
* 🧠 INTELLIGENT TEMPLATE MATCHING
|
|
813
|
-
* Finds the best matching template based on parsed intent
|
|
814
|
-
*/
|
|
815
|
-
async findBestTemplate(parsedIntent) {
|
|
816
|
-
console.log('🧠 Finding best template match...');
|
|
817
|
-
// 🎯 Template Library - Predefined patterns that work
|
|
818
|
-
const templates = [
|
|
819
|
-
{
|
|
820
|
-
name: 'Approval Workflow Template',
|
|
821
|
-
intents: ['approval'],
|
|
822
|
-
confidence: 0.95,
|
|
823
|
-
structure: 'approval_with_notification',
|
|
824
|
-
activities: ['approval_step', 'notification_approved', 'notification_rejected'],
|
|
825
|
-
tables: ['sc_request', 'sc_task', 'change_request']
|
|
826
|
-
},
|
|
827
|
-
{
|
|
828
|
-
name: 'Incident Notification Template',
|
|
829
|
-
intents: ['incident_management', 'notification'],
|
|
830
|
-
confidence: 0.90,
|
|
831
|
-
structure: 'incident_notification',
|
|
832
|
-
activities: ['field_check', 'send_email', 'log_activity'],
|
|
833
|
-
tables: ['incident', 'problem']
|
|
834
|
-
},
|
|
835
|
-
{
|
|
836
|
-
name: 'Request Fulfillment Template',
|
|
837
|
-
intents: ['request_fulfillment', 'task_management'],
|
|
838
|
-
confidence: 0.85,
|
|
839
|
-
structure: 'request_processing',
|
|
840
|
-
activities: ['validate_request', 'create_task', 'notify_requester'],
|
|
841
|
-
tables: ['sc_request', 'sc_task']
|
|
842
|
-
},
|
|
843
|
-
{
|
|
844
|
-
name: 'Data Processing Template',
|
|
845
|
-
intents: ['data_processing', 'integration'],
|
|
846
|
-
confidence: 0.80,
|
|
847
|
-
structure: 'data_transformation',
|
|
848
|
-
activities: ['fetch_data', 'transform_data', 'save_data'],
|
|
849
|
-
tables: ['*']
|
|
850
|
-
},
|
|
851
|
-
{
|
|
852
|
-
name: 'User Management Template',
|
|
853
|
-
intents: ['user_management'],
|
|
854
|
-
confidence: 0.75,
|
|
855
|
-
structure: 'user_lifecycle',
|
|
856
|
-
activities: ['validate_user', 'update_profile', 'send_notification'],
|
|
857
|
-
tables: ['sys_user', 'sys_user_group']
|
|
858
|
-
}
|
|
859
|
-
];
|
|
860
|
-
// 🎯 Smart Matching Algorithm
|
|
861
|
-
let bestMatch = null;
|
|
862
|
-
let highestScore = 0;
|
|
863
|
-
for (const template of templates) {
|
|
864
|
-
let score = 0;
|
|
865
|
-
// Intent matching (primary factor)
|
|
866
|
-
const intentMatches = template.intents.filter(intent => parsedIntent.intents.includes(intent)).length;
|
|
867
|
-
score += intentMatches * 40; // 40 points per intent match
|
|
868
|
-
// Table compatibility
|
|
869
|
-
if (template.tables.includes(parsedIntent.table) || template.tables.includes('*')) {
|
|
870
|
-
score += 20;
|
|
871
|
-
}
|
|
872
|
-
// Complexity matching
|
|
873
|
-
const expectedActivities = template.activities.length;
|
|
874
|
-
if (parsedIntent.complexity === 'simple' && expectedActivities <= 3)
|
|
875
|
-
score += 15;
|
|
876
|
-
if (parsedIntent.complexity === 'medium' && expectedActivities <= 5)
|
|
877
|
-
score += 15;
|
|
878
|
-
if (parsedIntent.complexity === 'high' && expectedActivities > 5)
|
|
879
|
-
score += 15;
|
|
880
|
-
const finalConfidence = Math.min(0.95, score / 100); // Cap at 95%
|
|
881
|
-
if (finalConfidence > highestScore && finalConfidence >= 0.6) {
|
|
882
|
-
highestScore = finalConfidence;
|
|
883
|
-
bestMatch = {
|
|
884
|
-
...template,
|
|
885
|
-
confidence: finalConfidence,
|
|
886
|
-
matchScore: score
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
console.log('🧠 Best template match:', bestMatch);
|
|
891
|
-
return bestMatch;
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* 🧠 INTELLIGENT ARTIFACT DISCOVERY
|
|
895
|
-
* Discovers existing ServiceNow artifacts that can be reused
|
|
896
|
-
*/
|
|
897
|
-
async discoverRequiredArtifacts(parsedIntent) {
|
|
898
|
-
console.log('🧠 Discovering required artifacts...');
|
|
899
|
-
const artifacts = {
|
|
900
|
-
existing: [],
|
|
901
|
-
created: [],
|
|
902
|
-
required: []
|
|
903
|
-
};
|
|
904
|
-
// 🎯 Based on intents, determine what artifacts are needed
|
|
905
|
-
if (parsedIntent.intents.includes('notification')) {
|
|
906
|
-
artifacts.required.push({
|
|
907
|
-
type: 'email_template',
|
|
908
|
-
purpose: 'notification',
|
|
909
|
-
priority: 'high'
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
if (parsedIntent.intents.includes('approval')) {
|
|
913
|
-
artifacts.required.push({
|
|
914
|
-
type: 'approval_definition',
|
|
915
|
-
purpose: 'approval_workflow',
|
|
916
|
-
priority: 'critical'
|
|
917
|
-
});
|
|
918
|
-
}
|
|
919
|
-
if (parsedIntent.intents.includes('data_processing')) {
|
|
920
|
-
artifacts.required.push({
|
|
921
|
-
type: 'script_include',
|
|
922
|
-
purpose: 'data_transformation',
|
|
923
|
-
priority: 'medium'
|
|
924
|
-
});
|
|
925
|
-
}
|
|
926
|
-
if (parsedIntent.intents.includes('integration')) {
|
|
927
|
-
artifacts.required.push({
|
|
928
|
-
type: 'rest_message',
|
|
929
|
-
purpose: 'external_integration',
|
|
930
|
-
priority: 'high'
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
// 🎯 Try to discover existing artifacts (simplified for now)
|
|
934
|
-
try {
|
|
935
|
-
// In a real implementation, we would search ServiceNow for existing components
|
|
936
|
-
// For now, we'll simulate discovery
|
|
937
|
-
artifacts.existing = [];
|
|
938
|
-
artifacts.created = artifacts.required.map(req => ({
|
|
939
|
-
...req,
|
|
940
|
-
status: 'will_be_created',
|
|
941
|
-
fallback: true
|
|
942
|
-
}));
|
|
943
|
-
}
|
|
944
|
-
catch (error) {
|
|
945
|
-
console.log('⚠️ Artifact discovery failed, will create fallbacks');
|
|
946
|
-
artifacts.created = artifacts.required;
|
|
947
|
-
}
|
|
948
|
-
console.log('🧠 Discovered artifacts:', artifacts);
|
|
949
|
-
return artifacts;
|
|
950
|
-
}
|
|
951
|
-
/**
|
|
952
|
-
* 🧠 INTELLIGENT FLOW DEFINITION GENERATION
|
|
953
|
-
* Creates complete ServiceNow Flow Designer compatible structure
|
|
954
|
-
*/
|
|
955
|
-
async generateFlowDefinition(parsedIntent, templateMatch, artifacts) {
|
|
956
|
-
console.log('🧠 Generating complete flow definition...');
|
|
957
|
-
// 🎯 Base Flow Structure
|
|
958
|
-
const flowDefinition = {
|
|
959
|
-
name: parsedIntent.flowName,
|
|
960
|
-
description: parsedIntent.description,
|
|
961
|
-
active: true,
|
|
962
|
-
trigger_type: parsedIntent.trigger.type,
|
|
963
|
-
table: parsedIntent.table,
|
|
964
|
-
activities: [],
|
|
965
|
-
variables: [],
|
|
966
|
-
error_handling: [],
|
|
967
|
-
connections: []
|
|
968
|
-
};
|
|
969
|
-
// 🎯 Generate Activities based on template and intent
|
|
970
|
-
if (templateMatch) {
|
|
971
|
-
console.log(`🧠 Using template: ${templateMatch.name}`);
|
|
972
|
-
flowDefinition.activities = await this.generateActivitiesFromTemplate(templateMatch, parsedIntent, artifacts);
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
console.log('🧠 No template match - generating custom activities');
|
|
976
|
-
flowDefinition.activities = await this.generateCustomActivities(parsedIntent, artifacts);
|
|
977
|
-
}
|
|
978
|
-
// 🔴 BUG-003 FIX: Validate all field references against the table schema
|
|
979
|
-
flowDefinition.activities = await this.validateAndFixFieldReferences(flowDefinition.activities, parsedIntent.table);
|
|
980
|
-
// 🎯 Generate Variables for data flow
|
|
981
|
-
flowDefinition.variables = this.generateFlowVariables(parsedIntent);
|
|
982
|
-
// 🎯 Generate Error Handling
|
|
983
|
-
flowDefinition.error_handling = this.generateErrorHandling(parsedIntent);
|
|
984
|
-
// 🎯 Generate Connections between activities
|
|
985
|
-
flowDefinition.connections = this.generateActivityConnections(flowDefinition.activities);
|
|
986
|
-
console.log('🧠 Complete flow definition generated');
|
|
987
|
-
return flowDefinition;
|
|
988
|
-
}
|
|
989
|
-
/**
|
|
990
|
-
* 🔴 BUG-003 FIX: Validate and fix field references against table schema
|
|
991
|
-
*/
|
|
992
|
-
async validateAndFixFieldReferences(activities, tableName) {
|
|
993
|
-
console.log(`🔴 BUG-003: Validating field references for table '${tableName}'`);
|
|
994
|
-
// Common field mappings for different tables
|
|
995
|
-
const tableFieldMappings = {
|
|
996
|
-
incident: {
|
|
997
|
-
caller_id: 'caller_id',
|
|
998
|
-
severity: 'severity',
|
|
999
|
-
priority: 'priority',
|
|
1000
|
-
short_description: 'short_description',
|
|
1001
|
-
description: 'description',
|
|
1002
|
-
assigned_to: 'assigned_to',
|
|
1003
|
-
state: 'state',
|
|
1004
|
-
number: 'number',
|
|
1005
|
-
work_notes: 'work_notes',
|
|
1006
|
-
comments: 'comments',
|
|
1007
|
-
category: 'category',
|
|
1008
|
-
subcategory: 'subcategory',
|
|
1009
|
-
resolved_by: 'resolved_by',
|
|
1010
|
-
close_notes: 'close_notes'
|
|
1011
|
-
},
|
|
1012
|
-
change_request: {
|
|
1013
|
-
requested_by: 'requested_by',
|
|
1014
|
-
category: 'category',
|
|
1015
|
-
priority: 'priority',
|
|
1016
|
-
risk: 'risk',
|
|
1017
|
-
impact: 'impact',
|
|
1018
|
-
short_description: 'short_description',
|
|
1019
|
-
description: 'description',
|
|
1020
|
-
assigned_to: 'assigned_to',
|
|
1021
|
-
state: 'state',
|
|
1022
|
-
number: 'number',
|
|
1023
|
-
work_notes: 'work_notes',
|
|
1024
|
-
type: 'type',
|
|
1025
|
-
// Change request doesn't have caller_id or severity
|
|
1026
|
-
caller_id: 'requested_by', // Map to equivalent field
|
|
1027
|
-
severity: 'impact' // Map severity to impact for change requests
|
|
1028
|
-
},
|
|
1029
|
-
sc_request: {
|
|
1030
|
-
requested_for: 'requested_for',
|
|
1031
|
-
opened_by: 'opened_by',
|
|
1032
|
-
short_description: 'short_description',
|
|
1033
|
-
description: 'description',
|
|
1034
|
-
assigned_to: 'assigned_to',
|
|
1035
|
-
state: 'state',
|
|
1036
|
-
number: 'number',
|
|
1037
|
-
work_notes: 'work_notes',
|
|
1038
|
-
comments: 'comments',
|
|
1039
|
-
priority: 'priority',
|
|
1040
|
-
// Service catalog requests use different field names
|
|
1041
|
-
caller_id: 'requested_for',
|
|
1042
|
-
severity: 'priority'
|
|
1043
|
-
},
|
|
1044
|
-
problem: {
|
|
1045
|
-
opened_by: 'opened_by',
|
|
1046
|
-
short_description: 'short_description',
|
|
1047
|
-
description: 'description',
|
|
1048
|
-
assigned_to: 'assigned_to',
|
|
1049
|
-
state: 'state',
|
|
1050
|
-
number: 'number',
|
|
1051
|
-
work_notes: 'work_notes',
|
|
1052
|
-
priority: 'priority',
|
|
1053
|
-
category: 'category',
|
|
1054
|
-
subcategory: 'subcategory',
|
|
1055
|
-
known_error: 'known_error',
|
|
1056
|
-
workaround: 'workaround',
|
|
1057
|
-
// Problems don't have caller_id
|
|
1058
|
-
caller_id: 'opened_by',
|
|
1059
|
-
severity: 'priority'
|
|
1060
|
-
}
|
|
1061
|
-
};
|
|
1062
|
-
// Get field mappings for the current table
|
|
1063
|
-
const fieldMap = tableFieldMappings[tableName] || tableFieldMappings.incident;
|
|
1064
|
-
// Process each activity to fix field references
|
|
1065
|
-
const fixedActivities = activities.map(activity => {
|
|
1066
|
-
if (activity.inputs?.script) {
|
|
1067
|
-
// Fix field references in scripts
|
|
1068
|
-
let fixedScript = activity.inputs.script;
|
|
1069
|
-
// Replace field references that don't exist on the target table
|
|
1070
|
-
Object.keys(fieldMap).forEach(standardField => {
|
|
1071
|
-
const tableField = fieldMap[standardField];
|
|
1072
|
-
if (standardField !== tableField) {
|
|
1073
|
-
// Replace current.caller_id with current.requested_by for change_request, etc.
|
|
1074
|
-
const regex = new RegExp(`current\\.${standardField}`, 'g');
|
|
1075
|
-
fixedScript = fixedScript.replace(regex, `current.${tableField}`);
|
|
1076
|
-
// Also handle ${record.caller_id} style references
|
|
1077
|
-
const regex2 = new RegExp(`\\$\\{record\\.${standardField}\\}`, 'g');
|
|
1078
|
-
fixedScript = fixedScript.replace(regex2, `\${record.${tableField}}`);
|
|
1079
|
-
}
|
|
1080
|
-
});
|
|
1081
|
-
activity.inputs.script = fixedScript;
|
|
1082
|
-
}
|
|
1083
|
-
// Fix field references in other input fields
|
|
1084
|
-
if (activity.inputs) {
|
|
1085
|
-
Object.keys(activity.inputs).forEach(inputKey => {
|
|
1086
|
-
if (typeof activity.inputs[inputKey] === 'string' && inputKey !== 'script') {
|
|
1087
|
-
let value = activity.inputs[inputKey];
|
|
1088
|
-
// Fix ${record.field} references
|
|
1089
|
-
Object.keys(fieldMap).forEach(standardField => {
|
|
1090
|
-
const tableField = fieldMap[standardField];
|
|
1091
|
-
if (standardField !== tableField) {
|
|
1092
|
-
const regex = new RegExp(`\\$\\{record\\.${standardField}\\}`, 'g');
|
|
1093
|
-
value = value.replace(regex, `\${record.${tableField}}`);
|
|
1094
|
-
}
|
|
1095
|
-
});
|
|
1096
|
-
activity.inputs[inputKey] = value;
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
1099
|
-
}
|
|
1100
|
-
return activity;
|
|
1101
|
-
});
|
|
1102
|
-
console.log(`🔴 BUG-003: Field validation complete. Fixed field references for table '${tableName}'`);
|
|
1103
|
-
return fixedActivities;
|
|
1104
|
-
}
|
|
1105
|
-
/**
|
|
1106
|
-
* Generate activities from template
|
|
1107
|
-
*/
|
|
1108
|
-
async generateActivitiesFromTemplate(templateMatch, parsedIntent, artifacts) {
|
|
1109
|
-
const activities = [];
|
|
1110
|
-
switch (templateMatch.structure) {
|
|
1111
|
-
case 'approval_with_notification':
|
|
1112
|
-
activities.push({
|
|
1113
|
-
id: 'approval_step',
|
|
1114
|
-
name: 'Request Approval',
|
|
1115
|
-
type: 'approval',
|
|
1116
|
-
inputs: {
|
|
1117
|
-
approver: 'admin',
|
|
1118
|
-
message: `Please approve: ${parsedIntent.description}`,
|
|
1119
|
-
due_date: '+7 days'
|
|
1120
|
-
},
|
|
1121
|
-
outputs: {
|
|
1122
|
-
approval_result: 'string',
|
|
1123
|
-
approved_by: 'string'
|
|
1124
|
-
}
|
|
1125
|
-
}, {
|
|
1126
|
-
id: 'notification_approved',
|
|
1127
|
-
name: 'Send Approval Notification',
|
|
1128
|
-
type: 'notification',
|
|
1129
|
-
condition: '${approval_step.approval_result} == "approved"',
|
|
1130
|
-
inputs: {
|
|
1131
|
-
recipient: '${record.requested_for}',
|
|
1132
|
-
subject: 'Request Approved',
|
|
1133
|
-
message: 'Your request has been approved by ${approval_step.approved_by}'
|
|
1134
|
-
}
|
|
1135
|
-
}, {
|
|
1136
|
-
id: 'notification_rejected',
|
|
1137
|
-
name: 'Send Rejection Notification',
|
|
1138
|
-
type: 'notification',
|
|
1139
|
-
condition: '${approval_step.approval_result} == "rejected"',
|
|
1140
|
-
inputs: {
|
|
1141
|
-
recipient: '${record.requested_for}',
|
|
1142
|
-
subject: 'Request Rejected',
|
|
1143
|
-
message: 'Your request has been rejected. Please contact support for details.'
|
|
1144
|
-
}
|
|
1145
|
-
});
|
|
1146
|
-
break;
|
|
1147
|
-
case 'incident_notification':
|
|
1148
|
-
activities.push({
|
|
1149
|
-
id: 'field_check',
|
|
1150
|
-
name: 'Check Incident Priority',
|
|
1151
|
-
type: 'condition',
|
|
1152
|
-
condition: '${record.priority} <= 2', // High or Critical
|
|
1153
|
-
inputs: {
|
|
1154
|
-
field_to_check: 'priority',
|
|
1155
|
-
operator: 'less_than_or_equal',
|
|
1156
|
-
value: '2'
|
|
1157
|
-
}
|
|
1158
|
-
}, {
|
|
1159
|
-
id: 'send_email',
|
|
1160
|
-
name: 'Send High Priority Alert',
|
|
1161
|
-
type: 'notification',
|
|
1162
|
-
condition: '${field_check.result} == true',
|
|
1163
|
-
inputs: {
|
|
1164
|
-
recipient: 'it-management@company.com',
|
|
1165
|
-
subject: 'HIGH PRIORITY: ${record.short_description}',
|
|
1166
|
-
message: 'Incident ${{record.number}} requires immediate attention.\\n\\nDescription: ${{record.description}}\\nPriority: ${{record.priority}}\\nAssignee: ${{record.assigned_to}}'
|
|
1167
|
-
}
|
|
1168
|
-
}, {
|
|
1169
|
-
id: 'log_activity',
|
|
1170
|
-
name: 'Log Notification Sent',
|
|
1171
|
-
type: 'script',
|
|
1172
|
-
inputs: {
|
|
1173
|
-
script: `gs.log('High priority incident notification sent for ' + current.number, 'IncidentFlow');
|
|
1174
|
-
current.work_notes = 'Automated notification sent to IT Management';
|
|
1175
|
-
current.update();`
|
|
1176
|
-
}
|
|
1177
|
-
});
|
|
1178
|
-
break;
|
|
1179
|
-
case 'request_processing':
|
|
1180
|
-
activities.push({
|
|
1181
|
-
id: 'validate_request',
|
|
1182
|
-
name: 'Validate Request Data',
|
|
1183
|
-
type: 'script',
|
|
1184
|
-
inputs: {
|
|
1185
|
-
script: `var isValid = true;
|
|
1186
|
-
var errors = [];
|
|
1187
|
-
|
|
1188
|
-
if (!current.requested_for) {
|
|
1189
|
-
errors.push('Requested for field is required');
|
|
1190
|
-
isValid = false;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
if (!current.short_description) {
|
|
1194
|
-
errors.push('Short description is required');
|
|
1195
|
-
isValid = false;
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
return { valid: isValid, errors: errors };`
|
|
1199
|
-
},
|
|
1200
|
-
outputs: {
|
|
1201
|
-
validation_result: 'object'
|
|
1202
|
-
}
|
|
1203
|
-
}, {
|
|
1204
|
-
id: 'create_task',
|
|
1205
|
-
name: 'Create Fulfillment Task',
|
|
1206
|
-
type: 'create_record',
|
|
1207
|
-
condition: '${validate_request.validation_result.valid} == true',
|
|
1208
|
-
inputs: {
|
|
1209
|
-
table: 'sc_task',
|
|
1210
|
-
fields: {
|
|
1211
|
-
request: '${record.sys_id}',
|
|
1212
|
-
short_description: 'Fulfill: ${record.short_description}',
|
|
1213
|
-
description: '${record.description}',
|
|
1214
|
-
assigned_to: 'fulfillment.team',
|
|
1215
|
-
state: '1' // Open
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
}, {
|
|
1219
|
-
id: 'notify_requester',
|
|
1220
|
-
name: 'Notify Requester',
|
|
1221
|
-
type: 'notification',
|
|
1222
|
-
inputs: {
|
|
1223
|
-
recipient: '${record.requested_for}',
|
|
1224
|
-
subject: 'Request Processing Started',
|
|
1225
|
-
message: 'Your request ${{record.number}} is being processed.\\n\\nTask ${{create_task.result.number}} has been created for fulfillment.'
|
|
1226
|
-
}
|
|
1227
|
-
});
|
|
1228
|
-
break;
|
|
1229
|
-
case 'data_transformation':
|
|
1230
|
-
activities.push({
|
|
1231
|
-
id: 'fetch_data',
|
|
1232
|
-
name: 'Fetch Record Data',
|
|
1233
|
-
type: 'script',
|
|
1234
|
-
inputs: {
|
|
1235
|
-
script: `var recordData = {
|
|
1236
|
-
sys_id: current.sys_id,
|
|
1237
|
-
table: current.sys_class_name,
|
|
1238
|
-
fields: {}
|
|
1239
|
-
};
|
|
1240
|
-
|
|
1241
|
-
// Get all fields and values
|
|
1242
|
-
var fields = current.getElements();
|
|
1243
|
-
for (var i = 0; i < fields.size(); i++) {
|
|
1244
|
-
var field = fields.get(i);
|
|
1245
|
-
recordData.fields[field.getName()] = current.getValue(field.getName());
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
return recordData;`
|
|
1249
|
-
},
|
|
1250
|
-
outputs: {
|
|
1251
|
-
record_data: 'object'
|
|
1252
|
-
}
|
|
1253
|
-
}, {
|
|
1254
|
-
id: 'transform_data',
|
|
1255
|
-
name: 'Transform Data',
|
|
1256
|
-
type: 'script',
|
|
1257
|
-
inputs: {
|
|
1258
|
-
script: `var transformedData = fetch_data.record_data;
|
|
1259
|
-
|
|
1260
|
-
// Apply transformations based on business rules
|
|
1261
|
-
if (transformedData.fields.description) {
|
|
1262
|
-
transformedData.fields.description = transformedData.fields.description.toUpperCase();
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
transformedData.transformed_at = new GlideDateTime().toString();
|
|
1266
|
-
transformedData.transform_id = gs.generateGUID();
|
|
1267
|
-
|
|
1268
|
-
return transformedData;`
|
|
1269
|
-
},
|
|
1270
|
-
outputs: {
|
|
1271
|
-
transformed_data: 'object'
|
|
1272
|
-
}
|
|
1273
|
-
}, {
|
|
1274
|
-
id: 'save_data',
|
|
1275
|
-
name: 'Save Transformed Data',
|
|
1276
|
-
type: 'create_record',
|
|
1277
|
-
inputs: {
|
|
1278
|
-
table: 'u_transformed_data', // Custom table
|
|
1279
|
-
fields: {
|
|
1280
|
-
original_record: '${fetch_data.record_data.sys_id}',
|
|
1281
|
-
transformed_data: '${transform_data.transformed_data}',
|
|
1282
|
-
processed_date: '${gs.nowDateTime()}'
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
});
|
|
1286
|
-
break;
|
|
1287
|
-
default:
|
|
1288
|
-
// Fallback to custom activities
|
|
1289
|
-
return await this.generateCustomActivities(parsedIntent, artifacts);
|
|
1290
|
-
}
|
|
1291
|
-
return activities;
|
|
1292
|
-
}
|
|
1293
|
-
/**
|
|
1294
|
-
* Generate custom activities when no template matches
|
|
1295
|
-
*/
|
|
1296
|
-
async generateCustomActivities(parsedIntent, artifacts) {
|
|
1297
|
-
const activities = [];
|
|
1298
|
-
// 🎯 Always start with validation for data integrity
|
|
1299
|
-
activities.push({
|
|
1300
|
-
id: 'validate_input',
|
|
1301
|
-
name: 'Validate Input Data',
|
|
1302
|
-
type: 'script',
|
|
1303
|
-
inputs: {
|
|
1304
|
-
script: `var result = { valid: true, message: 'Input validation passed' };
|
|
1305
|
-
|
|
1306
|
-
// Basic validation logic
|
|
1307
|
-
if (!current) {
|
|
1308
|
-
result.valid = false;
|
|
1309
|
-
result.message = 'No record context available';
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
return result;`
|
|
1313
|
-
},
|
|
1314
|
-
outputs: {
|
|
1315
|
-
validation_result: 'object'
|
|
1316
|
-
}
|
|
1317
|
-
});
|
|
1318
|
-
// 🎯 Add activities based on detected intents
|
|
1319
|
-
if (parsedIntent.intents.includes('notification')) {
|
|
1320
|
-
activities.push({
|
|
1321
|
-
id: 'send_notification',
|
|
1322
|
-
name: 'Send Notification',
|
|
1323
|
-
type: 'notification',
|
|
1324
|
-
condition: '${validate_input.validation_result.valid} == true',
|
|
1325
|
-
inputs: {
|
|
1326
|
-
recipient: 'admin@company.com',
|
|
1327
|
-
subject: 'Flow Notification: ${{record.short_description}}',
|
|
1328
|
-
message: 'A flow has been triggered for record ${{record.number}}\\n\\nDetails: ${{record.description}}'
|
|
1329
|
-
}
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
if (parsedIntent.intents.includes('data_processing')) {
|
|
1333
|
-
activities.push({
|
|
1334
|
-
id: 'process_data',
|
|
1335
|
-
name: 'Process Record Data',
|
|
1336
|
-
type: 'script',
|
|
1337
|
-
inputs: {
|
|
1338
|
-
script: `// Process the record data
|
|
1339
|
-
current.work_notes = 'Processed by automated flow on ' + new GlideDateTime();
|
|
1340
|
-
current.state = 2; // In Progress
|
|
1341
|
-
current.update();
|
|
1342
|
-
|
|
1343
|
-
gs.log('Record processed by flow: ' + current.number, 'CustomFlow');`
|
|
1344
|
-
}
|
|
1345
|
-
});
|
|
1346
|
-
}
|
|
1347
|
-
// 🎯 Always end with logging for audit trail
|
|
1348
|
-
activities.push({
|
|
1349
|
-
id: 'log_completion',
|
|
1350
|
-
name: 'Log Flow Completion',
|
|
1351
|
-
type: 'script',
|
|
1352
|
-
inputs: {
|
|
1353
|
-
script: `gs.log('Flow completed successfully for record: ' + current.number, 'FlowCompletion');
|
|
1354
|
-
|
|
1355
|
-
// Update record with completion timestamp
|
|
1356
|
-
current.u_flow_completed = new GlideDateTime();
|
|
1357
|
-
current.update();`
|
|
1358
|
-
}
|
|
1359
|
-
});
|
|
1360
|
-
return activities;
|
|
1361
|
-
}
|
|
1362
|
-
/**
|
|
1363
|
-
* Generate flow variables for data passing
|
|
1364
|
-
*/
|
|
1365
|
-
generateFlowVariables(parsedIntent) {
|
|
1366
|
-
const variables = [
|
|
1367
|
-
{
|
|
1368
|
-
id: 'flow_start_time',
|
|
1369
|
-
name: 'Flow Start Time',
|
|
1370
|
-
type: 'datetime',
|
|
1371
|
-
input: false,
|
|
1372
|
-
output: true,
|
|
1373
|
-
default_value: '${gs.nowDateTime()}'
|
|
1374
|
-
},
|
|
1375
|
-
{
|
|
1376
|
-
id: 'record_context',
|
|
1377
|
-
name: 'Record Context',
|
|
1378
|
-
type: 'reference',
|
|
1379
|
-
input: true,
|
|
1380
|
-
output: false,
|
|
1381
|
-
table: parsedIntent.table
|
|
1382
|
-
}
|
|
1383
|
-
];
|
|
1384
|
-
// Add intent-specific variables
|
|
1385
|
-
if (parsedIntent.intents.includes('approval')) {
|
|
1386
|
-
variables.push({
|
|
1387
|
-
id: 'approval_result',
|
|
1388
|
-
name: 'Approval Result',
|
|
1389
|
-
type: 'string',
|
|
1390
|
-
input: false,
|
|
1391
|
-
output: true,
|
|
1392
|
-
default_value: ''
|
|
1393
|
-
});
|
|
1394
|
-
}
|
|
1395
|
-
if (parsedIntent.intents.includes('notification')) {
|
|
1396
|
-
variables.push({
|
|
1397
|
-
id: 'notification_sent',
|
|
1398
|
-
name: 'Notification Sent',
|
|
1399
|
-
type: 'boolean',
|
|
1400
|
-
input: false,
|
|
1401
|
-
output: true,
|
|
1402
|
-
default_value: 'false'
|
|
1403
|
-
});
|
|
1404
|
-
}
|
|
1405
|
-
return variables;
|
|
1406
|
-
}
|
|
1407
|
-
/**
|
|
1408
|
-
* Generate error handling activities
|
|
1409
|
-
*/
|
|
1410
|
-
generateErrorHandling(parsedIntent) {
|
|
1411
|
-
return [
|
|
1412
|
-
{
|
|
1413
|
-
id: 'error_handler',
|
|
1414
|
-
name: 'Handle Flow Errors',
|
|
1415
|
-
type: 'script',
|
|
1416
|
-
trigger: 'on_error',
|
|
1417
|
-
inputs: {
|
|
1418
|
-
script: `gs.error('Flow error occurred: ' + error.message, 'FlowError');
|
|
1419
|
-
|
|
1420
|
-
// Send error notification
|
|
1421
|
-
var email = new GlideEmailOutbound();
|
|
1422
|
-
email.setSubject('Flow Error in ${parsedIntent.flowName}');
|
|
1423
|
-
email.setBody('An error occurred during flow execution: ' + error.message);
|
|
1424
|
-
email.addAddress('admin@company.com');
|
|
1425
|
-
email.send();
|
|
1426
|
-
|
|
1427
|
-
// Log to system log
|
|
1428
|
-
gs.log('Flow error logged and notification sent', 'FlowError');`
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
];
|
|
1432
|
-
}
|
|
1433
|
-
/**
|
|
1434
|
-
* Generate connections between activities
|
|
1435
|
-
*/
|
|
1436
|
-
generateActivityConnections(activities) {
|
|
1437
|
-
const connections = [];
|
|
1438
|
-
for (let i = 0; i < activities.length - 1; i++) {
|
|
1439
|
-
connections.push({
|
|
1440
|
-
from: activities[i].id,
|
|
1441
|
-
to: activities[i + 1].id,
|
|
1442
|
-
condition: activities[i + 1].condition || 'always'
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
return connections;
|
|
1446
|
-
}
|
|
1447
|
-
async analyzeFlowInstruction(args) {
|
|
1448
|
-
// Check authentication first
|
|
1449
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
1450
|
-
if (!isAuth) {
|
|
1451
|
-
return {
|
|
1452
|
-
content: [
|
|
1453
|
-
{
|
|
1454
|
-
type: 'text',
|
|
1455
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
1456
|
-
},
|
|
1457
|
-
],
|
|
1458
|
-
};
|
|
1459
|
-
}
|
|
1460
|
-
try {
|
|
1461
|
-
this.logger.info('Analyzing flow instruction', { instruction: args.instruction });
|
|
1462
|
-
const flowInstruction = await this.composer.createFlowFromInstruction(args.instruction);
|
|
1463
|
-
return {
|
|
1464
|
-
content: [
|
|
1465
|
-
{
|
|
1466
|
-
type: 'text',
|
|
1467
|
-
text: `🔍 Flow Instruction Analysis
|
|
1468
|
-
|
|
1469
|
-
📝 **Original Instruction:**
|
|
1470
|
-
"${args.instruction}"
|
|
1471
|
-
|
|
1472
|
-
🧠 **Parsed Intent:**
|
|
1473
|
-
- **Flow Name**: ${flowInstruction.parsedIntent?.flowName || 'Auto-generated'}
|
|
1474
|
-
- **Table**: ${flowInstruction.parsedIntent?.table || 'Unknown'}
|
|
1475
|
-
- **Trigger Type**: ${flowInstruction.parsedIntent?.trigger?.type || 'Unknown'}
|
|
1476
|
-
- **Condition**: ${flowInstruction.parsedIntent?.trigger?.condition || 'None'}
|
|
1477
|
-
- **Intents**: ${flowInstruction.parsedIntent?.intents?.join(', ') || 'None'}
|
|
1478
|
-
- **Data Flow**: ${flowInstruction.parsedIntent?.dataFlow?.join(' → ') || 'None'}
|
|
1479
|
-
|
|
1480
|
-
🔧 **Required Artifacts:**
|
|
1481
|
-
${flowInstruction.requiredArtifacts?.map((artifact, index) => `${index + 1}. **${artifact.type}**
|
|
1482
|
-
- Name: ${artifact.name}
|
|
1483
|
-
- Sys ID: ${artifact.sys_id}
|
|
1484
|
-
- Inputs: ${artifact.inputs?.length || 0} input(s)
|
|
1485
|
-
- Outputs: ${artifact.outputs?.length || 0} output(s)`)?.join('\n\n') || 'No required artifacts'}
|
|
1486
|
-
|
|
1487
|
-
🏗️ **Flow Structure Preview:**
|
|
1488
|
-
- **Name**: ${flowInstruction.flowStructure?.name || 'Unknown'}
|
|
1489
|
-
- **Trigger**: ${flowInstruction.flowStructure?.trigger?.type || 'Unknown'} on ${flowInstruction.flowStructure?.trigger?.table || 'Unknown'}
|
|
1490
|
-
- **Activities**: ${flowInstruction.flowStructure?.activities?.length || 0}
|
|
1491
|
-
- **Variables**: ${flowInstruction.flowStructure?.variables?.length || 0}
|
|
1492
|
-
- **Error Handling**: ${flowInstruction.flowStructure?.error_handling?.length || 0} rules
|
|
1493
|
-
|
|
1494
|
-
📊 **Complexity Analysis:**
|
|
1495
|
-
- **Artifact Dependencies**: ${flowInstruction.requiredArtifacts?.length || 0}
|
|
1496
|
-
- **Processing Steps**: ${flowInstruction.flowStructure?.activities?.length || 0}
|
|
1497
|
-
- **Integration Points**: ${flowInstruction.requiredArtifacts?.length || 0}
|
|
1498
|
-
- **Data Flow Steps**: ${flowInstruction.parsedIntent?.dataFlow?.length || 0}
|
|
1499
|
-
|
|
1500
|
-
✅ **Analysis Complete!** The instruction has been successfully parsed and all required components identified.`,
|
|
1501
|
-
},
|
|
1502
|
-
],
|
|
1503
|
-
};
|
|
1504
|
-
}
|
|
1505
|
-
catch (error) {
|
|
1506
|
-
throw new Error(`Flow instruction analysis failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
async discoverFlowArtifacts(args) {
|
|
1510
|
-
// Check authentication first
|
|
1511
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
1512
|
-
if (!isAuth) {
|
|
1513
|
-
return {
|
|
1514
|
-
content: [
|
|
1515
|
-
{
|
|
1516
|
-
type: 'text',
|
|
1517
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
1518
|
-
},
|
|
1519
|
-
],
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
try {
|
|
1523
|
-
this.logger.info('Discovering flow artifacts', { instruction: args.instruction });
|
|
1524
|
-
const flowInstruction = await this.composer.createFlowFromInstruction(args.instruction);
|
|
1525
|
-
// Filter by specific artifact types if requested
|
|
1526
|
-
let artifactsToShow = flowInstruction.requiredArtifacts;
|
|
1527
|
-
if (args.artifact_types && args.artifact_types.length > 0) {
|
|
1528
|
-
artifactsToShow = flowInstruction.requiredArtifacts?.filter((a) => args.artifact_types.includes(a.type));
|
|
1529
|
-
}
|
|
1530
|
-
const credentials = await this.oauth.loadCredentials();
|
|
1531
|
-
return {
|
|
1532
|
-
content: [
|
|
1533
|
-
{
|
|
1534
|
-
type: 'text',
|
|
1535
|
-
text: `🔍 ServiceNow Artifact Discovery Results
|
|
1536
|
-
|
|
1537
|
-
🎯 **Instruction**: "${args.instruction}"
|
|
1538
|
-
|
|
1539
|
-
📦 **Discovered Artifacts** (${artifactsToShow.length} found):
|
|
1540
|
-
|
|
1541
|
-
${artifactsToShow.map((artifact, index) => `### ${index + 1}. ${artifact.type.toUpperCase()}
|
|
1542
|
-
**Purpose**: ${artifact.purpose}
|
|
1543
|
-
**Search Strategy**: "${artifact.searchQuery}"
|
|
1544
|
-
**Required**: ${artifact.required ? '✅ Yes' : '❌ No'}
|
|
1545
|
-
**Fallback**: ${artifact.fallbackAction || 'None'}
|
|
1546
|
-
|
|
1547
|
-
**Search Details:**
|
|
1548
|
-
- Table: ${this.getTableForArtifactType(artifact.type)}
|
|
1549
|
-
- Search Fields: name, description, short_description
|
|
1550
|
-
- Match Priority: Exact → Fuzzy → Semantic
|
|
1551
|
-
|
|
1552
|
-
**Integration Points:**
|
|
1553
|
-
- Used in flow step: ${this.getFlowStepForArtifact(artifact, flowInstruction)}
|
|
1554
|
-
- Data inputs: ${this.getArtifactInputs(artifact)}
|
|
1555
|
-
- Data outputs: ${this.getArtifactOutputs(artifact)}
|
|
1556
|
-
`).join('\n')}
|
|
1557
|
-
|
|
1558
|
-
🔗 **ServiceNow Search Links:**
|
|
1559
|
-
${artifactsToShow.map((artifact) => `- ${artifact.type}: https://${credentials?.instance}/nav_to.do?uri=${this.getTableForArtifactType(artifact.type)}_list.do`).join('\n')}
|
|
1560
|
-
|
|
1561
|
-
💡 **Discovery Strategy:**
|
|
1562
|
-
1. **Intelligent Search**: Uses natural language processing to find relevant artifacts
|
|
1563
|
-
2. **Semantic Matching**: Matches purpose and functionality, not just names
|
|
1564
|
-
3. **Fallback Creation**: Creates missing artifacts automatically if needed
|
|
1565
|
-
4. **Dependency Mapping**: Identifies relationships between artifacts
|
|
1566
|
-
|
|
1567
|
-
🎯 **Next Steps:**
|
|
1568
|
-
- Run \`snow_preview_flow_structure\` to see how these artifacts will be used
|
|
1569
|
-
- Use \`snow_create_complex_flow\` to create and deploy the complete flow
|
|
1570
|
-
- Individual artifacts can be analyzed using \`snow_analyze_artifact\`
|
|
1571
|
-
|
|
1572
|
-
✅ **Discovery Complete!** All required artifacts have been identified and are ready for flow composition.`,
|
|
1573
|
-
},
|
|
1574
|
-
],
|
|
1575
|
-
};
|
|
1576
|
-
}
|
|
1577
|
-
catch (error) {
|
|
1578
|
-
throw new Error(`Artifact discovery failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
/**
|
|
1582
|
-
* Extract a flow name from instruction text
|
|
1583
|
-
*/
|
|
1584
|
-
extractFlowName(instruction) {
|
|
1585
|
-
// Try to extract meaningful name from instruction
|
|
1586
|
-
const keywords = ['flow', 'process', 'workflow', 'automation'];
|
|
1587
|
-
const words = instruction.toLowerCase().split(/\s+/);
|
|
1588
|
-
// Look for keywords and use surrounding context
|
|
1589
|
-
for (const keyword of keywords) {
|
|
1590
|
-
const keywordIndex = words.indexOf(keyword);
|
|
1591
|
-
if (keywordIndex >= 0) {
|
|
1592
|
-
// Get 2-3 words before the keyword as the name
|
|
1593
|
-
const startIndex = Math.max(0, keywordIndex - 2);
|
|
1594
|
-
const nameParts = words.slice(startIndex, keywordIndex + 1);
|
|
1595
|
-
return nameParts.join('_').replace(/[^a-z0-9_]/g, '');
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
// Fallback: use first few words
|
|
1599
|
-
return words.slice(0, 3).join('_').replace(/[^a-z0-9_]/g, '') + '_flow';
|
|
1600
|
-
}
|
|
1601
|
-
async previewFlowStructure(args) {
|
|
1602
|
-
// Check authentication first
|
|
1603
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
1604
|
-
if (!isAuth) {
|
|
1605
|
-
return {
|
|
1606
|
-
content: [
|
|
1607
|
-
{
|
|
1608
|
-
type: 'text',
|
|
1609
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
1610
|
-
},
|
|
1611
|
-
],
|
|
1612
|
-
};
|
|
1613
|
-
}
|
|
1614
|
-
try {
|
|
1615
|
-
this.logger.info('Previewing flow structure', { instruction: args.instruction });
|
|
1616
|
-
const flowInstruction = await this.composer.createFlowFromInstruction(args.instruction);
|
|
1617
|
-
// FIX: Add null safety checks to prevent "Cannot read properties of undefined" errors
|
|
1618
|
-
if (!flowInstruction || !flowInstruction.flowStructure) {
|
|
1619
|
-
this.logger.error('Flow instruction or flowStructure is undefined', { flowInstruction });
|
|
1620
|
-
// Create minimal fallback flow structure
|
|
1621
|
-
const fallbackFlow = {
|
|
1622
|
-
name: this.extractFlowName(args.instruction),
|
|
1623
|
-
description: `Flow for: ${args.instruction}`,
|
|
1624
|
-
trigger: { type: 'manual', table: 'task', condition: '' },
|
|
1625
|
-
variables: [],
|
|
1626
|
-
activities: [],
|
|
1627
|
-
error_handling: []
|
|
1628
|
-
};
|
|
1629
|
-
return {
|
|
1630
|
-
content: [{
|
|
1631
|
-
type: 'text',
|
|
1632
|
-
text: `⚠️ **Flow Structure Creation Issue**
|
|
1633
|
-
|
|
1634
|
-
The flow composer returned incomplete data. Creating minimal flow structure:
|
|
1635
|
-
|
|
1636
|
-
📋 **Flow Information:**
|
|
1637
|
-
- **Name**: ${fallbackFlow.name}
|
|
1638
|
-
- **Description**: ${fallbackFlow.description}
|
|
1639
|
-
- **Type**: Manual trigger on task table
|
|
1640
|
-
|
|
1641
|
-
💡 **Suggestion**: Try being more specific with your flow requirements, for example:
|
|
1642
|
-
- "Create an approval flow for incident management"
|
|
1643
|
-
- "Build a notification flow when priority 1 incidents are created"
|
|
1644
|
-
- "Design a flow to update request items when approved"
|
|
1645
|
-
|
|
1646
|
-
🔧 **Debug Info**: flowInstruction=${JSON.stringify(flowInstruction ? Object.keys(flowInstruction) : 'null')}`
|
|
1647
|
-
}]
|
|
1648
|
-
};
|
|
1649
|
-
}
|
|
1650
|
-
const flowStructure = flowInstruction.flowStructure;
|
|
1651
|
-
// Additional safety checks for flowStructure properties
|
|
1652
|
-
const safeGet = (obj, path, defaultValue = 'Unknown') => {
|
|
1653
|
-
const parts = path.split('.');
|
|
1654
|
-
let current = obj;
|
|
1655
|
-
for (const part of parts) {
|
|
1656
|
-
if (!current || typeof current !== 'object')
|
|
1657
|
-
return defaultValue;
|
|
1658
|
-
current = current[part];
|
|
1659
|
-
}
|
|
1660
|
-
return current || defaultValue;
|
|
1661
|
-
};
|
|
1662
|
-
return {
|
|
1663
|
-
content: [
|
|
1664
|
-
{
|
|
1665
|
-
type: 'text',
|
|
1666
|
-
text: `🔍 Flow Structure Preview
|
|
1667
|
-
|
|
1668
|
-
📋 **Flow Information:**
|
|
1669
|
-
- **Name**: ${safeGet(flowStructure, 'name', 'Auto-generated')}
|
|
1670
|
-
- **Description**: ${safeGet(flowStructure, 'description', 'No description')}
|
|
1671
|
-
|
|
1672
|
-
🔄 **Trigger Configuration:**
|
|
1673
|
-
- **Type**: ${safeGet(flowStructure, 'trigger.type', 'manual')}
|
|
1674
|
-
- **Table**: ${safeGet(flowStructure, 'trigger.table', 'task')}
|
|
1675
|
-
- **Condition**: ${safeGet(flowStructure, 'trigger.condition', 'None')}
|
|
1676
|
-
|
|
1677
|
-
📊 **Flow Variables:**
|
|
1678
|
-
${flowStructure.variables && Array.isArray(flowStructure.variables)
|
|
1679
|
-
? flowStructure.variables.map((variable) => `- **${variable.name}** (${variable.type}): ${variable.description}`).join('\n')
|
|
1680
|
-
: '- No variables defined'}
|
|
1681
|
-
|
|
1682
|
-
🏗️ **Flow Activities:**
|
|
1683
|
-
${flowStructure.activities.map((activity, index) => `### ${index + 1}. ${activity.name}
|
|
1684
|
-
**Type**: ${activity.type}
|
|
1685
|
-
**ID**: ${activity.id}
|
|
1686
|
-
${activity.artifact ? `**Uses Artifact**: ${activity.artifact.name} (${activity.artifact.type})` : ''}
|
|
1687
|
-
|
|
1688
|
-
**Inputs:**
|
|
1689
|
-
${Object.entries(activity.inputs).map(([key, value]) => ` - ${key}: ${value}`).join('\n')}
|
|
1690
|
-
|
|
1691
|
-
**Outputs:**
|
|
1692
|
-
${Object.entries(activity.outputs).map(([key, value]) => ` - ${key}: ${value}`).join('\n')}
|
|
1693
|
-
`).join('\n')}
|
|
1694
|
-
|
|
1695
|
-
⚠️ **Error Handling:**
|
|
1696
|
-
${flowStructure.error_handling.map((handler, index) => `${index + 1}. **Condition**: ${handler.condition}
|
|
1697
|
-
**Action**: ${handler.action}
|
|
1698
|
-
**Parameters**: ${JSON.stringify(handler.parameters || {})}`).join('\n\n')}
|
|
1699
|
-
|
|
1700
|
-
🔄 **Flow Execution Path:**
|
|
1701
|
-
1. **${flowStructure.trigger.type}** event occurs on **${flowStructure.trigger.table}**
|
|
1702
|
-
${flowStructure.activities.map((activity, index) => `${index + 2}. Execute **${activity.name}** (${activity.type})`).join('\n')}
|
|
1703
|
-
|
|
1704
|
-
📈 **Flow Metrics:**
|
|
1705
|
-
- **Total Activities**: ${flowStructure.activities.length}
|
|
1706
|
-
- **Variables**: ${flowStructure.variables.length}
|
|
1707
|
-
- **Error Handlers**: ${flowStructure.error_handling.length}
|
|
1708
|
-
- **Artifact Dependencies**: ${flowStructure.activities.filter((a) => a.artifact).length}
|
|
1709
|
-
- **External Integrations**: ${flowStructure.activities.filter((a) => a.type === 'custom_script').length}
|
|
1710
|
-
|
|
1711
|
-
🎯 **Data Flow Analysis:**
|
|
1712
|
-
${this.analyzeDataFlow(flowStructure.activities)}
|
|
1713
|
-
|
|
1714
|
-
✅ **Preview Complete!** The flow structure is optimized and ready for deployment.
|
|
1715
|
-
|
|
1716
|
-
🚀 **To Deploy**: Use \`snow_deploy_composed_flow\` or \`snow_create_complex_flow\` with \`deploy_immediately: true\``,
|
|
1717
|
-
},
|
|
1718
|
-
],
|
|
1719
|
-
};
|
|
1720
|
-
}
|
|
1721
|
-
catch (error) {
|
|
1722
|
-
throw new Error(`Flow structure preview failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
async deployComposedFlow(args) {
|
|
1726
|
-
// Check authentication first
|
|
1727
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
1728
|
-
if (!isAuth) {
|
|
1729
|
-
return {
|
|
1730
|
-
content: [
|
|
1731
|
-
{
|
|
1732
|
-
type: 'text',
|
|
1733
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
1734
|
-
},
|
|
1735
|
-
],
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
try {
|
|
1739
|
-
this.logger.info('Deploying composed flow', { flow: args.flow_instruction });
|
|
1740
|
-
const deploymentResult = await this.composer.deployFlow(args.flow_instruction);
|
|
1741
|
-
const credentials = await this.oauth.loadCredentials();
|
|
1742
|
-
return {
|
|
1743
|
-
content: [
|
|
1744
|
-
{
|
|
1745
|
-
type: 'text',
|
|
1746
|
-
text: `🚀 Flow Deployment Complete!
|
|
1747
|
-
|
|
1748
|
-
✅ **Deployment Status**: ${deploymentResult.success ? 'Successful' : 'Failed'}
|
|
1749
|
-
📋 **Message**: ${deploymentResult.message}
|
|
1750
|
-
|
|
1751
|
-
🎯 **Deployed Flow Details:**
|
|
1752
|
-
- **Name**: ${args.flow_instruction.flowStructure.name}
|
|
1753
|
-
- **Activities**: ${args.flow_instruction.flowStructure.activities.length}
|
|
1754
|
-
- **Artifacts**: ${args.flow_instruction.requiredArtifacts?.length || 0}
|
|
1755
|
-
|
|
1756
|
-
🔗 **ServiceNow Links:**
|
|
1757
|
-
- Flow Designer: https://${credentials?.instance}/flow-designer/flow/${args.flow_instruction.flowStructure.name}
|
|
1758
|
-
- Flow Designer Home: https://${credentials?.instance}/flow-designer
|
|
1759
|
-
|
|
1760
|
-
📊 **Deployment Summary:**
|
|
1761
|
-
${args.flow_instruction.requiredArtifacts?.map((artifact, index) => `${index + 1}. **${artifact.type}**: ${artifact.purpose} - ${artifact.required ? 'Required' : 'Optional'}`)?.join('\n') || 'No artifacts'}
|
|
1762
|
-
|
|
1763
|
-
✅ **Deployment Complete!** Your complex ServiceNow flow with multi-artifact orchestration is now active.`,
|
|
1764
|
-
},
|
|
1765
|
-
],
|
|
1766
|
-
};
|
|
1767
|
-
}
|
|
1768
|
-
catch (error) {
|
|
1769
|
-
throw new Error(`Flow deployment failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
getTableForArtifactType(type) {
|
|
1773
|
-
const tableMapping = {
|
|
1774
|
-
'script_include': 'sys_script_include',
|
|
1775
|
-
'business_rule': 'sys_script',
|
|
1776
|
-
'table': 'sys_db_object',
|
|
1777
|
-
'widget': 'sp_widget',
|
|
1778
|
-
'ui_script': 'sys_ui_script'
|
|
1779
|
-
};
|
|
1780
|
-
return tableMapping[type] || 'sys_metadata';
|
|
1781
|
-
}
|
|
1782
|
-
getFlowStepForArtifact(artifact, flowInstruction) {
|
|
1783
|
-
const step = flowInstruction.flowStructure?.activities?.find((a) => a.artifact_reference && a.artifact_reference.type === artifact.type);
|
|
1784
|
-
return step ? step.name : 'Not used in flow';
|
|
1785
|
-
}
|
|
1786
|
-
getArtifactInputs(artifact) {
|
|
1787
|
-
switch (artifact.type) {
|
|
1788
|
-
case 'script_include':
|
|
1789
|
-
return 'message, target_language, configuration';
|
|
1790
|
-
case 'business_rule':
|
|
1791
|
-
return 'record data, trigger conditions';
|
|
1792
|
-
case 'table':
|
|
1793
|
-
return 'record data, field values';
|
|
1794
|
-
default:
|
|
1795
|
-
return 'context-dependent';
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
getArtifactOutputs(artifact) {
|
|
1799
|
-
switch (artifact.type) {
|
|
1800
|
-
case 'script_include':
|
|
1801
|
-
return 'processed_data, success_flag, error_message';
|
|
1802
|
-
case 'business_rule':
|
|
1803
|
-
return 'validation_result, side_effects';
|
|
1804
|
-
case 'table':
|
|
1805
|
-
return 'record_id, created_timestamp';
|
|
1806
|
-
default:
|
|
1807
|
-
return 'context-dependent';
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
analyzeDataFlow(activities) {
|
|
1811
|
-
let dataFlow = "Data flows through the following path:\n";
|
|
1812
|
-
activities.forEach((activity, index) => {
|
|
1813
|
-
const inputs = Object.keys(activity.inputs).join(', ');
|
|
1814
|
-
const outputs = Object.keys(activity.outputs).join(', ');
|
|
1815
|
-
dataFlow += `${index + 1}. **${activity.name}**: ${inputs} → ${outputs}\n`;
|
|
1816
|
-
});
|
|
1817
|
-
return dataFlow;
|
|
1818
|
-
}
|
|
1819
|
-
/**
|
|
1820
|
-
* Enhanced error handling for ServiceNow API operations
|
|
1821
|
-
*/
|
|
1822
|
-
handleServiceNowError(error, operation) {
|
|
1823
|
-
this.logger.error(`ServiceNow API error during ${operation}`, error);
|
|
1824
|
-
let errorMessage = 'Unknown error occurred';
|
|
1825
|
-
let troubleshooting = [];
|
|
1826
|
-
if (error.response) {
|
|
1827
|
-
const status = error.response.status;
|
|
1828
|
-
const data = error.response.data;
|
|
1829
|
-
switch (status) {
|
|
1830
|
-
case 401:
|
|
1831
|
-
errorMessage = `🚨 Authentication Error (401) - Token Expired or Invalid
|
|
1832
|
-
|
|
1833
|
-
📍 Possible Causes:
|
|
1834
|
-
• OAuth token expired or invalid
|
|
1835
|
-
• ServiceNow instance URL incorrect
|
|
1836
|
-
• Credentials not properly configured
|
|
1837
|
-
|
|
1838
|
-
🔧 Troubleshooting Steps:
|
|
1839
|
-
1. Run diagnostics: snow_auth_diagnostics()
|
|
1840
|
-
2. Re-authenticate: snow-flow auth login
|
|
1841
|
-
3. Check credentials: Verify SNOW_INSTANCE, CLIENT_ID, CLIENT_SECRET
|
|
1842
|
-
4. Verify instance URL format: https://dev123456.service-now.com
|
|
1843
|
-
|
|
1844
|
-
💡 Quick Fix: Run snow_auth_diagnostics() for detailed analysis`;
|
|
1845
|
-
troubleshooting = [
|
|
1846
|
-
'Run snow_auth_diagnostics() for detailed analysis',
|
|
1847
|
-
'Re-authenticate with snow-flow auth login',
|
|
1848
|
-
'Verify .env file OAuth credentials',
|
|
1849
|
-
'Check ServiceNow instance URL format'
|
|
1850
|
-
];
|
|
1851
|
-
break;
|
|
1852
|
-
case 403:
|
|
1853
|
-
errorMessage = `🚨 Permission Error (403) - Insufficient Access Rights
|
|
1854
|
-
|
|
1855
|
-
📍 Possible Causes:
|
|
1856
|
-
• Insufficient permissions for flow operations
|
|
1857
|
-
• Missing required ServiceNow roles
|
|
1858
|
-
• Application scope restrictions
|
|
1859
|
-
|
|
1860
|
-
🔧 Troubleshooting Steps:
|
|
1861
|
-
1. Run diagnostics: snow_auth_diagnostics()
|
|
1862
|
-
2. Check required roles: flow_designer, admin, itil
|
|
1863
|
-
3. Contact ServiceNow administrator for role assignment
|
|
1864
|
-
4. Verify application scope permissions
|
|
1865
|
-
|
|
1866
|
-
💡 Required Roles:
|
|
1867
|
-
• flow_designer: For flow operations
|
|
1868
|
-
• admin: For Update Set management
|
|
1869
|
-
• itil: For incident/request operations`;
|
|
1870
|
-
troubleshooting = [
|
|
1871
|
-
'Run snow_auth_diagnostics() to check permissions',
|
|
1872
|
-
'Verify user has flow_designer, admin, itil roles',
|
|
1873
|
-
'Contact ServiceNow administrator for role assignment',
|
|
1874
|
-
'Check application scope permissions'
|
|
1875
|
-
];
|
|
1876
|
-
break;
|
|
1877
|
-
case 404:
|
|
1878
|
-
errorMessage = `🚨 Flow Testing failed: Endpoint not found (404)
|
|
1879
|
-
|
|
1880
|
-
📍 Possible Causes:
|
|
1881
|
-
• Flow sys_id format incorrect or invalid
|
|
1882
|
-
• API endpoint not available on this ServiceNow instance
|
|
1883
|
-
• Insufficient permissions for this operation
|
|
1884
|
-
• Flow not properly created or activated
|
|
1885
|
-
|
|
1886
|
-
🔧 Troubleshooting Steps:
|
|
1887
|
-
1. Verify artifact exists: snow_get_by_sysid("your-sys-id")
|
|
1888
|
-
2. Check Update Set tracking: snow_update_set_current()
|
|
1889
|
-
3. Try alternative: snow_test_flow_with_mock()
|
|
1890
|
-
4. Verify permissions: snow_auth_diagnostics()
|
|
1891
|
-
|
|
1892
|
-
💡 Alternative Tools:
|
|
1893
|
-
• For flow testing: Use snow_test_flow_with_mock (always works)
|
|
1894
|
-
• For verification: Use snow_get_by_sysid first
|
|
1895
|
-
• For comprehensive testing: Only after basic tests pass`;
|
|
1896
|
-
troubleshooting = [
|
|
1897
|
-
'Use snow_test_flow_with_mock() for reliable testing',
|
|
1898
|
-
'Verify flow exists with snow_get_by_sysid()',
|
|
1899
|
-
'Check Update Set status with snow_update_set_current()',
|
|
1900
|
-
'Run snow_auth_diagnostics() to check permissions'
|
|
1901
|
-
];
|
|
1902
|
-
break;
|
|
1903
|
-
case 429:
|
|
1904
|
-
errorMessage = 'Rate limit exceeded';
|
|
1905
|
-
troubleshooting = [
|
|
1906
|
-
'Wait a few minutes before retrying',
|
|
1907
|
-
'Reduce the frequency of API calls',
|
|
1908
|
-
'Contact ServiceNow administrator about rate limits'
|
|
1909
|
-
];
|
|
1910
|
-
break;
|
|
1911
|
-
case 500:
|
|
1912
|
-
errorMessage = 'ServiceNow server error';
|
|
1913
|
-
troubleshooting = [
|
|
1914
|
-
'Wait a few minutes and try again',
|
|
1915
|
-
'Check ServiceNow instance status',
|
|
1916
|
-
'Contact ServiceNow administrator if issue persists'
|
|
1917
|
-
];
|
|
1918
|
-
break;
|
|
1919
|
-
default:
|
|
1920
|
-
errorMessage = data?.error?.message || `HTTP ${status} error`;
|
|
1921
|
-
troubleshooting = [
|
|
1922
|
-
'Check ServiceNow instance connectivity',
|
|
1923
|
-
'Verify API permissions',
|
|
1924
|
-
'Review ServiceNow logs for details'
|
|
1925
|
-
];
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
else if (error.request) {
|
|
1929
|
-
errorMessage = 'Network connection error';
|
|
1930
|
-
troubleshooting = [
|
|
1931
|
-
'Check internet connectivity',
|
|
1932
|
-
'Verify ServiceNow instance URL',
|
|
1933
|
-
'Check if ServiceNow instance is accessible'
|
|
1934
|
-
];
|
|
1935
|
-
}
|
|
1936
|
-
else {
|
|
1937
|
-
errorMessage = error.message || 'Unknown error';
|
|
1938
|
-
troubleshooting = [
|
|
1939
|
-
'Check the instruction syntax',
|
|
1940
|
-
'Verify all required parameters are provided',
|
|
1941
|
-
'Try a simpler instruction to isolate the issue'
|
|
1942
|
-
];
|
|
1943
|
-
}
|
|
1944
|
-
return {
|
|
1945
|
-
content: [
|
|
1946
|
-
{
|
|
1947
|
-
type: 'text',
|
|
1948
|
-
text: `❌ ${operation} Failed
|
|
1949
|
-
|
|
1950
|
-
**Error Details:**
|
|
1951
|
-
${errorMessage}
|
|
1952
|
-
|
|
1953
|
-
**Troubleshooting Steps:**
|
|
1954
|
-
${troubleshooting.map((step, index) => `${index + 1}. ${step}`).join('\n')}
|
|
1955
|
-
|
|
1956
|
-
**Additional Help:**
|
|
1957
|
-
- Check ServiceNow instance health: https://status.servicenow.com/
|
|
1958
|
-
- Review ServiceNow API documentation
|
|
1959
|
-
- Contact your ServiceNow administrator for permissions
|
|
1960
|
-
- Try using basic functionality first before advanced features
|
|
1961
|
-
|
|
1962
|
-
**Alternative Approaches:**
|
|
1963
|
-
- Use simpler instructions with fewer components
|
|
1964
|
-
- Try analysis tools first (e.g., \`snow_analyze_flow_instruction\`)
|
|
1965
|
-
- Use template matching for common patterns
|
|
1966
|
-
- Break complex flows into smaller parts`,
|
|
1967
|
-
},
|
|
1968
|
-
],
|
|
1969
|
-
};
|
|
1970
|
-
}
|
|
1971
|
-
/**
|
|
1972
|
-
* Retry operation with exponential backoff
|
|
1973
|
-
*/
|
|
1974
|
-
async retryOperation(operation, operationName, maxRetries = 3, baseDelay = 1000) {
|
|
1975
|
-
let lastError;
|
|
1976
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1977
|
-
try {
|
|
1978
|
-
this.logger.info(`Attempting ${operationName} (attempt ${attempt}/${maxRetries})`);
|
|
1979
|
-
return await operation();
|
|
1980
|
-
}
|
|
1981
|
-
catch (error) {
|
|
1982
|
-
lastError = error;
|
|
1983
|
-
if (attempt === maxRetries) {
|
|
1984
|
-
break;
|
|
1985
|
-
}
|
|
1986
|
-
// Don't retry on authentication or permission errors
|
|
1987
|
-
if (error.response?.status === 401 || error.response?.status === 403) {
|
|
1988
|
-
break;
|
|
1989
|
-
}
|
|
1990
|
-
// Don't retry on client errors (except rate limiting)
|
|
1991
|
-
if (error.response?.status >= 400 && error.response?.status < 500 && error.response?.status !== 429) {
|
|
1992
|
-
break;
|
|
1993
|
-
}
|
|
1994
|
-
const delay = baseDelay * Math.pow(2, attempt - 1);
|
|
1995
|
-
this.logger.warn(`${operationName} failed (attempt ${attempt}), retrying in ${delay}ms`, error);
|
|
1996
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
throw lastError;
|
|
2000
|
-
}
|
|
2001
|
-
/**
|
|
2002
|
-
* Format intelligent analysis results for display
|
|
2003
|
-
*/
|
|
2004
|
-
formatIntelligentAnalysis(flowInstruction) {
|
|
2005
|
-
// Backward compatibility - handle cases where intelligent analysis is not available
|
|
2006
|
-
if (!flowInstruction.decisionAnalysis && !flowInstruction.validation &&
|
|
2007
|
-
!flowInstruction.templateMatching && !flowInstruction.subflowCreation) {
|
|
2008
|
-
return `📊 **Flow Analysis:**
|
|
2009
|
-
- **Type**: Standard flow creation
|
|
2010
|
-
- **Processing**: Basic natural language processing applied
|
|
2011
|
-
- **Deployment**: Ready for ServiceNow deployment`;
|
|
2012
|
-
}
|
|
2013
|
-
const analysis = flowInstruction.decisionAnalysis;
|
|
2014
|
-
const validation = flowInstruction.validation;
|
|
2015
|
-
const templateMatching = flowInstruction.templateMatching;
|
|
2016
|
-
const subflowCreation = flowInstruction.subflowCreation;
|
|
2017
|
-
let analysisText = '🧠 **Intelligent Analysis Results:**\n\n';
|
|
2018
|
-
// Decision analysis (if available)
|
|
2019
|
-
if (analysis) {
|
|
2020
|
-
analysisText += `📊 **Decision Analysis:**
|
|
2021
|
-
- **Recommended Type**: ${analysis.recommendedType} (${Math.round(analysis.confidence * 100)}% confidence)
|
|
2022
|
-
- **Rationale**: ${analysis.rationale}
|
|
2023
|
-
- **Complexity**: ${analysis.complexity}
|
|
2024
|
-
- **Reusability**: ${analysis.reusability}
|
|
2025
|
-
- **Context**: ${analysis.context}
|
|
2026
|
-
|
|
2027
|
-
`;
|
|
2028
|
-
}
|
|
2029
|
-
// Validation results (if available)
|
|
2030
|
-
if (validation) {
|
|
2031
|
-
analysisText += `✅ **Validation Results:**
|
|
2032
|
-
- **Valid**: ${validation.isValid ? 'Yes' : 'No'}
|
|
2033
|
-
- **Score**: ${validation.score}/${validation.maxScore}
|
|
2034
|
-
- **Severity**: ${validation.severity}
|
|
2035
|
-
- **Issues**: ${validation.issues?.length || 0} identified
|
|
2036
|
-
- **Recommendations**: ${validation.recommendations?.length || 0} provided
|
|
2037
|
-
|
|
2038
|
-
`;
|
|
2039
|
-
}
|
|
2040
|
-
// Template matching (if available)
|
|
2041
|
-
if (templateMatching) {
|
|
2042
|
-
analysisText += `🎯 **Template Matching:**
|
|
2043
|
-
- **Matches Found**: ${templateMatching.matches}
|
|
2044
|
-
- **Best Match**: ${templateMatching.bestMatch || 'None'}
|
|
2045
|
-
- **Match Confidence**: ${Math.round(templateMatching.confidence * 100)}%
|
|
2046
|
-
|
|
2047
|
-
`;
|
|
2048
|
-
}
|
|
2049
|
-
// Subflow creation (if available)
|
|
2050
|
-
if (subflowCreation) {
|
|
2051
|
-
analysisText += `🔄 **Subflow Creation:**
|
|
2052
|
-
- **Candidates Identified**: ${subflowCreation.candidatesIdentified}
|
|
2053
|
-
- **Subflows Created**: ${subflowCreation.subflowsCreated}
|
|
2054
|
-
- **Success Rate**: ${subflowCreation.candidatesIdentified > 0 ? Math.round((subflowCreation.subflowsCreated / subflowCreation.candidatesIdentified) * 100) : 0}%
|
|
2055
|
-
|
|
2056
|
-
`;
|
|
2057
|
-
}
|
|
2058
|
-
// Recommendations
|
|
2059
|
-
analysisText += `💡 **Recommendations:**
|
|
2060
|
-
${flowInstruction.recommendations?.map((rec, index) => `${index + 1}. ${rec}`).join('\n') || 'No specific recommendations'}`;
|
|
2061
|
-
return analysisText;
|
|
2062
|
-
}
|
|
2063
|
-
/**
|
|
2064
|
-
* Safe method to access composer features with fallback
|
|
2065
|
-
*/
|
|
2066
|
-
async safeComposerOperation(operation, fallbackOperation, operationName) {
|
|
2067
|
-
try {
|
|
2068
|
-
return await operation();
|
|
2069
|
-
}
|
|
2070
|
-
catch (error) {
|
|
2071
|
-
this.logger.warn(`${operationName} failed, falling back to basic operation`, error);
|
|
2072
|
-
return await fallbackOperation();
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
/**
|
|
2076
|
-
* Intelligent flow analysis tool
|
|
2077
|
-
*/
|
|
2078
|
-
async intelligentFlowAnalysis(args) {
|
|
2079
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
2080
|
-
if (!isAuth) {
|
|
2081
|
-
return {
|
|
2082
|
-
content: [
|
|
2083
|
-
{
|
|
2084
|
-
type: 'text',
|
|
2085
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
2086
|
-
},
|
|
2087
|
-
],
|
|
2088
|
-
};
|
|
2089
|
-
}
|
|
2090
|
-
try {
|
|
2091
|
-
this.logger.info('Performing intelligent flow analysis', { instruction: args.instruction });
|
|
2092
|
-
const analysisResult = await this.composer.getFlowAnalysisSummary(args.instruction);
|
|
2093
|
-
return {
|
|
2094
|
-
content: [
|
|
2095
|
-
{
|
|
2096
|
-
type: 'text',
|
|
2097
|
-
text: `🧠 Intelligent Flow Analysis Results
|
|
2098
|
-
|
|
2099
|
-
📝 **Original Instruction:**
|
|
2100
|
-
"${args.instruction}"
|
|
2101
|
-
|
|
2102
|
-
🎯 **Decision Analysis:**
|
|
2103
|
-
- **Recommended Type**: ${analysisResult.decision?.recommendedType || 'Unknown'}
|
|
2104
|
-
- **Confidence**: ${analysisResult.decision?.confidence ? Math.round(analysisResult.decision.confidence * 100) + '%' : 'Unknown'}
|
|
2105
|
-
- **Rationale**: ${analysisResult.decision?.rationale || 'No rationale provided'}
|
|
2106
|
-
|
|
2107
|
-
📊 **Complexity Assessment:**
|
|
2108
|
-
- **Level**: ${analysisResult.complexity || 'Unknown'}
|
|
2109
|
-
- **Reusability**: ${analysisResult.reusability || 'Unknown'}
|
|
2110
|
-
- **Context**: ${analysisResult.context || 'Unknown'}
|
|
2111
|
-
|
|
2112
|
-
✅ **Validation Results:**
|
|
2113
|
-
- **Valid**: ${analysisResult.validation?.isValid ? 'Yes' : 'No'}
|
|
2114
|
-
- **Score**: ${analysisResult.validation?.score || 0}/${analysisResult.validation?.maxScore || 0}
|
|
2115
|
-
|
|
2116
|
-
🎯 **Template Matching:**
|
|
2117
|
-
- **Matches Found**: ${analysisResult.templates?.matchCount || 0}
|
|
2118
|
-
- **Best Match**: ${analysisResult.templates?.bestMatch || 'None'}
|
|
2119
|
-
- **Confidence**: ${analysisResult.templates?.confidence ? Math.round(analysisResult.templates.confidence * 100) + '%' : 'N/A'}
|
|
2120
|
-
|
|
2121
|
-
🔄 **Subflow Opportunities:**
|
|
2122
|
-
- **Candidates Identified**: ${analysisResult.subflowCandidates || 0}
|
|
2123
|
-
- **Alternatives Available**: ${analysisResult.alternatives?.length || 0}
|
|
2124
|
-
|
|
2125
|
-
💡 **Key Insights:**
|
|
2126
|
-
- Flow complexity suggests ${analysisResult.complexity === 'high' ? 'breaking into smaller components' : 'keeping as single flow'}
|
|
2127
|
-
- ${analysisResult.reusability === 'high' ? 'High reusability indicates subflow opportunities' : 'Low reusability suggests single-use flow'}
|
|
2128
|
-
- ${analysisResult.templates?.matchCount > 0 ? 'Template matching available for consistency' : 'Custom implementation required'}
|
|
2129
|
-
|
|
2130
|
-
🚀 **Next Steps:**
|
|
2131
|
-
1. Use \`snow_template_matching\` to explore template options
|
|
2132
|
-
2. Run \`snow_create_flow\` with deploy_immediately: true to implement the recommended approach
|
|
2133
|
-
3. Consider \`snow_scope_optimization\` for deployment strategy
|
|
2134
|
-
|
|
2135
|
-
✅ **Analysis Complete!** The instruction has been comprehensively analyzed with intelligent insights.`,
|
|
2136
|
-
},
|
|
2137
|
-
],
|
|
2138
|
-
};
|
|
2139
|
-
}
|
|
2140
|
-
catch (error) {
|
|
2141
|
-
throw new Error(`Intelligent flow analysis failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
/**
|
|
2145
|
-
* Scope optimization tool
|
|
2146
|
-
*/
|
|
2147
|
-
async scopeOptimization(args) {
|
|
2148
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
2149
|
-
if (!isAuth) {
|
|
2150
|
-
return {
|
|
2151
|
-
content: [
|
|
2152
|
-
{
|
|
2153
|
-
type: 'text',
|
|
2154
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
2155
|
-
},
|
|
2156
|
-
],
|
|
2157
|
-
};
|
|
2158
|
-
}
|
|
2159
|
-
try {
|
|
2160
|
-
this.logger.info('Performing scope optimization analysis', {
|
|
2161
|
-
artifactType: args.artifact_type,
|
|
2162
|
-
environmentType: args.environment_type
|
|
2163
|
-
});
|
|
2164
|
-
// Create a deployment context for analysis
|
|
2165
|
-
const deploymentContext = {
|
|
2166
|
-
artifactType: args.artifact_type,
|
|
2167
|
-
artifactData: args.artifact_data,
|
|
2168
|
-
environmentType: args.environment_type || 'development'
|
|
2169
|
-
};
|
|
2170
|
-
// Use the composer's scope manager for analysis
|
|
2171
|
-
const scopeAnalysis = await this.composer.scopeManagerInstance.makeScopeDecision(deploymentContext);
|
|
2172
|
-
return {
|
|
2173
|
-
content: [
|
|
2174
|
-
{
|
|
2175
|
-
type: 'text',
|
|
2176
|
-
text: `🎯 Scope Optimization Analysis
|
|
2177
|
-
|
|
2178
|
-
📋 **Artifact Information:**
|
|
2179
|
-
- **Type**: ${args.artifact_type}
|
|
2180
|
-
- **Environment**: ${args.environment_type || 'development'}
|
|
2181
|
-
- **Name**: ${args.artifact_data?.name || 'Unknown'}
|
|
2182
|
-
|
|
2183
|
-
🎯 **Scope Recommendation:**
|
|
2184
|
-
- **Recommended Scope**: ${scopeAnalysis?.selectedScope || 'global'}
|
|
2185
|
-
- **Confidence**: ${scopeAnalysis?.confidence ? Math.round(scopeAnalysis.confidence * 100) + '%' : 'Unknown'}
|
|
2186
|
-
- **Rationale**: ${scopeAnalysis?.rationale || 'Global scope provides maximum flexibility and reusability'}
|
|
2187
|
-
|
|
2188
|
-
🔄 **Fallback Strategy:**
|
|
2189
|
-
- **Fallback Scope**: ${scopeAnalysis?.fallbackScope || 'application'}
|
|
2190
|
-
- **Fallback Triggers**: Permission issues, compliance requirements, environment restrictions
|
|
2191
|
-
|
|
2192
|
-
✅ **Validation Results:**
|
|
2193
|
-
- **Permissions**: ${scopeAnalysis?.validationResult?.permissions || 'Valid'}
|
|
2194
|
-
- **Compliance**: ${scopeAnalysis?.validationResult?.compliance || 'Compliant'}
|
|
2195
|
-
- **Dependencies**: ${scopeAnalysis?.validationResult?.dependencies || 'Resolved'}
|
|
2196
|
-
|
|
2197
|
-
💡 **Recommendations:**
|
|
2198
|
-
${scopeAnalysis?.recommendations?.map((rec, index) => `${index + 1}. ${rec}`).join('\n') || '1. Deploy to global scope for maximum reusability\n2. Ensure proper naming conventions\n3. Document scope decision for future reference'}
|
|
2199
|
-
|
|
2200
|
-
🚀 **Deployment Strategy:**
|
|
2201
|
-
1. **Primary**: Deploy to ${scopeAnalysis?.selectedScope || 'global'} scope
|
|
2202
|
-
2. **Fallback**: Use ${scopeAnalysis?.fallbackScope || 'application'} scope if primary fails
|
|
2203
|
-
3. **Validation**: Comprehensive pre-deployment checks
|
|
2204
|
-
4. **Monitoring**: Post-deployment validation and rollback capability
|
|
2205
|
-
|
|
2206
|
-
⚠️ **Important Considerations:**
|
|
2207
|
-
- Global scope artifacts are shared across all applications
|
|
2208
|
-
- Application scope provides isolation but limits reusability
|
|
2209
|
-
- Environment-specific considerations may override recommendations
|
|
2210
|
-
- Compliance requirements may dictate scope selection
|
|
2211
|
-
|
|
2212
|
-
✅ **Analysis Complete!** Scope optimization strategy is ready for implementation.`,
|
|
2213
|
-
},
|
|
2214
|
-
],
|
|
2215
|
-
};
|
|
2216
|
-
}
|
|
2217
|
-
catch (error) {
|
|
2218
|
-
throw new Error(`Scope optimization failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
/**
|
|
2222
|
-
* Template matching tool
|
|
2223
|
-
*/
|
|
2224
|
-
async templateMatching(args) {
|
|
2225
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
2226
|
-
if (!isAuth) {
|
|
2227
|
-
return {
|
|
2228
|
-
content: [
|
|
2229
|
-
{
|
|
2230
|
-
type: 'text',
|
|
2231
|
-
text: '❌ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.',
|
|
2232
|
-
},
|
|
2233
|
-
],
|
|
2234
|
-
};
|
|
2235
|
-
}
|
|
2236
|
-
try {
|
|
2237
|
-
this.logger.info('Performing template matching', {
|
|
2238
|
-
instruction: args.instruction,
|
|
2239
|
-
minimumConfidence: args.minimum_confidence || 0.6
|
|
2240
|
-
});
|
|
2241
|
-
const matchingResults = await this.composer.patternTemplatesInstance.findMatchingTemplates(args.instruction);
|
|
2242
|
-
// Filter by minimum confidence if specified
|
|
2243
|
-
const filteredResults = matchingResults?.filter((result) => result.confidence >= (args.minimum_confidence || 0.6)) || [];
|
|
2244
|
-
// Filter by categories if specified
|
|
2245
|
-
const categoryFilteredResults = args.template_categories ?
|
|
2246
|
-
filteredResults.filter((result) => args.template_categories.includes(result.template.category)) : filteredResults;
|
|
2247
|
-
return {
|
|
2248
|
-
content: [
|
|
2249
|
-
{
|
|
2250
|
-
type: 'text',
|
|
2251
|
-
text: `🎯 Template Matching Results
|
|
2252
|
-
|
|
2253
|
-
📝 **Search Criteria:**
|
|
2254
|
-
- **Instruction**: "${args.instruction}"
|
|
2255
|
-
- **Minimum Confidence**: ${Math.round((args.minimum_confidence || 0.6) * 100)}%
|
|
2256
|
-
- **Categories**: ${args.template_categories?.join(', ') || 'All categories'}
|
|
2257
|
-
|
|
2258
|
-
🎯 **Matching Templates (${categoryFilteredResults.length} found):**
|
|
2259
|
-
|
|
2260
|
-
${categoryFilteredResults.map((result, index) => `### ${index + 1}. ${result.template.name}
|
|
2261
|
-
**Category**: ${result.template.category}
|
|
2262
|
-
**Confidence**: ${Math.round(result.confidence * 100)}%
|
|
2263
|
-
**Description**: ${result.template.description}
|
|
2264
|
-
|
|
2265
|
-
**Template Features:**
|
|
2266
|
-
- **Triggers**: ${result.template.triggers?.join(', ') || 'Generic'}
|
|
2267
|
-
- **Activities**: ${result.template.activities?.length || 0} predefined activities
|
|
2268
|
-
- **Variables**: ${result.template.variables?.length || 0} template variables
|
|
2269
|
-
- **Customizable**: ${result.template.customizable ? 'Yes' : 'No'}
|
|
2270
|
-
|
|
2271
|
-
**Why this matches:**
|
|
2272
|
-
${result.matchingReasons?.map((reason) => `- ${reason}`).join('\n') || '- Pattern similarity with instruction'}
|
|
2273
|
-
|
|
2274
|
-
**Confidence Breakdown:**
|
|
2275
|
-
- **Keyword Match**: ${Math.round(result.scores?.keywords * 100)}%
|
|
2276
|
-
- **Intent Match**: ${Math.round(result.scores?.intent * 100)}%
|
|
2277
|
-
- **Structure Match**: ${Math.round(result.scores?.structure * 100)}%
|
|
2278
|
-
- **Context Match**: ${Math.round(result.scores?.context * 100)}%`).join('\n\n')}
|
|
2279
|
-
|
|
2280
|
-
${categoryFilteredResults.length === 0 ? `🔍 **No templates found matching your criteria.**
|
|
2281
|
-
|
|
2282
|
-
**Suggestions:**
|
|
2283
|
-
1. Lower the minimum confidence threshold (currently ${Math.round((args.minimum_confidence || 0.6) * 100)}%)
|
|
2284
|
-
2. Remove category filters to see all available templates
|
|
2285
|
-
3. Try different keywords or phrases in your instruction
|
|
2286
|
-
4. Consider creating a custom flow without templates` : ''}
|
|
2287
|
-
|
|
2288
|
-
💡 **Template Usage:**
|
|
2289
|
-
- **Best Match**: ${categoryFilteredResults[0]?.template.name || 'None'}
|
|
2290
|
-
- **Confidence**: ${categoryFilteredResults[0]?.confidence ? Math.round(categoryFilteredResults[0].confidence * 100) + '%' : 'N/A'}
|
|
2291
|
-
- **Recommended**: ${categoryFilteredResults[0]?.confidence >= 0.8 ? 'Yes - High confidence match' : 'Consider manual review'}
|
|
2292
|
-
|
|
2293
|
-
🚀 **Next Steps:**
|
|
2294
|
-
1. Use \`snow_create_flow\` with deploy_immediately: true to implement the best matching template
|
|
2295
|
-
2. Review template customization options
|
|
2296
|
-
3. Consider \`snow_intelligent_flow_analysis\` for detailed analysis
|
|
2297
|
-
4. Modify instruction if no suitable templates found
|
|
2298
|
-
|
|
2299
|
-
✅ **Template matching complete!** ${categoryFilteredResults.length > 0 ? 'Templates ready for implementation.' : 'Consider custom flow creation.'}`,
|
|
2300
|
-
},
|
|
2301
|
-
],
|
|
2302
|
-
};
|
|
2303
|
-
}
|
|
2304
|
-
catch (error) {
|
|
2305
|
-
throw new Error(`Template matching failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
async start() {
|
|
2309
|
-
const transport = new stdio_js_1.StdioServerTransport();
|
|
2310
|
-
await this.server.connect(transport);
|
|
2311
|
-
this.logger.info('ServiceNow Flow Composer MCP Server started');
|
|
2312
|
-
}
|
|
2313
|
-
/**
|
|
2314
|
-
* Map trigger type to XML format
|
|
2315
|
-
*/
|
|
2316
|
-
mapTriggerTypeToXML(triggerType) {
|
|
2317
|
-
const mapping = {
|
|
2318
|
-
'record_created': 'record_created',
|
|
2319
|
-
'record_updated': 'record_updated',
|
|
2320
|
-
'manual': 'manual',
|
|
2321
|
-
'scheduled': 'scheduled',
|
|
2322
|
-
'create': 'record_created',
|
|
2323
|
-
'update': 'record_updated',
|
|
2324
|
-
'on_create': 'record_created',
|
|
2325
|
-
'on_update': 'record_updated'
|
|
2326
|
-
};
|
|
2327
|
-
return mapping[triggerType.toLowerCase()] || 'manual';
|
|
2328
|
-
}
|
|
2329
|
-
/**
|
|
2330
|
-
* Convert activities to XML format
|
|
2331
|
-
*/
|
|
2332
|
-
convertActivitiesToXML(activities) {
|
|
2333
|
-
return activities.map((activity, index) => ({
|
|
2334
|
-
type: this.mapActivityTypeToXML(activity.type),
|
|
2335
|
-
name: activity.name || `Activity ${index + 1}`,
|
|
2336
|
-
inputs: activity.inputs || {},
|
|
2337
|
-
order: (index + 1) * 100,
|
|
2338
|
-
description: activity.description || activity.name
|
|
2339
|
-
}));
|
|
2340
|
-
}
|
|
2341
|
-
/**
|
|
2342
|
-
* Convert activities to CompleteFlowXMLGenerator format
|
|
2343
|
-
*/
|
|
2344
|
-
convertActivitiesToCompleteFormat(activities) {
|
|
2345
|
-
return activities.map((activity, index) => ({
|
|
2346
|
-
name: activity.name || `Activity ${index + 1}`,
|
|
2347
|
-
type: this.mapActivityTypeToXML(activity.type),
|
|
2348
|
-
order: (index + 1) * 100,
|
|
2349
|
-
description: activity.description || activity.name || '',
|
|
2350
|
-
inputs: activity.inputs || {},
|
|
2351
|
-
outputs: activity.outputs || {},
|
|
2352
|
-
condition: activity.condition || '',
|
|
2353
|
-
artifact_reference: activity.artifact_reference,
|
|
2354
|
-
subflow_reference: activity.subflow_reference
|
|
2355
|
-
}));
|
|
2356
|
-
}
|
|
2357
|
-
/**
|
|
2358
|
-
* Map activity type to XML format
|
|
2359
|
-
*/
|
|
2360
|
-
mapActivityTypeToXML(activityType) {
|
|
2361
|
-
const mapping = {
|
|
2362
|
-
'approval': 'approval',
|
|
2363
|
-
'notification': 'notification',
|
|
2364
|
-
'email': 'notification',
|
|
2365
|
-
'script': 'script',
|
|
2366
|
-
'create_record': 'create_record',
|
|
2367
|
-
'update_record': 'update_record',
|
|
2368
|
-
'rest_call': 'rest_step',
|
|
2369
|
-
'condition': 'condition',
|
|
2370
|
-
'subflow': 'assign_subflow'
|
|
2371
|
-
};
|
|
2372
|
-
return mapping[activityType.toLowerCase()] || 'script';
|
|
2373
|
-
}
|
|
2374
|
-
/**
|
|
2375
|
-
* Comprehensive flow verification with retry logic
|
|
2376
|
-
*/
|
|
2377
|
-
async verifyFlowInServiceNow(flowName) {
|
|
2378
|
-
const maxRetries = 5;
|
|
2379
|
-
const baseDelay = 2000; // Start with 2 seconds
|
|
2380
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
2381
|
-
try {
|
|
2382
|
-
// Progressive delay - ServiceNow needs time to process
|
|
2383
|
-
if (attempt > 1) {
|
|
2384
|
-
const delay = baseDelay * attempt; // 2s, 4s, 6s, 8s, 10s
|
|
2385
|
-
this.logger.info(`Waiting ${delay}ms before verification attempt ${attempt}/${maxRetries}`);
|
|
2386
|
-
await this.sleep(delay);
|
|
2387
|
-
}
|
|
2388
|
-
const ServiceNowClient = (await Promise.resolve().then(() => __importStar(require('../utils/servicenow-client.js')))).ServiceNowClient;
|
|
2389
|
-
const client = new ServiceNowClient();
|
|
2390
|
-
// Multi-table verification for comprehensive check
|
|
2391
|
-
const verificationPromises = [
|
|
2392
|
-
// Check main flow table
|
|
2393
|
-
client.makeRequest({
|
|
2394
|
-
method: 'GET',
|
|
2395
|
-
url: '/api/now/table/sys_hub_flow',
|
|
2396
|
-
params: {
|
|
2397
|
-
sysparm_query: `name=${flowName}^ORsys_name=${flowName}`,
|
|
2398
|
-
sysparm_fields: 'sys_id,name,sys_name,active,table,description',
|
|
2399
|
-
sysparm_limit: 5
|
|
2400
|
-
}
|
|
2401
|
-
}),
|
|
2402
|
-
// Check flow snapshots
|
|
2403
|
-
client.makeRequest({
|
|
2404
|
-
method: 'GET',
|
|
2405
|
-
url: '/api/now/table/sys_hub_flow_snapshot',
|
|
2406
|
-
params: {
|
|
2407
|
-
sysparm_query: `flow.name=${flowName}^ORflow.sys_name=${flowName}`,
|
|
2408
|
-
sysparm_fields: 'sys_id,flow,name,active',
|
|
2409
|
-
sysparm_limit: 5
|
|
2410
|
-
}
|
|
2411
|
-
}),
|
|
2412
|
-
// Check trigger instances
|
|
2413
|
-
client.makeRequest({
|
|
2414
|
-
method: 'GET',
|
|
2415
|
-
url: '/api/now/table/sys_hub_trigger_instance',
|
|
2416
|
-
params: {
|
|
2417
|
-
sysparm_query: `flow.name=${flowName}^ORflow.sys_name=${flowName}`,
|
|
2418
|
-
sysparm_fields: 'sys_id,flow,trigger_type',
|
|
2419
|
-
sysparm_limit: 5
|
|
2420
|
-
}
|
|
2421
|
-
})
|
|
2422
|
-
];
|
|
2423
|
-
const [flowCheck, snapshotCheck, triggerCheck] = await Promise.allSettled(verificationPromises);
|
|
2424
|
-
// Analyze results
|
|
2425
|
-
const flowExists = flowCheck.status === 'fulfilled' &&
|
|
2426
|
-
flowCheck.value.result &&
|
|
2427
|
-
flowCheck.value.result.length > 0;
|
|
2428
|
-
const snapshotExists = snapshotCheck.status === 'fulfilled' &&
|
|
2429
|
-
snapshotCheck.value.result &&
|
|
2430
|
-
snapshotCheck.value.result.length > 0;
|
|
2431
|
-
const triggerExists = triggerCheck.status === 'fulfilled' &&
|
|
2432
|
-
triggerCheck.value.result &&
|
|
2433
|
-
triggerCheck.value.result.length > 0;
|
|
2434
|
-
// Comprehensive verification result
|
|
2435
|
-
if (flowExists) {
|
|
2436
|
-
const flowData = flowCheck.value.result[0];
|
|
2437
|
-
return {
|
|
2438
|
-
verified: true,
|
|
2439
|
-
sys_id: flowData.sys_id,
|
|
2440
|
-
name: flowData.name || flowData.sys_name,
|
|
2441
|
-
active: flowData.active,
|
|
2442
|
-
table: flowData.table,
|
|
2443
|
-
has_snapshot: snapshotExists,
|
|
2444
|
-
has_trigger: triggerExists,
|
|
2445
|
-
verification_attempt: attempt,
|
|
2446
|
-
verification_method: 'multi_table_comprehensive',
|
|
2447
|
-
completeness_score: (flowExists ? 1 : 0) + (snapshotExists ? 1 : 0) + (triggerExists ? 1 : 0),
|
|
2448
|
-
url: `https://${await this.getInstanceUrl()}/flow-designer/flow/${flowData.sys_id}`
|
|
2449
|
-
};
|
|
2450
|
-
}
|
|
2451
|
-
// Log partial results for debugging
|
|
2452
|
-
this.logger.warn(`Verification attempt ${attempt}: Flow=${flowExists}, Snapshot=${snapshotExists}, Trigger=${triggerExists}`);
|
|
2453
|
-
// If this is the last attempt, return detailed failure info
|
|
2454
|
-
if (attempt === maxRetries) {
|
|
2455
|
-
return {
|
|
2456
|
-
verified: false,
|
|
2457
|
-
reason: 'Flow not found after comprehensive verification',
|
|
2458
|
-
attempts: maxRetries,
|
|
2459
|
-
partial_results: {
|
|
2460
|
-
flow_found: flowExists,
|
|
2461
|
-
snapshot_found: snapshotExists,
|
|
2462
|
-
trigger_found: triggerExists
|
|
2463
|
-
},
|
|
2464
|
-
search_query: `name=${flowName}`,
|
|
2465
|
-
recommendation: 'Check ServiceNow Flow Designer manually or verify deployment was successful'
|
|
2466
|
-
};
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
catch (error) {
|
|
2470
|
-
this.logger.warn(`Verification attempt ${attempt} failed:`, error);
|
|
2471
|
-
// If this is the last attempt, include error details
|
|
2472
|
-
if (attempt === maxRetries) {
|
|
2473
|
-
return {
|
|
2474
|
-
verified: false,
|
|
2475
|
-
reason: 'Verification failed due to error',
|
|
2476
|
-
error: error instanceof Error ? error.message : String(error),
|
|
2477
|
-
attempts: maxRetries
|
|
2478
|
-
};
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
return {
|
|
2483
|
-
verified: false,
|
|
2484
|
-
reason: 'Max verification attempts exceeded',
|
|
2485
|
-
attempts: maxRetries
|
|
2486
|
-
};
|
|
2487
|
-
}
|
|
2488
|
-
/**
|
|
2489
|
-
* Helper to get instance URL for flow links
|
|
2490
|
-
*/
|
|
2491
|
-
async getInstanceUrl() {
|
|
2492
|
-
try {
|
|
2493
|
-
const credentials = await this.oauth.loadCredentials();
|
|
2494
|
-
return credentials?.instance || 'your-instance.service-now.com';
|
|
2495
|
-
}
|
|
2496
|
-
catch {
|
|
2497
|
-
return 'your-instance.service-now.com';
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
|
-
/**
|
|
2501
|
-
* Sleep utility
|
|
2502
|
-
*/
|
|
2503
|
-
sleep(ms) {
|
|
2504
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
2505
|
-
}
|
|
2506
|
-
/**
|
|
2507
|
-
* Generate manual import guide for failed deployments
|
|
2508
|
-
*/
|
|
2509
|
-
generateManualImportGuide(xmlFilePath) {
|
|
2510
|
-
// BUG-004 FIX: Handle undefined or empty file paths properly
|
|
2511
|
-
if (!xmlFilePath || xmlFilePath.trim() === '') {
|
|
2512
|
-
return `
|
|
2513
|
-
**⚠️ No XML file was generated**
|
|
2514
|
-
|
|
2515
|
-
Since the flow XML generation failed, you'll need to:
|
|
2516
|
-
|
|
2517
|
-
1. **Create the flow manually in ServiceNow**:
|
|
2518
|
-
- Navigate to Flow Designer
|
|
2519
|
-
- Click "New" > "Flow"
|
|
2520
|
-
- Build the flow based on your requirements
|
|
2521
|
-
|
|
2522
|
-
2. **Alternative: Use the deployment tool**:
|
|
2523
|
-
- Run: snow-flow deploy --retry
|
|
2524
|
-
- This will attempt to regenerate and deploy the flow
|
|
2525
|
-
|
|
2526
|
-
3. **Check error logs**:
|
|
2527
|
-
- Review the error details above to understand why XML generation failed
|
|
2528
|
-
- Common causes: missing artifacts, permission issues, or invalid flow structure`;
|
|
2529
|
-
}
|
|
2530
|
-
return `
|
|
2531
|
-
1. **Navigate to ServiceNow**:
|
|
2532
|
-
- System Update Sets > Retrieved Update Sets
|
|
2533
|
-
|
|
2534
|
-
2. **Import XML**:
|
|
2535
|
-
- Click "Import Update Set from XML"
|
|
2536
|
-
- Select file: ${xmlFilePath}
|
|
2537
|
-
- Click "Upload"
|
|
2538
|
-
|
|
2539
|
-
3. **Preview**:
|
|
2540
|
-
- Find your imported update set
|
|
2541
|
-
- Click "Preview Update Set"
|
|
2542
|
-
- Review any conflicts or issues
|
|
2543
|
-
|
|
2544
|
-
4. **Commit**:
|
|
2545
|
-
- If preview is clean, click "Commit Update Set"
|
|
2546
|
-
- Your flow will be available in Flow Designer
|
|
2547
|
-
|
|
2548
|
-
5. **Verify**:
|
|
2549
|
-
- Navigate to Flow Designer
|
|
2550
|
-
- Check "My Flows" for your new flow`;
|
|
2551
|
-
}
|
|
2552
|
-
/**
|
|
2553
|
-
* Deploy with fallback strategies + MANDATORY VERIFICATION
|
|
2554
|
-
* 🔴 CRITICAL FIX: SNOW-001 Silent Deployment Failures
|
|
2555
|
-
* Each strategy now MUST verify that the flow actually exists before claiming success
|
|
2556
|
-
*/
|
|
2557
|
-
async deployWithFallback(xmlFilePath, flowDefinition) {
|
|
2558
|
-
// 🚀 ENHANCED: Use our complete solution components
|
|
2559
|
-
const toolRegistry = (0, mcp_tool_registry_js_1.getToolRegistry)();
|
|
2560
|
-
try {
|
|
2561
|
-
// Use our enhanced deployment system
|
|
2562
|
-
this.logger.info('🚀 Using enhanced deployment system with complete solution');
|
|
2563
|
-
// Deploy using UpdateSetImporter
|
|
2564
|
-
const importResult = await (0, update_set_importer_js_1.deployFlowXML)(xmlFilePath, true);
|
|
2565
|
-
if (importResult.success) {
|
|
2566
|
-
// Extract complete metadata using DeploymentMetadataHandler
|
|
2567
|
-
const metadataResult = await (0, deployment_metadata_handler_js_1.ensureDeploymentMetadata)('flow', { success: true, flow: { sys_id: importResult.flowSysId } }, {
|
|
2568
|
-
flowSysId: importResult.flowSysId,
|
|
2569
|
-
name: flowDefinition.name,
|
|
2570
|
-
update_set_id: importResult.localUpdateSetId
|
|
2571
|
-
});
|
|
2572
|
-
if (metadataResult.success && metadataResult.metadata) {
|
|
2573
|
-
return {
|
|
2574
|
-
success: true,
|
|
2575
|
-
strategy: 'Enhanced XML Update Set',
|
|
2576
|
-
result: importResult,
|
|
2577
|
-
verification: {
|
|
2578
|
-
verified: true,
|
|
2579
|
-
sys_id: metadataResult.metadata.sys_id,
|
|
2580
|
-
url: metadataResult.metadata.ui_url,
|
|
2581
|
-
api_endpoint: metadataResult.metadata.api_endpoint,
|
|
2582
|
-
has_flow: true,
|
|
2583
|
-
has_snapshot: true,
|
|
2584
|
-
has_trigger: true,
|
|
2585
|
-
completeness_score: 100,
|
|
2586
|
-
verification_attempt: 1,
|
|
2587
|
-
reason: 'Complete deployment with metadata verification'
|
|
2588
|
-
},
|
|
2589
|
-
deployment_verified: true,
|
|
2590
|
-
metadata: metadataResult.metadata
|
|
2591
|
-
};
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
// If enhanced deployment fails, try legacy methods
|
|
2595
|
-
this.logger.warn('Enhanced deployment failed, trying fallback strategies');
|
|
2596
|
-
}
|
|
2597
|
-
catch (error) {
|
|
2598
|
-
this.logger.warn('Enhanced deployment error:', error);
|
|
2599
|
-
}
|
|
2600
|
-
// Fallback to legacy strategies
|
|
2601
|
-
const strategies = [
|
|
2602
|
-
{
|
|
2603
|
-
name: 'XML Remote Update Set',
|
|
2604
|
-
fn: async () => await this.deployXMLToServiceNowWithVerification(xmlFilePath, flowDefinition.name)
|
|
2605
|
-
},
|
|
2606
|
-
{
|
|
2607
|
-
name: 'Direct Table API',
|
|
2608
|
-
fn: async () => await this.deployViaTableAPIWithVerification(flowDefinition)
|
|
2609
|
-
}
|
|
2610
|
-
];
|
|
2611
|
-
let lastError;
|
|
2612
|
-
for (const strategy of strategies) {
|
|
2613
|
-
try {
|
|
2614
|
-
this.logger.info(`Trying deployment strategy: ${strategy.name}`);
|
|
2615
|
-
const result = await strategy.fn();
|
|
2616
|
-
// 🔴 CRITICAL: Strategy can only return if it includes verification proof
|
|
2617
|
-
if (!result.verification || !result.verification.verified) {
|
|
2618
|
-
throw new Error(`${strategy.name} completed but verification failed: ${result.verification?.reason || 'Unknown verification failure'}`);
|
|
2619
|
-
}
|
|
2620
|
-
return {
|
|
2621
|
-
success: true,
|
|
2622
|
-
strategy: strategy.name,
|
|
2623
|
-
result,
|
|
2624
|
-
verification: result.verification,
|
|
2625
|
-
deployment_verified: true
|
|
2626
|
-
};
|
|
2627
|
-
}
|
|
2628
|
-
catch (error) {
|
|
2629
|
-
this.logger.warn(`Strategy ${strategy.name} failed:`, error);
|
|
2630
|
-
lastError = error;
|
|
2631
|
-
}
|
|
2632
|
-
}
|
|
2633
|
-
throw lastError || new Error('All deployment strategies failed');
|
|
2634
|
-
}
|
|
2635
|
-
/**
|
|
2636
|
-
* 🔴 CRITICAL FIX: Deploy XML with MANDATORY verification
|
|
2637
|
-
* SNOW-001: Prevents false positive where XML import succeeds but flow doesn't exist
|
|
2638
|
-
*/
|
|
2639
|
-
async deployXMLToServiceNowWithVerification(xmlFilePath, flowName) {
|
|
2640
|
-
this.logger.info(`🔴 CRITICAL FIX: XML deployment with mandatory verification for: ${flowName}`);
|
|
2641
|
-
// Step 1: Deploy the XML (existing logic)
|
|
2642
|
-
await this.deployXMLToServiceNow(xmlFilePath);
|
|
2643
|
-
// Step 2: MANDATORY verification - wait for ServiceNow to process
|
|
2644
|
-
this.logger.info('🔍 Starting mandatory post-deployment verification...');
|
|
2645
|
-
const verification = await this.verifyFlowInServiceNow(flowName);
|
|
2646
|
-
if (!verification.verified) {
|
|
2647
|
-
// 🔴 CRITICAL: XML deployment succeeded but flow doesn't exist
|
|
2648
|
-
const errorMsg = `🔴 CRITICAL: XML deployment appeared to succeed but flow verification failed: ${verification.reason}`;
|
|
2649
|
-
this.logger.error('SNOW-001 detected: Silent deployment failure', {
|
|
2650
|
-
xmlFilePath,
|
|
2651
|
-
flowName,
|
|
2652
|
-
verificationResult: verification,
|
|
2653
|
-
issue: 'XML import/commit succeeded but no flow created'
|
|
2654
|
-
});
|
|
2655
|
-
throw new Error(errorMsg);
|
|
2656
|
-
}
|
|
2657
|
-
this.logger.info(`✅ XML deployment verified successfully: ${flowName} found with sys_id ${verification.sys_id}`);
|
|
2658
|
-
return {
|
|
2659
|
-
deployment_method: 'XML Remote Update Set',
|
|
2660
|
-
xml_file: xmlFilePath,
|
|
2661
|
-
verification: verification,
|
|
2662
|
-
success_message: `XML deployment completed and verified: Flow ${flowName} is live in ServiceNow`
|
|
2663
|
-
};
|
|
2664
|
-
}
|
|
2665
|
-
/**
|
|
2666
|
-
* 🔴 CRITICAL FIX: Deploy via Table API with MANDATORY verification
|
|
2667
|
-
* SNOW-001: Prevents false positive where API call succeeds but flow doesn't exist
|
|
2668
|
-
*/
|
|
2669
|
-
async deployViaTableAPIWithVerification(flowDefinition) {
|
|
2670
|
-
this.logger.info(`🔴 CRITICAL FIX: Table API deployment with mandatory verification for: ${flowDefinition.name}`);
|
|
2671
|
-
// Step 1: Deploy via Table API (existing logic)
|
|
2672
|
-
await this.deployViaTableAPI(flowDefinition);
|
|
2673
|
-
// Step 2: MANDATORY verification
|
|
2674
|
-
this.logger.info('🔍 Starting mandatory post-deployment verification...');
|
|
2675
|
-
const verification = await this.verifyFlowInServiceNow(flowDefinition.name);
|
|
2676
|
-
if (!verification.verified) {
|
|
2677
|
-
// 🔴 CRITICAL: Table API deployment succeeded but flow doesn't exist
|
|
2678
|
-
const errorMsg = `🔴 CRITICAL: Table API deployment appeared to succeed but flow verification failed: ${verification.reason}`;
|
|
2679
|
-
this.logger.error('SNOW-001 detected: Silent deployment failure', {
|
|
2680
|
-
flowName: flowDefinition.name,
|
|
2681
|
-
verificationResult: verification,
|
|
2682
|
-
issue: 'Table API call succeeded but no flow created'
|
|
2683
|
-
});
|
|
2684
|
-
throw new Error(errorMsg);
|
|
2685
|
-
}
|
|
2686
|
-
this.logger.info(`✅ Table API deployment verified successfully: ${flowDefinition.name} found with sys_id ${verification.sys_id}`);
|
|
2687
|
-
return {
|
|
2688
|
-
deployment_method: 'Direct Table API',
|
|
2689
|
-
verification: verification,
|
|
2690
|
-
success_message: `Table API deployment completed and verified: Flow ${flowDefinition.name} is live in ServiceNow`
|
|
2691
|
-
};
|
|
2692
|
-
}
|
|
2693
|
-
/**
|
|
2694
|
-
* Deploy via direct table API (LEGACY METHOD - used by new verified method)
|
|
2695
|
-
*/
|
|
2696
|
-
async deployViaTableAPI(flowDefinition) {
|
|
2697
|
-
const ServiceNowClient = (await Promise.resolve().then(() => __importStar(require('../utils/servicenow-client.js')))).ServiceNowClient;
|
|
2698
|
-
const client = new ServiceNowClient();
|
|
2699
|
-
// Try to create flow directly in sys_hub_flow
|
|
2700
|
-
const flowResponse = await client.makeRequest({
|
|
2701
|
-
method: 'POST',
|
|
2702
|
-
url: '/api/now/table/sys_hub_flow',
|
|
2703
|
-
data: {
|
|
2704
|
-
name: flowDefinition.name,
|
|
2705
|
-
description: flowDefinition.description,
|
|
2706
|
-
active: true,
|
|
2707
|
-
// Additional flow properties
|
|
2708
|
-
table: flowDefinition.table
|
|
2709
|
-
}
|
|
2710
|
-
});
|
|
2711
|
-
if (!flowResponse.result || !flowResponse.result.sys_id) {
|
|
2712
|
-
throw new Error('Failed to create flow via Table API');
|
|
2713
|
-
}
|
|
2714
|
-
this.logger.info(`Flow created via Table API: ${flowResponse.result.sys_id}`);
|
|
2715
|
-
}
|
|
2716
|
-
/**
|
|
2717
|
-
* Deploy XML file to ServiceNow automatically
|
|
2718
|
-
*/
|
|
2719
|
-
async deployXMLToServiceNow(xmlFilePath) {
|
|
2720
|
-
// Check authentication
|
|
2721
|
-
const isAuth = await this.oauth.isAuthenticated();
|
|
2722
|
-
if (!isAuth) {
|
|
2723
|
-
throw new Error('Not authenticated with ServiceNow. Please run: snow-flow auth login');
|
|
2724
|
-
}
|
|
2725
|
-
// Initialize ServiceNow client
|
|
2726
|
-
const ServiceNowClient = (await Promise.resolve().then(() => __importStar(require('../utils/servicenow-client.js')))).ServiceNowClient;
|
|
2727
|
-
const client = new ServiceNowClient();
|
|
2728
|
-
// Check for active Update Set first
|
|
2729
|
-
let currentUpdateSet;
|
|
2730
|
-
try {
|
|
2731
|
-
const updateSetResponse = await client.makeRequest({
|
|
2732
|
-
method: 'GET',
|
|
2733
|
-
url: '/api/now/table/sys_update_set',
|
|
2734
|
-
params: {
|
|
2735
|
-
sysparm_query: 'state=in progress^nameNOT LIKEDefault',
|
|
2736
|
-
sysparm_limit: 1
|
|
2737
|
-
}
|
|
2738
|
-
});
|
|
2739
|
-
if (!updateSetResponse.result || updateSetResponse.result.length === 0) {
|
|
2740
|
-
this.logger.warn('No active Update Set found. Flow will be imported but not tracked properly.');
|
|
2741
|
-
// Continue anyway - let ServiceNow handle it
|
|
2742
|
-
}
|
|
2743
|
-
else {
|
|
2744
|
-
currentUpdateSet = updateSetResponse.result[0];
|
|
2745
|
-
this.logger.info(`Active Update Set found: ${currentUpdateSet.name}`);
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
|
-
catch (error) {
|
|
2749
|
-
this.logger.warn('Could not check for active Update Set:', error);
|
|
2750
|
-
// Continue anyway
|
|
2751
|
-
}
|
|
2752
|
-
// Read the XML file
|
|
2753
|
-
const fs = require('fs').promises;
|
|
2754
|
-
const xmlContent = await fs.readFile(xmlFilePath, 'utf-8');
|
|
2755
|
-
// Import XML as remote update set
|
|
2756
|
-
let importResponse;
|
|
2757
|
-
try {
|
|
2758
|
-
importResponse = await client.makeRequest({
|
|
2759
|
-
method: 'POST',
|
|
2760
|
-
url: '/api/now/table/sys_remote_update_set',
|
|
2761
|
-
headers: {
|
|
2762
|
-
'Content-Type': 'application/xml',
|
|
2763
|
-
'Accept': 'application/json'
|
|
2764
|
-
},
|
|
2765
|
-
data: xmlContent
|
|
2766
|
-
});
|
|
2767
|
-
}
|
|
2768
|
-
catch (error) {
|
|
2769
|
-
// Enhanced error handling with detailed messages
|
|
2770
|
-
if (error.response?.status === 400) {
|
|
2771
|
-
const errorDetail = error.response.data?.error?.detail ||
|
|
2772
|
-
error.response.data?.error?.message ||
|
|
2773
|
-
'Unknown error';
|
|
2774
|
-
this.logger.error('ServiceNow 400 Error:', {
|
|
2775
|
-
status: error.response.status,
|
|
2776
|
-
statusText: error.response.statusText,
|
|
2777
|
-
data: error.response.data,
|
|
2778
|
-
headers: error.response.headers
|
|
2779
|
-
});
|
|
2780
|
-
throw new Error(`ServiceNow rejected the XML: ${errorDetail}. Check if you have an active Update Set.`);
|
|
2781
|
-
}
|
|
2782
|
-
else if (error.response?.status === 401 || error.response?.status === 403) {
|
|
2783
|
-
throw new Error('Authentication failed. Your session may have expired. Run: snow-flow auth login');
|
|
2784
|
-
}
|
|
2785
|
-
else {
|
|
2786
|
-
throw new Error(`Failed to import XML: ${error.message}`);
|
|
2787
|
-
}
|
|
2788
|
-
}
|
|
2789
|
-
if (!importResponse.result || !importResponse.result.sys_id) {
|
|
2790
|
-
throw new Error('Failed to import XML update set');
|
|
2791
|
-
}
|
|
2792
|
-
const remoteUpdateSetId = importResponse.result.sys_id;
|
|
2793
|
-
this.logger.info(`✅ XML imported successfully (sys_id: ${remoteUpdateSetId})`);
|
|
2794
|
-
// Load the update set
|
|
2795
|
-
try {
|
|
2796
|
-
await client.makeRequest({
|
|
2797
|
-
method: 'PUT',
|
|
2798
|
-
url: `/api/now/table/sys_remote_update_set/${remoteUpdateSetId}`,
|
|
2799
|
-
data: {
|
|
2800
|
-
state: 'loaded'
|
|
2801
|
-
}
|
|
2802
|
-
});
|
|
2803
|
-
}
|
|
2804
|
-
catch (error) {
|
|
2805
|
-
this.logger.error('Failed to load update set:', error);
|
|
2806
|
-
throw new Error(`Failed to load update set: ${error.message}. You may need to load it manually.`);
|
|
2807
|
-
}
|
|
2808
|
-
// Find the loaded update set
|
|
2809
|
-
const loadedResponse = await client.makeRequest({
|
|
2810
|
-
method: 'GET',
|
|
2811
|
-
url: '/api/now/table/sys_update_set',
|
|
2812
|
-
params: {
|
|
2813
|
-
sysparm_query: `remote_sys_id=${remoteUpdateSetId}`,
|
|
2814
|
-
sysparm_limit: 1
|
|
2815
|
-
}
|
|
2816
|
-
});
|
|
2817
|
-
if (!loadedResponse.result || loadedResponse.result.length === 0) {
|
|
2818
|
-
throw new Error('Failed to find loaded update set');
|
|
2819
|
-
}
|
|
2820
|
-
const updateSetId = loadedResponse.result[0].sys_id;
|
|
2821
|
-
const updateSetName = loadedResponse.result[0].name;
|
|
2822
|
-
// Preview the update set
|
|
2823
|
-
try {
|
|
2824
|
-
await client.makeRequest({
|
|
2825
|
-
method: 'POST',
|
|
2826
|
-
url: `/api/now/table/sys_update_set/${updateSetId}/preview`
|
|
2827
|
-
});
|
|
2828
|
-
}
|
|
2829
|
-
catch (error) {
|
|
2830
|
-
this.logger.error('Failed to preview update set:', error);
|
|
2831
|
-
// Continue anyway, as preview might fail but commit could still work
|
|
2832
|
-
}
|
|
2833
|
-
// Check for preview problems
|
|
2834
|
-
const previewProblems = await client.makeRequest({
|
|
2835
|
-
method: 'GET',
|
|
2836
|
-
url: '/api/now/table/sys_update_preview_problem',
|
|
2837
|
-
params: {
|
|
2838
|
-
sysparm_query: `update_set=${updateSetId}`,
|
|
2839
|
-
sysparm_limit: 100
|
|
2840
|
-
}
|
|
2841
|
-
});
|
|
2842
|
-
if (previewProblems.result && previewProblems.result.length > 0) {
|
|
2843
|
-
const problemsList = previewProblems.result.map((p) => `- ${p.type}: ${p.description}`).join('\n');
|
|
2844
|
-
throw new Error(`Preview found problems:\n${problemsList}\n\nPlease review and resolve in ServiceNow UI`);
|
|
2845
|
-
}
|
|
2846
|
-
// Commit the update set
|
|
2847
|
-
try {
|
|
2848
|
-
await client.makeRequest({
|
|
2849
|
-
method: 'POST',
|
|
2850
|
-
url: `/api/now/table/sys_update_set/${updateSetId}/commit`
|
|
2851
|
-
});
|
|
2852
|
-
this.logger.info(`✅ Update set committed successfully: ${updateSetName}`);
|
|
2853
|
-
}
|
|
2854
|
-
catch (error) {
|
|
2855
|
-
this.logger.error('Failed to commit update set:', error);
|
|
2856
|
-
throw new Error(`Failed to commit update set. Manual intervention required in ServiceNow UI.`);
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
/**
|
|
2860
|
-
* 🚀 BUG-007 FIX: Performance Analysis Tool
|
|
2861
|
-
* Analyze flows for performance bottlenecks and provide database index recommendations
|
|
2862
|
-
*/
|
|
2863
|
-
async performanceAnalysis(args) {
|
|
2864
|
-
try {
|
|
2865
|
-
this.logger.info('🔍 Running performance analysis', {
|
|
2866
|
-
flowDefinition: !!args.flow_definition,
|
|
2867
|
-
tableName: args.table_name,
|
|
2868
|
-
includeIndexes: args.include_database_indexes,
|
|
2869
|
-
includeCode: args.include_code_analysis
|
|
2870
|
-
});
|
|
2871
|
-
// Import the performance engine
|
|
2872
|
-
const { PerformanceRecommendationsEngine } = await Promise.resolve().then(() => __importStar(require('../intelligence/performance-recommendations-engine.js')));
|
|
2873
|
-
const performanceEngine = new PerformanceRecommendationsEngine();
|
|
2874
|
-
// Run performance analysis
|
|
2875
|
-
const analysisResult = await performanceEngine.analyzeFlowPerformance(args.flow_definition);
|
|
2876
|
-
let responseText = `🚀 **Performance Analysis Results**
|
|
2877
|
-
|
|
2878
|
-
📊 **SUMMARY:**
|
|
2879
|
-
• Critical Issues: ${analysisResult.summary.criticalIssues}
|
|
2880
|
-
• Estimated Performance Improvement: ${analysisResult.summary.estimatedImprovementPercent}%
|
|
2881
|
-
• Total Recommendations: ${analysisResult.databaseIndexes.length + analysisResult.performanceRecommendations.length}
|
|
2882
|
-
|
|
2883
|
-
`;
|
|
2884
|
-
// Add database index recommendations if requested
|
|
2885
|
-
if (args.include_database_indexes !== false && analysisResult.databaseIndexes.length > 0) {
|
|
2886
|
-
responseText += `🗄️ **DATABASE INDEX RECOMMENDATIONS:**
|
|
2887
|
-
|
|
2888
|
-
${analysisResult.databaseIndexes.map((idx, i) => `**${i + 1}. ${idx.table} - ${idx.fields.join(', ')} [${idx.priority.toUpperCase()}]**
|
|
2889
|
-
💡 **Reason**: ${idx.reason}
|
|
2890
|
-
📈 **Expected Improvement**: ${idx.estimatedImprovement}%
|
|
2891
|
-
💻 **SQL**: \`${idx.createStatement}\`
|
|
2892
|
-
📊 **Impact**: ${idx.impactAnalysis.queryImpact.join(', ')}
|
|
2893
|
-
💾 **Storage**: ${idx.impactAnalysis.storageImpact}
|
|
2894
|
-
🔧 **Maintenance**: ${idx.impactAnalysis.maintenanceImpact}
|
|
2895
|
-
`).join('\n')}
|
|
2896
|
-
|
|
2897
|
-
`;
|
|
2898
|
-
}
|
|
2899
|
-
// Add performance recommendations if requested
|
|
2900
|
-
if (args.include_code_analysis !== false && analysisResult.performanceRecommendations.length > 0) {
|
|
2901
|
-
responseText += `⚡ **PERFORMANCE RECOMMENDATIONS:**
|
|
2902
|
-
|
|
2903
|
-
${analysisResult.performanceRecommendations.map((rec, i) => `**${i + 1}. ${rec.type.replace(/_/g, ' ').toUpperCase()} [${rec.impact.toUpperCase()} IMPACT]**
|
|
2904
|
-
📋 **Issue**: ${rec.description}
|
|
2905
|
-
💡 **Recommendation**: ${rec.recommendation}
|
|
2906
|
-
⏱️ **Time Savings**: ${rec.estimated_time_savings}
|
|
2907
|
-
${rec.code_example ? `\n💻 **Example Code**:\n\`\`\`javascript\n${rec.code_example}\n\`\`\`` : ''}
|
|
2908
|
-
`).join('\n')}
|
|
2909
|
-
|
|
2910
|
-
`;
|
|
2911
|
-
}
|
|
2912
|
-
// Add top priority actions
|
|
2913
|
-
if (analysisResult.summary.recommendedActions.length > 0) {
|
|
2914
|
-
responseText += `🎯 **TOP PRIORITY ACTIONS:**
|
|
2915
|
-
${analysisResult.summary.recommendedActions.map((action, i) => `${i + 1}. ${action}`).join('\n')}
|
|
2916
|
-
|
|
2917
|
-
`;
|
|
2918
|
-
}
|
|
2919
|
-
// Add detailed report if requested
|
|
2920
|
-
if (args.detailed_report) {
|
|
2921
|
-
responseText += `📋 **DETAILED PERFORMANCE REPORT:**
|
|
2922
|
-
|
|
2923
|
-
${performanceEngine.generatePerformanceReport(analysisResult)}`;
|
|
2924
|
-
}
|
|
2925
|
-
responseText += `
|
|
2926
|
-
🔍 **NEXT STEPS:**
|
|
2927
|
-
1. Implement critical database indexes first (highest ROI)
|
|
2928
|
-
2. Review and optimize flow scripts for performance issues
|
|
2929
|
-
3. Consider implementing caching for frequently accessed data
|
|
2930
|
-
4. Monitor performance metrics after implementing changes
|
|
2931
|
-
5. Schedule regular performance reviews for optimal results
|
|
2932
|
-
|
|
2933
|
-
⚠️ **IMPORTANT**: Test all database changes in a development environment first!
|
|
2934
|
-
|
|
2935
|
-
✅ **Performance analysis complete!** Review recommendations and implement changes for optimal performance.`;
|
|
2936
|
-
return {
|
|
2937
|
-
content: [
|
|
2938
|
-
{
|
|
2939
|
-
type: 'text',
|
|
2940
|
-
text: responseText,
|
|
2941
|
-
},
|
|
2942
|
-
],
|
|
2943
|
-
};
|
|
2944
|
-
}
|
|
2945
|
-
catch (error) {
|
|
2946
|
-
this.logger.error('Performance analysis failed:', error);
|
|
2947
|
-
throw new Error(`Performance analysis failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2948
|
-
}
|
|
2949
|
-
}
|
|
2950
|
-
/**
|
|
2951
|
-
* 🚀 BUG-006 FIX: Comprehensive Requirements Analysis Tool
|
|
2952
|
-
* Multi-pass analysis to ensure comprehensive requirements coverage
|
|
2953
|
-
*/
|
|
2954
|
-
async comprehensiveRequirementsAnalysis(args) {
|
|
2955
|
-
try {
|
|
2956
|
-
this.logger.info('🔍 Running comprehensive multi-pass requirements analysis', {
|
|
2957
|
-
objective: args.objective,
|
|
2958
|
-
includeDependencies: args.include_dependencies,
|
|
2959
|
-
includeContext: args.include_context_analysis,
|
|
2960
|
-
includeValidation: args.include_validation
|
|
2961
|
-
});
|
|
2962
|
-
// Import the multi-pass analyzer
|
|
2963
|
-
const { MultiPassRequirementsAnalyzer } = await Promise.resolve().then(() => __importStar(require('../intelligence/multi-pass-requirements-analyzer.js')));
|
|
2964
|
-
const analyzer = new MultiPassRequirementsAnalyzer();
|
|
2965
|
-
// Run comprehensive multi-pass analysis
|
|
2966
|
-
const analysisResult = await analyzer.analyzeRequirements(args.objective);
|
|
2967
|
-
let responseText = `🚀 **Comprehensive Requirements Analysis Results**
|
|
2968
|
-
|
|
2969
|
-
📝 **OBJECTIVE**: ${args.objective}
|
|
2970
|
-
|
|
2971
|
-
📊 **ANALYSIS SUMMARY:**
|
|
2972
|
-
• Total Requirements Identified: ${analysisResult.totalRequirements}
|
|
2973
|
-
• MCP Coverage: ${analysisResult.mcpCoveredCount}/${analysisResult.totalRequirements} (${analysisResult.mcpCoveragePercentage}%)
|
|
2974
|
-
• Gap Requirements: ${analysisResult.gapCount}
|
|
2975
|
-
• Estimated Complexity: ${analysisResult.estimatedComplexity.toUpperCase()}
|
|
2976
|
-
• Risk Assessment: ${analysisResult.riskAssessment.toUpperCase()}
|
|
2977
|
-
• Completeness Score: ${analysisResult.completenessScore}/100
|
|
2978
|
-
• Confidence Level: ${analysisResult.confidenceLevel.toUpperCase()}
|
|
2979
|
-
|
|
2980
|
-
`;
|
|
2981
|
-
// Add multi-pass analysis breakdown
|
|
2982
|
-
responseText += `🔍 **MULTI-PASS ANALYSIS BREAKDOWN:**
|
|
2983
|
-
|
|
2984
|
-
${Object.entries(analysisResult.analysisPassesData).map(([passKey, passData]) => `**${passData.passName} (Pass ${passData.passNumber})**
|
|
2985
|
-
• Requirements Found: ${passData.newRequirementsAdded}
|
|
2986
|
-
• Analysis Method: ${passData.analysisMethod}
|
|
2987
|
-
• Processing Time: ${passData.processingTime}ms
|
|
2988
|
-
• Confidence: ${Math.round(passData.confidence * 100)}%
|
|
2989
|
-
• Key Findings: ${passData.keyFindings.length > 0 ? passData.keyFindings.slice(0, 3).join('; ') : 'No specific findings'}
|
|
2990
|
-
`).join('\n')}
|
|
2991
|
-
|
|
2992
|
-
`;
|
|
2993
|
-
// Add requirements by category
|
|
2994
|
-
const categorizedRequirements = analysisResult.requirements.reduce((acc, req) => {
|
|
2995
|
-
if (!acc[req.category])
|
|
2996
|
-
acc[req.category] = [];
|
|
2997
|
-
acc[req.category].push(req);
|
|
2998
|
-
return acc;
|
|
2999
|
-
}, {});
|
|
3000
|
-
responseText += `📋 **REQUIREMENTS BY CATEGORY:**
|
|
3001
|
-
|
|
3002
|
-
${Object.entries(categorizedRequirements).map(([category, reqs]) => `**${category.replace(/_/g, ' ').toUpperCase()}** (${reqs.length} items)
|
|
3003
|
-
${reqs.slice(0, 5).map(req => `• ${req.name} [${req.priority.toUpperCase()}] ${req.mcpCoverage ? '✅ MCP' : '⚠️ Manual'} - ${req.description.substring(0, 80)}...`).join('\n')}
|
|
3004
|
-
${reqs.length > 5 ? `... and ${reqs.length - 5} more items` : ''}
|
|
3005
|
-
`).join('\n')}
|
|
3006
|
-
|
|
3007
|
-
`;
|
|
3008
|
-
// Add critical path analysis
|
|
3009
|
-
if (analysisResult.criticalPath.length > 0) {
|
|
3010
|
-
responseText += `🎯 **CRITICAL PATH REQUIREMENTS:**
|
|
3011
|
-
${analysisResult.criticalPath.map((req, i) => `${i + 1}. ${req}`).join('\n')}
|
|
3012
|
-
|
|
3013
|
-
`;
|
|
3014
|
-
}
|
|
3015
|
-
// Add cross-domain impacts
|
|
3016
|
-
if (analysisResult.crossDomainImpacts.length > 0) {
|
|
3017
|
-
responseText += `🌐 **CROSS-DOMAIN IMPACTS:**
|
|
3018
|
-
${analysisResult.crossDomainImpacts.map((impact, i) => `${i + 1}. ${impact}`).join('\n')}
|
|
3019
|
-
|
|
3020
|
-
`;
|
|
3021
|
-
}
|
|
3022
|
-
// Add implicit dependencies
|
|
3023
|
-
if (analysisResult.implicitDependencies.length > 0) {
|
|
3024
|
-
responseText += `🔗 **IMPLICIT DEPENDENCIES:**
|
|
3025
|
-
${analysisResult.implicitDependencies.slice(0, 5).map((dep, i) => `${i + 1}. ${dep}`).join('\n')}
|
|
3026
|
-
|
|
3027
|
-
`;
|
|
3028
|
-
}
|
|
3029
|
-
// Add missing requirements detected
|
|
3030
|
-
if (analysisResult.missingRequirementsDetected.length > 0) {
|
|
3031
|
-
responseText += `⚠️ **MISSING REQUIREMENTS DETECTED:**
|
|
3032
|
-
${analysisResult.missingRequirementsDetected.slice(0, 3).map((req, i) => `${i + 1}. **${req.name}** [${req.priority.toUpperCase()}]
|
|
3033
|
-
${req.description}
|
|
3034
|
-
Effort: ${req.estimatedEffort} | Risk: ${req.riskLevel} | MCP: ${req.mcpCoverage ? 'Yes' : 'No'}`).join('\n\n')}
|
|
3035
|
-
|
|
3036
|
-
`;
|
|
3037
|
-
}
|
|
3038
|
-
// Add detailed report if requested
|
|
3039
|
-
if (args.detailed_report) {
|
|
3040
|
-
responseText += `📋 **DETAILED ANALYSIS REPORT:**
|
|
3041
|
-
|
|
3042
|
-
**COMPLETENESS ANALYSIS:**
|
|
3043
|
-
The analysis achieved a completeness score of ${analysisResult.completenessScore}/100 with ${analysisResult.confidenceLevel} confidence.
|
|
3044
|
-
|
|
3045
|
-
**PASS-BY-PASS BREAKDOWN:**
|
|
3046
|
-
${Object.entries(analysisResult.analysisPassesData).map(([passKey, passData]) => `
|
|
3047
|
-
**${passData.passName}:**
|
|
3048
|
-
- New requirements identified: ${passData.newRequirementsAdded}
|
|
3049
|
-
- Key insights: ${passData.keyFindings.join('; ')}
|
|
3050
|
-
- Analysis approach: ${passData.analysisMethod}
|
|
3051
|
-
- Processing efficiency: ${passData.processingTime}ms
|
|
3052
|
-
`).join('')}
|
|
3053
|
-
|
|
3054
|
-
**RISK ASSESSMENT:**
|
|
3055
|
-
${analysisResult.riskAssessment === 'high' ? '⚠️ HIGH RISK: This objective involves complex integrations and significant system changes.' :
|
|
3056
|
-
analysisResult.riskAssessment === 'medium' ? '🔶 MEDIUM RISK: Standard complexity with some integration challenges.' :
|
|
3057
|
-
'✅ LOW RISK: Straightforward implementation with minimal system impact.'}
|
|
3058
|
-
|
|
3059
|
-
**COMPLEXITY BREAKDOWN:**
|
|
3060
|
-
The ${analysisResult.estimatedComplexity} complexity rating is based on:
|
|
3061
|
-
- Number of components: ${analysisResult.totalRequirements}
|
|
3062
|
-
- Integration points: ${analysisResult.categories.length} different categories
|
|
3063
|
-
- Estimated duration: ${analysisResult.estimatedDuration}
|
|
3064
|
-
- Cross-domain impacts: ${analysisResult.crossDomainImpacts.length} identified
|
|
3065
|
-
|
|
3066
|
-
`;
|
|
3067
|
-
}
|
|
3068
|
-
responseText += `
|
|
3069
|
-
🔍 **NEXT STEPS:**
|
|
3070
|
-
1. **Immediate Actions**: Focus on ${analysisResult.criticalPath.length > 0 ? 'critical path requirements' : 'high-priority items'}
|
|
3071
|
-
2. **MCP Coverage**: ${analysisResult.mcpCoveragePercentage}% can be automated, ${100 - analysisResult.mcpCoveragePercentage}% requires manual work
|
|
3072
|
-
3. **Resource Planning**: Estimated ${analysisResult.estimatedDuration} development time
|
|
3073
|
-
4. **Risk Mitigation**: Address ${analysisResult.riskAssessment} risk items first
|
|
3074
|
-
5. **Quality Assurance**: Validate completeness score of ${analysisResult.completenessScore}/100
|
|
3075
|
-
|
|
3076
|
-
💡 **RECOMMENDATIONS:**
|
|
3077
|
-
• Start with MCP-covered requirements for quick wins
|
|
3078
|
-
• Address security and compliance requirements early
|
|
3079
|
-
• Plan for cross-domain impact testing
|
|
3080
|
-
• Consider phased implementation for complex scenarios
|
|
3081
|
-
|
|
3082
|
-
✅ **Comprehensive analysis complete!** This ${analysisResult.analysisPassesData.pass1_initial.requirementsFound + analysisResult.analysisPassesData.pass2_dependencies.newRequirementsAdded + analysisResult.analysisPassesData.pass3_context.newRequirementsAdded + analysisResult.analysisPassesData.pass4_validation.newRequirementsAdded}-requirement analysis ensures nothing is missed.`;
|
|
3083
|
-
return {
|
|
3084
|
-
content: [
|
|
3085
|
-
{
|
|
3086
|
-
type: 'text',
|
|
3087
|
-
text: responseText,
|
|
3088
|
-
},
|
|
3089
|
-
],
|
|
3090
|
-
};
|
|
3091
|
-
}
|
|
3092
|
-
catch (error) {
|
|
3093
|
-
this.logger.error('Comprehensive requirements analysis failed:', error);
|
|
3094
|
-
throw new Error(`Comprehensive requirements analysis failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3095
|
-
}
|
|
3096
|
-
}
|
|
3097
|
-
}
|
|
3098
|
-
// Start the server
|
|
3099
|
-
const server = new ServiceNowFlowComposerMCP();
|
|
3100
|
-
server.start().catch((error) => {
|
|
3101
|
-
console.error('Failed to start ServiceNow Flow Composer MCP:', error);
|
|
3102
|
-
process.exit(1);
|
|
3103
|
-
});
|