snow-flow 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +49 -0
- package/.mcp.json +106 -0
- package/.mcp.json.template +106 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/bin/snow-flow +4 -0
- package/bin/snow-flow.js +3 -0
- package/claude-flow +79 -0
- package/claude-flow.bat +18 -0
- package/claude-flow.config.json +20 -0
- package/claude-flow.ps1 +24 -0
- package/dist/agents/app-creator.agent.d.ts +55 -0
- package/dist/agents/app-creator.agent.d.ts.map +1 -0
- package/dist/agents/app-creator.agent.js +1292 -0
- package/dist/agents/app-creator.agent.js.map +1 -0
- package/dist/agents/base-snow-agent.d.ts +63 -0
- package/dist/agents/base-snow-agent.d.ts.map +1 -0
- package/dist/agents/base-snow-agent.js +296 -0
- package/dist/agents/base-snow-agent.js.map +1 -0
- package/dist/agents/script-generator.agent.d.ts +32 -0
- package/dist/agents/script-generator.agent.d.ts.map +1 -0
- package/dist/agents/script-generator.agent.js +772 -0
- package/dist/agents/script-generator.agent.js.map +1 -0
- package/dist/agents/ui-builder.agent.d.ts +50 -0
- package/dist/agents/ui-builder.agent.d.ts.map +1 -0
- package/dist/agents/ui-builder.agent.js +1539 -0
- package/dist/agents/ui-builder.agent.js.map +1 -0
- package/dist/agents/widget-builder.agent.d.ts +32 -0
- package/dist/agents/widget-builder.agent.d.ts.map +1 -0
- package/dist/agents/widget-builder.agent.js +439 -0
- package/dist/agents/widget-builder.agent.js.map +1 -0
- package/dist/agents/workflow-designer.agent.d.ts +31 -0
- package/dist/agents/workflow-designer.agent.d.ts.map +1 -0
- package/dist/agents/workflow-designer.agent.js +583 -0
- package/dist/agents/workflow-designer.agent.js.map +1 -0
- package/dist/api/error-handling.d.ts +214 -0
- package/dist/api/error-handling.d.ts.map +1 -0
- package/dist/api/error-handling.js +594 -0
- package/dist/api/error-handling.js.map +1 -0
- package/dist/api/flow-designer-api.d.ts +167 -0
- package/dist/api/flow-designer-api.d.ts.map +1 -0
- package/dist/api/flow-designer-api.js +555 -0
- package/dist/api/flow-designer-api.js.map +1 -0
- package/dist/api/natural-language-mapper.d.ts +126 -0
- package/dist/api/natural-language-mapper.d.ts.map +1 -0
- package/dist/api/natural-language-mapper.js +498 -0
- package/dist/api/natural-language-mapper.js.map +1 -0
- package/dist/api/performance-optimizer.d.ts +240 -0
- package/dist/api/performance-optimizer.d.ts.map +1 -0
- package/dist/api/performance-optimizer.js +701 -0
- package/dist/api/performance-optimizer.js.map +1 -0
- package/dist/api/transaction-manager.d.ts +189 -0
- package/dist/api/transaction-manager.d.ts.map +1 -0
- package/dist/api/transaction-manager.js +576 -0
- package/dist/api/transaction-manager.js.map +1 -0
- package/dist/cli/deploy-artifact.d.ts +7 -0
- package/dist/cli/deploy-artifact.d.ts.map +1 -0
- package/dist/cli/deploy-artifact.js +279 -0
- package/dist/cli/deploy-artifact.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2057 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/managers/scope-manager.d.ts +75 -0
- package/dist/managers/scope-manager.d.ts.map +1 -0
- package/dist/managers/scope-manager.js +448 -0
- package/dist/managers/scope-manager.js.map +1 -0
- package/dist/mcp/mcp-wrapper.d.ts +8 -0
- package/dist/mcp/mcp-wrapper.d.ts.map +1 -0
- package/dist/mcp/mcp-wrapper.js +77 -0
- package/dist/mcp/mcp-wrapper.js.map +1 -0
- package/dist/mcp/servicenow-automation-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-automation-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-automation-mcp.js +683 -0
- package/dist/mcp/servicenow-automation-mcp.js.map +1 -0
- package/dist/mcp/servicenow-deployment-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-deployment-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-deployment-mcp.js +972 -0
- package/dist/mcp/servicenow-deployment-mcp.js.map +1 -0
- package/dist/mcp/servicenow-flow-composer-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-flow-composer-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-flow-composer-mcp.js +1121 -0
- package/dist/mcp/servicenow-flow-composer-mcp.js.map +1 -0
- package/dist/mcp/servicenow-graph-memory-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-graph-memory-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-graph-memory-mcp.js +703 -0
- package/dist/mcp/servicenow-graph-memory-mcp.js.map +1 -0
- package/dist/mcp/servicenow-integration-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-integration-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-integration-mcp.js +689 -0
- package/dist/mcp/servicenow-integration-mcp.js.map +1 -0
- package/dist/mcp/servicenow-intelligent-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-intelligent-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-intelligent-mcp.js +1138 -0
- package/dist/mcp/servicenow-intelligent-mcp.js.map +1 -0
- package/dist/mcp/servicenow-mcp-server.d.ts +37 -0
- package/dist/mcp/servicenow-mcp-server.d.ts.map +1 -0
- package/dist/mcp/servicenow-mcp-server.js +648 -0
- package/dist/mcp/servicenow-mcp-server.js.map +1 -0
- package/dist/mcp/servicenow-operations-mcp.d.ts +15 -0
- package/dist/mcp/servicenow-operations-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-operations-mcp.js +1287 -0
- package/dist/mcp/servicenow-operations-mcp.js.map +1 -0
- package/dist/mcp/servicenow-platform-development-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-platform-development-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-platform-development-mcp.js +557 -0
- package/dist/mcp/servicenow-platform-development-mcp.js.map +1 -0
- package/dist/mcp/servicenow-progressive-indexer.d.ts +79 -0
- package/dist/mcp/servicenow-progressive-indexer.d.ts.map +1 -0
- package/dist/mcp/servicenow-progressive-indexer.js +320 -0
- package/dist/mcp/servicenow-progressive-indexer.js.map +1 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.js +888 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.js.map +1 -0
- package/dist/mcp/servicenow-security-compliance-mcp.d.ts +8 -0
- package/dist/mcp/servicenow-security-compliance-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-security-compliance-mcp.js +812 -0
- package/dist/mcp/servicenow-security-compliance-mcp.js.map +1 -0
- package/dist/mcp/servicenow-update-set-mcp.d.ts +7 -0
- package/dist/mcp/servicenow-update-set-mcp.d.ts.map +1 -0
- package/dist/mcp/servicenow-update-set-mcp.js +599 -0
- package/dist/mcp/servicenow-update-set-mcp.js.map +1 -0
- package/dist/mcp/start-all-mcp-servers.d.ts +6 -0
- package/dist/mcp/start-all-mcp-servers.d.ts.map +1 -0
- package/dist/mcp/start-all-mcp-servers.js +65 -0
- package/dist/mcp/start-all-mcp-servers.js.map +1 -0
- package/dist/mcp/start-servicenow-mcp.d.ts +7 -0
- package/dist/mcp/start-servicenow-mcp.d.ts.map +1 -0
- package/dist/mcp/start-servicenow-mcp.js +64 -0
- package/dist/mcp/start-servicenow-mcp.js.map +1 -0
- package/dist/mcp/test-simple-mcp.d.ts +6 -0
- package/dist/mcp/test-simple-mcp.d.ts.map +1 -0
- package/dist/mcp/test-simple-mcp.js +64 -0
- package/dist/mcp/test-simple-mcp.js.map +1 -0
- package/dist/orchestrator/flow-composer.d.ts +269 -0
- package/dist/orchestrator/flow-composer.d.ts.map +1 -0
- package/dist/orchestrator/flow-composer.js +2221 -0
- package/dist/orchestrator/flow-composer.js.map +1 -0
- package/dist/orchestrator/flow-pattern-templates.d.ts +260 -0
- package/dist/orchestrator/flow-pattern-templates.d.ts.map +1 -0
- package/dist/orchestrator/flow-pattern-templates.js +906 -0
- package/dist/orchestrator/flow-pattern-templates.js.map +1 -0
- package/dist/orchestrator/flow-subflow-decision-engine.d.ts +202 -0
- package/dist/orchestrator/flow-subflow-decision-engine.d.ts.map +1 -0
- package/dist/orchestrator/flow-subflow-decision-engine.js +769 -0
- package/dist/orchestrator/flow-subflow-decision-engine.js.map +1 -0
- package/dist/orchestrator/flow-validation-engine.d.ts +145 -0
- package/dist/orchestrator/flow-validation-engine.d.ts.map +1 -0
- package/dist/orchestrator/flow-validation-engine.js +663 -0
- package/dist/orchestrator/flow-validation-engine.js.map +1 -0
- package/dist/orchestrator/snow-orchestrator.d.ts +49 -0
- package/dist/orchestrator/snow-orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/snow-orchestrator.js +235 -0
- package/dist/orchestrator/snow-orchestrator.js.map +1 -0
- package/dist/orchestrator/subflow-creation-handler.d.ts +230 -0
- package/dist/orchestrator/subflow-creation-handler.d.ts.map +1 -0
- package/dist/orchestrator/subflow-creation-handler.js +791 -0
- package/dist/orchestrator/subflow-creation-handler.js.map +1 -0
- package/dist/strategies/global-scope-strategy.d.ts +123 -0
- package/dist/strategies/global-scope-strategy.d.ts.map +1 -0
- package/dist/strategies/global-scope-strategy.js +585 -0
- package/dist/strategies/global-scope-strategy.js.map +1 -0
- package/dist/types/index.d.ts +138 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/servicenow.types.d.ts +260 -0
- package/dist/types/servicenow.types.d.ts.map +1 -0
- package/dist/types/servicenow.types.js +3 -0
- package/dist/types/servicenow.types.js.map +1 -0
- package/dist/types/snow-flow.types.d.ts +114 -0
- package/dist/types/snow-flow.types.d.ts.map +1 -0
- package/dist/types/snow-flow.types.js +3 -0
- package/dist/types/snow-flow.types.js.map +1 -0
- package/dist/utils/action-type-cache.d.ts +66 -0
- package/dist/utils/action-type-cache.d.ts.map +1 -0
- package/dist/utils/action-type-cache.js +237 -0
- package/dist/utils/action-type-cache.js.map +1 -0
- package/dist/utils/agent-detector.d.ts +35 -0
- package/dist/utils/agent-detector.d.ts.map +1 -0
- package/dist/utils/agent-detector.js +353 -0
- package/dist/utils/agent-detector.js.map +1 -0
- package/dist/utils/flow-api-discovery.d.ts +151 -0
- package/dist/utils/flow-api-discovery.d.ts.map +1 -0
- package/dist/utils/flow-api-discovery.js +440 -0
- package/dist/utils/flow-api-discovery.js.map +1 -0
- package/dist/utils/flow-xml-generator.d.ts +41 -0
- package/dist/utils/flow-xml-generator.d.ts.map +1 -0
- package/dist/utils/flow-xml-generator.js +258 -0
- package/dist/utils/flow-xml-generator.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +51 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mcp-auth-middleware.d.ts +58 -0
- package/dist/utils/mcp-auth-middleware.d.ts.map +1 -0
- package/dist/utils/mcp-auth-middleware.js +227 -0
- package/dist/utils/mcp-auth-middleware.js.map +1 -0
- package/dist/utils/mcp-config-manager.d.ts +126 -0
- package/dist/utils/mcp-config-manager.d.ts.map +1 -0
- package/dist/utils/mcp-config-manager.js +209 -0
- package/dist/utils/mcp-config-manager.js.map +1 -0
- package/dist/utils/mcp-server-manager.d.ts +91 -0
- package/dist/utils/mcp-server-manager.d.ts.map +1 -0
- package/dist/utils/mcp-server-manager.js +338 -0
- package/dist/utils/mcp-server-manager.js.map +1 -0
- package/dist/utils/scope-utils.d.ts +72 -0
- package/dist/utils/scope-utils.d.ts.map +1 -0
- package/dist/utils/scope-utils.js +386 -0
- package/dist/utils/scope-utils.js.map +1 -0
- package/dist/utils/servicenow-client.d.ts +233 -0
- package/dist/utils/servicenow-client.d.ts.map +1 -0
- package/dist/utils/servicenow-client.js +1465 -0
- package/dist/utils/servicenow-client.js.map +1 -0
- package/dist/utils/snow-oauth-old.d.ts +65 -0
- package/dist/utils/snow-oauth-old.d.ts.map +1 -0
- package/dist/utils/snow-oauth-old.js +345 -0
- package/dist/utils/snow-oauth-old.js.map +1 -0
- package/dist/utils/snow-oauth.d.ts +85 -0
- package/dist/utils/snow-oauth.d.ts.map +1 -0
- package/dist/utils/snow-oauth.js +512 -0
- package/dist/utils/snow-oauth.js.map +1 -0
- package/dist/utils/template-engine.d.ts +76 -0
- package/dist/utils/template-engine.d.ts.map +1 -0
- package/dist/utils/template-engine.js +391 -0
- package/dist/utils/template-engine.js.map +1 -0
- package/dist/version.d.ts +35 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +72 -0
- package/dist/version.js.map +1 -0
- package/mcp-wrapper.sh +12 -0
- package/package.json +77 -0
- package/reports/swarm-auto-centralized-1752649029776.json +13 -0
- package/scripts/postinstall.js +30 -0
- package/scripts/setup-mcp.js +89 -0
|
@@ -0,0 +1,1292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* App Creator Agent for Scoped Applications
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AppCreatorAgent = void 0;
|
|
7
|
+
const base_agent_js_1 = require("../core/base-agent.js");
|
|
8
|
+
class AppCreatorAgent extends base_agent_js_1.BaseServiceNowAgent {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
super('app-creator', servicenow_types_js_1.AgentType.APP_CREATOR, [
|
|
11
|
+
'create_application',
|
|
12
|
+
'add_tables',
|
|
13
|
+
'create_menus',
|
|
14
|
+
'generate_app_structure',
|
|
15
|
+
'create_security_rules',
|
|
16
|
+
'package_application',
|
|
17
|
+
'generate_app_documentation'
|
|
18
|
+
], config);
|
|
19
|
+
}
|
|
20
|
+
async execute(task) {
|
|
21
|
+
this.logger.info(`Executing app creation task: ${task.description}`);
|
|
22
|
+
try {
|
|
23
|
+
switch (task.type) {
|
|
24
|
+
case 'create_application':
|
|
25
|
+
return await this.createApplication(task);
|
|
26
|
+
case 'generate_from_requirements':
|
|
27
|
+
return await this.generateFromRequirements(task);
|
|
28
|
+
case 'add_app_components':
|
|
29
|
+
return await this.addAppComponents(task);
|
|
30
|
+
case 'package_application':
|
|
31
|
+
return await this.packageApplication(task);
|
|
32
|
+
default:
|
|
33
|
+
throw new Error(`Unknown task type: ${task.type}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
this.logger.error(`App creation task failed: ${error.message}`);
|
|
38
|
+
return {
|
|
39
|
+
taskId: task.id,
|
|
40
|
+
success: false,
|
|
41
|
+
error: error.message
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async createApplication(task) {
|
|
46
|
+
const { name, scope, vendor, description, initialTables } = task.payload;
|
|
47
|
+
const app = {
|
|
48
|
+
name,
|
|
49
|
+
scope: scope || this.generateScope(name),
|
|
50
|
+
version: '1.0.0',
|
|
51
|
+
vendor: vendor || 'Custom',
|
|
52
|
+
vendorPrefix: this.generateVendorPrefix(vendor || 'Custom'),
|
|
53
|
+
shortDescription: description || `${name} Application`,
|
|
54
|
+
description: description || `Scoped application: ${name}`,
|
|
55
|
+
tables: initialTables || [],
|
|
56
|
+
menus: []
|
|
57
|
+
};
|
|
58
|
+
// Generate application structure
|
|
59
|
+
const appStructure = this.generateApplicationStructure(app);
|
|
60
|
+
// Generate orchestration commands
|
|
61
|
+
const commands = [
|
|
62
|
+
// Create base directory structure
|
|
63
|
+
this.generateCommand('Bash', 'create', {
|
|
64
|
+
command: `mkdir -p /Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}/{sys_app,tables,menus,security,scripts,ui,docs}`,
|
|
65
|
+
description: `Create application directory structure for ${name}`
|
|
66
|
+
}, 'Create directories'),
|
|
67
|
+
// Application manifest
|
|
68
|
+
this.generateCommand('Write', 'create', {
|
|
69
|
+
file_path: `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}/sys_app/manifest.json`,
|
|
70
|
+
content: JSON.stringify(appStructure.manifest, null, 2)
|
|
71
|
+
}, 'Create application manifest'),
|
|
72
|
+
// Application properties
|
|
73
|
+
this.generateCommand('Write', 'create', {
|
|
74
|
+
file_path: `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}/sys_app/properties.json`,
|
|
75
|
+
content: JSON.stringify(appStructure.properties, null, 2)
|
|
76
|
+
}, 'Create application properties'),
|
|
77
|
+
// README
|
|
78
|
+
this.generateCommand('Write', 'create', {
|
|
79
|
+
file_path: `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}/README.md`,
|
|
80
|
+
content: this.generateApplicationReadme(app)
|
|
81
|
+
}, 'Create application README')
|
|
82
|
+
];
|
|
83
|
+
// Store in memory for coordination
|
|
84
|
+
await this.storeInMemory(`applications:${app.scope}`, app);
|
|
85
|
+
return {
|
|
86
|
+
taskId: task.id,
|
|
87
|
+
success: true,
|
|
88
|
+
output: {
|
|
89
|
+
application: app,
|
|
90
|
+
structure: appStructure
|
|
91
|
+
},
|
|
92
|
+
artifacts: [
|
|
93
|
+
this.createArtifact('scoped_application', app.name, app, {
|
|
94
|
+
scope: app.scope,
|
|
95
|
+
version: app.version
|
|
96
|
+
})
|
|
97
|
+
],
|
|
98
|
+
commands
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async generateFromRequirements(task) {
|
|
102
|
+
const { requirements, appType, businessDomain } = task.payload;
|
|
103
|
+
// Analyze requirements to determine app structure
|
|
104
|
+
const analysis = this.analyzeAppRequirements(requirements, appType, businessDomain);
|
|
105
|
+
// Generate application based on analysis
|
|
106
|
+
const app = {
|
|
107
|
+
name: analysis.suggestedName,
|
|
108
|
+
scope: this.generateScope(analysis.suggestedName),
|
|
109
|
+
version: '1.0.0',
|
|
110
|
+
vendor: 'Auto-Generated',
|
|
111
|
+
vendorPrefix: 'x',
|
|
112
|
+
shortDescription: analysis.description,
|
|
113
|
+
description: `Application generated from requirements: ${requirements.substring(0, 200)}...`,
|
|
114
|
+
tables: this.generateTablesFromAnalysis(analysis),
|
|
115
|
+
menus: this.generateMenusFromAnalysis(analysis)
|
|
116
|
+
};
|
|
117
|
+
// Generate complete application package
|
|
118
|
+
const appPackage = await this.generateCompleteApplication(app, analysis);
|
|
119
|
+
// Generate comprehensive commands for all app components
|
|
120
|
+
const commands = this.generateApplicationCommands(app, appPackage);
|
|
121
|
+
return {
|
|
122
|
+
taskId: task.id,
|
|
123
|
+
success: true,
|
|
124
|
+
output: {
|
|
125
|
+
application: app,
|
|
126
|
+
package: appPackage,
|
|
127
|
+
analysis
|
|
128
|
+
},
|
|
129
|
+
artifacts: [
|
|
130
|
+
this.createArtifact('scoped_application', app.name, app),
|
|
131
|
+
...appPackage.artifacts
|
|
132
|
+
],
|
|
133
|
+
commands
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async addAppComponents(task) {
|
|
137
|
+
const { appScope, components } = task.payload;
|
|
138
|
+
// Retrieve existing application
|
|
139
|
+
const app = await this.retrieveFromMemory(`applications:${appScope}`);
|
|
140
|
+
if (!app) {
|
|
141
|
+
throw new Error(`Application ${appScope} not found`);
|
|
142
|
+
}
|
|
143
|
+
const addedComponents = {
|
|
144
|
+
tables: [],
|
|
145
|
+
menus: [],
|
|
146
|
+
scripts: [],
|
|
147
|
+
ui: []
|
|
148
|
+
};
|
|
149
|
+
// Add tables
|
|
150
|
+
if (components.tables) {
|
|
151
|
+
components.tables.forEach((table) => {
|
|
152
|
+
const appTable = this.createApplicationTable(table, app.scope);
|
|
153
|
+
app.tables.push(appTable);
|
|
154
|
+
addedComponents.tables.push(appTable);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Add menus
|
|
158
|
+
if (components.menus) {
|
|
159
|
+
components.menus.forEach((menu) => {
|
|
160
|
+
const appMenu = this.createApplicationMenu(menu, app.scope);
|
|
161
|
+
app.menus.push(appMenu);
|
|
162
|
+
addedComponents.menus.push(appMenu);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// Update stored application
|
|
166
|
+
await this.storeInMemory(`applications:${appScope}`, app);
|
|
167
|
+
// Generate commands for new components
|
|
168
|
+
const commands = this.generateComponentCommands(app.scope, addedComponents);
|
|
169
|
+
return {
|
|
170
|
+
taskId: task.id,
|
|
171
|
+
success: true,
|
|
172
|
+
output: {
|
|
173
|
+
application: app,
|
|
174
|
+
addedComponents
|
|
175
|
+
},
|
|
176
|
+
artifacts: [
|
|
177
|
+
...addedComponents.tables.map((table) => this.createArtifact('application_table', table.name, table)),
|
|
178
|
+
...addedComponents.menus.map((menu) => this.createArtifact('application_menu', menu.name, menu))
|
|
179
|
+
],
|
|
180
|
+
commands
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async packageApplication(task) {
|
|
184
|
+
const { appScope, includeData, format } = task.payload;
|
|
185
|
+
const app = await this.retrieveFromMemory(`applications:${appScope}`);
|
|
186
|
+
if (!app) {
|
|
187
|
+
throw new Error(`Application ${appScope} not found`);
|
|
188
|
+
}
|
|
189
|
+
// Generate application package
|
|
190
|
+
const appPackage = {
|
|
191
|
+
manifest: this.generateManifest(app),
|
|
192
|
+
metadata: this.generateMetadata(app),
|
|
193
|
+
components: {
|
|
194
|
+
tables: app.tables,
|
|
195
|
+
menus: app.menus,
|
|
196
|
+
security: this.generateSecurityRules(app),
|
|
197
|
+
scripts: this.generateApplicationScripts(app),
|
|
198
|
+
ui: this.generateApplicationUI(app)
|
|
199
|
+
},
|
|
200
|
+
data: includeData ? this.generateSampleData(app) : null
|
|
201
|
+
};
|
|
202
|
+
// Generate export based on format
|
|
203
|
+
let exportContent;
|
|
204
|
+
let fileName;
|
|
205
|
+
switch (format) {
|
|
206
|
+
case 'xml':
|
|
207
|
+
exportContent = this.generateXMLExport(appPackage);
|
|
208
|
+
fileName = `${app.scope}.xml`;
|
|
209
|
+
break;
|
|
210
|
+
case 'json':
|
|
211
|
+
exportContent = JSON.stringify(appPackage, null, 2);
|
|
212
|
+
fileName = `${app.scope}.json`;
|
|
213
|
+
break;
|
|
214
|
+
default:
|
|
215
|
+
exportContent = this.generateUpdateSetXML(appPackage);
|
|
216
|
+
fileName = `${app.scope}_update_set.xml`;
|
|
217
|
+
}
|
|
218
|
+
const commands = [
|
|
219
|
+
this.generateCommand('Write', 'create', {
|
|
220
|
+
file_path: `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}/export/${fileName}`,
|
|
221
|
+
content: exportContent
|
|
222
|
+
}, `Export application package as ${format}`),
|
|
223
|
+
this.generateCommand('Write', 'create', {
|
|
224
|
+
file_path: `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}/export/install-guide.md`,
|
|
225
|
+
content: this.generateInstallationGuide(app)
|
|
226
|
+
}, 'Create installation guide')
|
|
227
|
+
];
|
|
228
|
+
return {
|
|
229
|
+
taskId: task.id,
|
|
230
|
+
success: true,
|
|
231
|
+
output: {
|
|
232
|
+
package: appPackage,
|
|
233
|
+
exportFile: fileName
|
|
234
|
+
},
|
|
235
|
+
artifacts: [
|
|
236
|
+
this.createArtifact('application_package', fileName, exportContent),
|
|
237
|
+
this.createArtifact('documentation', 'install-guide.md', this.generateInstallationGuide(app))
|
|
238
|
+
],
|
|
239
|
+
commands
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// Helper methods
|
|
243
|
+
generateScope(name) {
|
|
244
|
+
return 'x_' + name.toLowerCase()
|
|
245
|
+
.replace(/[^a-z0-9]/g, '_')
|
|
246
|
+
.replace(/_+/g, '_')
|
|
247
|
+
.substring(0, 18);
|
|
248
|
+
}
|
|
249
|
+
generateVendorPrefix(vendor) {
|
|
250
|
+
return vendor.toLowerCase()
|
|
251
|
+
.split(/\s+/)
|
|
252
|
+
.map(word => word.charAt(0))
|
|
253
|
+
.join('')
|
|
254
|
+
.substring(0, 3) || 'x';
|
|
255
|
+
}
|
|
256
|
+
generateApplicationStructure(app) {
|
|
257
|
+
return {
|
|
258
|
+
manifest: {
|
|
259
|
+
name: app.name,
|
|
260
|
+
scope: app.scope,
|
|
261
|
+
version: app.version,
|
|
262
|
+
vendor: app.vendor,
|
|
263
|
+
vendor_prefix: app.vendorPrefix,
|
|
264
|
+
created: new Date().toISOString(),
|
|
265
|
+
dependencies: [],
|
|
266
|
+
components: {
|
|
267
|
+
tables: app.tables.length,
|
|
268
|
+
menus: app.menus.length
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
properties: {
|
|
272
|
+
js_level: 'helsinki',
|
|
273
|
+
logo: '',
|
|
274
|
+
private: false,
|
|
275
|
+
offline_mobile: false,
|
|
276
|
+
active: true,
|
|
277
|
+
enforce_license: 'none',
|
|
278
|
+
short_description: app.shortDescription,
|
|
279
|
+
description: app.description
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
generateApplicationReadme(app) {
|
|
284
|
+
return `# ${app.name}
|
|
285
|
+
|
|
286
|
+
## Overview
|
|
287
|
+
${app.description}
|
|
288
|
+
|
|
289
|
+
## Scope
|
|
290
|
+
- **Application Scope**: ${app.scope}
|
|
291
|
+
- **Version**: ${app.version}
|
|
292
|
+
- **Vendor**: ${app.vendor}
|
|
293
|
+
- **Vendor Prefix**: ${app.vendorPrefix}
|
|
294
|
+
|
|
295
|
+
## Components
|
|
296
|
+
|
|
297
|
+
### Tables
|
|
298
|
+
${app.tables.map(table => `- **${table.label}** (${table.name})
|
|
299
|
+
- Extends: ${table.extends}
|
|
300
|
+
- Fields: ${table.fields.length}`).join('\n')}
|
|
301
|
+
|
|
302
|
+
### Menus
|
|
303
|
+
${app.menus.map(menu => `- **${menu.label}**
|
|
304
|
+
- Modules: ${menu.modules.length}`).join('\n')}
|
|
305
|
+
|
|
306
|
+
## Installation
|
|
307
|
+
1. Import the application package into your ServiceNow instance
|
|
308
|
+
2. Navigate to System Applications > Applications
|
|
309
|
+
3. Find "${app.name}" and click Install
|
|
310
|
+
4. Follow the installation wizard
|
|
311
|
+
|
|
312
|
+
## Configuration
|
|
313
|
+
After installation:
|
|
314
|
+
1. Configure security rules as needed
|
|
315
|
+
2. Set up any required integrations
|
|
316
|
+
3. Customize UI as desired
|
|
317
|
+
|
|
318
|
+
## Usage
|
|
319
|
+
${this.generateUsageInstructions(app)}
|
|
320
|
+
|
|
321
|
+
## Support
|
|
322
|
+
For issues or questions, contact the application vendor.
|
|
323
|
+
|
|
324
|
+
Generated on: ${new Date().toISOString()}
|
|
325
|
+
Generated by: ServiceNow Multi-Agent Framework
|
|
326
|
+
`;
|
|
327
|
+
}
|
|
328
|
+
generateUsageInstructions(app) {
|
|
329
|
+
let instructions = '';
|
|
330
|
+
if (app.tables.length > 0) {
|
|
331
|
+
instructions += '\n### Working with Tables\n';
|
|
332
|
+
app.tables.forEach(table => {
|
|
333
|
+
instructions += `\n**${table.label}**:\n`;
|
|
334
|
+
instructions += `- Navigate to ${app.name} > ${table.label}\n`;
|
|
335
|
+
instructions += `- Use the New button to create records\n`;
|
|
336
|
+
instructions += `- Click on existing records to view/edit\n`;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (app.menus.length > 0) {
|
|
340
|
+
instructions += '\n### Navigation\n';
|
|
341
|
+
app.menus.forEach(menu => {
|
|
342
|
+
instructions += `\n**${menu.label}** menu contains:\n`;
|
|
343
|
+
menu.modules.forEach(module => {
|
|
344
|
+
instructions += `- ${module.label}: ${module.table ? `View ${module.table} records` : 'Custom module'}\n`;
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return instructions || 'See application menus for available features.';
|
|
349
|
+
}
|
|
350
|
+
analyzeAppRequirements(requirements, appType, businessDomain) {
|
|
351
|
+
const analysis = {
|
|
352
|
+
suggestedName: '',
|
|
353
|
+
description: '',
|
|
354
|
+
tables: [],
|
|
355
|
+
features: [],
|
|
356
|
+
workflows: [],
|
|
357
|
+
integrations: []
|
|
358
|
+
};
|
|
359
|
+
// Extract app name suggestion
|
|
360
|
+
const words = requirements.split(/\s+/).slice(0, 3);
|
|
361
|
+
analysis.suggestedName = words.join(' ') + ' App';
|
|
362
|
+
// Detect required tables
|
|
363
|
+
if (requirements.toLowerCase().includes('track') || requirements.toLowerCase().includes('manage')) {
|
|
364
|
+
analysis.tables.push({
|
|
365
|
+
purpose: 'main',
|
|
366
|
+
suggestedName: 'Main Records',
|
|
367
|
+
fields: ['name', 'description', 'status', 'assigned_to']
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
if (requirements.toLowerCase().includes('approve') || requirements.toLowerCase().includes('approval')) {
|
|
371
|
+
analysis.tables.push({
|
|
372
|
+
purpose: 'approval',
|
|
373
|
+
suggestedName: 'Approvals',
|
|
374
|
+
fields: ['request', 'approver', 'status', 'comments']
|
|
375
|
+
});
|
|
376
|
+
analysis.features.push('approval_workflow');
|
|
377
|
+
}
|
|
378
|
+
if (requirements.toLowerCase().includes('report') || requirements.toLowerCase().includes('dashboard')) {
|
|
379
|
+
analysis.features.push('reporting');
|
|
380
|
+
analysis.features.push('dashboard');
|
|
381
|
+
}
|
|
382
|
+
// Detect workflows
|
|
383
|
+
if (requirements.toLowerCase().includes('workflow') || requirements.toLowerCase().includes('process')) {
|
|
384
|
+
analysis.workflows.push('main_process');
|
|
385
|
+
}
|
|
386
|
+
// Detect integrations
|
|
387
|
+
if (requirements.toLowerCase().includes('integrate') || requirements.toLowerCase().includes('api')) {
|
|
388
|
+
analysis.integrations.push('rest_api');
|
|
389
|
+
}
|
|
390
|
+
// Set description
|
|
391
|
+
analysis.description = `${businessDomain || 'Business'} application for ${requirements.substring(0, 100)}...`;
|
|
392
|
+
return analysis;
|
|
393
|
+
}
|
|
394
|
+
generateTablesFromAnalysis(analysis) {
|
|
395
|
+
const tables = [];
|
|
396
|
+
analysis.tables.forEach((tableSpec, index) => {
|
|
397
|
+
const table = {
|
|
398
|
+
name: `u_${tableSpec.suggestedName.toLowerCase().replace(/\s+/g, '_')}`,
|
|
399
|
+
label: tableSpec.suggestedName,
|
|
400
|
+
parent: tableSpec.purpose === 'approval' ? 'sysapproval_approver' : 'task',
|
|
401
|
+
fields: this.generateFieldsFromSpec(tableSpec.fields)
|
|
402
|
+
};
|
|
403
|
+
tables.push(table);
|
|
404
|
+
});
|
|
405
|
+
// Add default table if none specified
|
|
406
|
+
if (tables.length === 0) {
|
|
407
|
+
tables.push({
|
|
408
|
+
name: 'u_main_table',
|
|
409
|
+
label: 'Main Table',
|
|
410
|
+
parent: 'task',
|
|
411
|
+
fields: this.generateDefaultFields()
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return tables;
|
|
415
|
+
}
|
|
416
|
+
generateFieldsFromSpec(fieldNames) {
|
|
417
|
+
const fields = [];
|
|
418
|
+
fieldNames.forEach(fieldName => {
|
|
419
|
+
fields.push(this.createFieldFromName(fieldName));
|
|
420
|
+
});
|
|
421
|
+
return fields;
|
|
422
|
+
}
|
|
423
|
+
createFieldFromName(fieldName) {
|
|
424
|
+
const field = {
|
|
425
|
+
name: `u_${fieldName.toLowerCase().replace(/\s+/g, '_')}`,
|
|
426
|
+
label: fieldName.charAt(0).toUpperCase() + fieldName.slice(1).replace(/_/g, ' '),
|
|
427
|
+
type: 'string',
|
|
428
|
+
max_length: 255
|
|
429
|
+
};
|
|
430
|
+
// Detect field types
|
|
431
|
+
if (fieldName.includes('date') || fieldName.includes('time')) {
|
|
432
|
+
field.type = 'glide_date_time';
|
|
433
|
+
delete field.max_length;
|
|
434
|
+
}
|
|
435
|
+
else if (fieldName.includes('user') || fieldName.includes('assigned')) {
|
|
436
|
+
field.type = 'reference';
|
|
437
|
+
field.reference = 'sys_user';
|
|
438
|
+
delete field.max_length;
|
|
439
|
+
}
|
|
440
|
+
else if (fieldName.includes('group')) {
|
|
441
|
+
field.type = 'reference';
|
|
442
|
+
field.reference = 'sys_user_group';
|
|
443
|
+
delete field.max_length;
|
|
444
|
+
}
|
|
445
|
+
else if (fieldName.includes('status') || fieldName.includes('state')) {
|
|
446
|
+
field.type = 'choice';
|
|
447
|
+
delete field.max_length;
|
|
448
|
+
}
|
|
449
|
+
else if (fieldName.includes('description') || fieldName.includes('comments')) {
|
|
450
|
+
field.type = 'string';
|
|
451
|
+
field.max_length = 4000;
|
|
452
|
+
}
|
|
453
|
+
else if (fieldName.includes('amount') || fieldName.includes('cost') || fieldName.includes('price')) {
|
|
454
|
+
field.type = 'currency';
|
|
455
|
+
delete field.max_length;
|
|
456
|
+
}
|
|
457
|
+
return field;
|
|
458
|
+
}
|
|
459
|
+
generateDefaultFields() {
|
|
460
|
+
return [
|
|
461
|
+
{
|
|
462
|
+
name: 'u_description',
|
|
463
|
+
label: 'Description',
|
|
464
|
+
type: 'string',
|
|
465
|
+
max_length: 4000
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: 'u_status',
|
|
469
|
+
label: 'Status',
|
|
470
|
+
type: 'choice'
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
name: 'u_priority',
|
|
474
|
+
label: 'Priority',
|
|
475
|
+
type: 'integer',
|
|
476
|
+
default_value: 3
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
name: 'u_assigned_user',
|
|
480
|
+
label: 'Assigned User',
|
|
481
|
+
type: 'reference',
|
|
482
|
+
reference: 'sys_user'
|
|
483
|
+
}
|
|
484
|
+
];
|
|
485
|
+
}
|
|
486
|
+
generateMenusFromAnalysis(analysis) {
|
|
487
|
+
const menus = [];
|
|
488
|
+
// Main application menu
|
|
489
|
+
const mainMenu = {
|
|
490
|
+
name: 'main_menu',
|
|
491
|
+
label: analysis.suggestedName,
|
|
492
|
+
application: 'custom',
|
|
493
|
+
modules: []
|
|
494
|
+
};
|
|
495
|
+
// Add modules for each table
|
|
496
|
+
analysis.tables.forEach((tableSpec, index) => {
|
|
497
|
+
const tableName = `u_${tableSpec.suggestedName.toLowerCase().replace(/\s+/g, '_')}`;
|
|
498
|
+
mainMenu.modules.push({
|
|
499
|
+
name: `${tableName}_list`,
|
|
500
|
+
label: `All ${tableSpec.suggestedName}`,
|
|
501
|
+
table: tableName,
|
|
502
|
+
order: (index + 1) * 100
|
|
503
|
+
});
|
|
504
|
+
mainMenu.modules.push({
|
|
505
|
+
name: `${tableName}_new`,
|
|
506
|
+
label: `Create New`,
|
|
507
|
+
table: tableName,
|
|
508
|
+
view: 'new',
|
|
509
|
+
order: (index + 1) * 100 + 10
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
// Add reporting module if needed
|
|
513
|
+
if (analysis.features.includes('reporting')) {
|
|
514
|
+
mainMenu.modules.push({
|
|
515
|
+
name: 'reports',
|
|
516
|
+
label: 'Reports',
|
|
517
|
+
table: 'sys_report',
|
|
518
|
+
filter: `table=u_main_table`,
|
|
519
|
+
order: 900
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
// Add dashboard module if needed
|
|
523
|
+
if (analysis.features.includes('dashboard')) {
|
|
524
|
+
mainMenu.modules.push({
|
|
525
|
+
name: 'dashboard',
|
|
526
|
+
label: 'Dashboard',
|
|
527
|
+
table: 'pa_dashboards',
|
|
528
|
+
order: 50
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
menus.push(mainMenu);
|
|
532
|
+
return menus;
|
|
533
|
+
}
|
|
534
|
+
async generateCompleteApplication(app, analysis) {
|
|
535
|
+
const appPackage = {
|
|
536
|
+
tables: {},
|
|
537
|
+
menus: {},
|
|
538
|
+
security: {},
|
|
539
|
+
scripts: {},
|
|
540
|
+
ui: {},
|
|
541
|
+
workflows: {},
|
|
542
|
+
artifacts: []
|
|
543
|
+
};
|
|
544
|
+
// Generate table definitions
|
|
545
|
+
app.tables.forEach(table => {
|
|
546
|
+
appPackage.tables[table.name] = {
|
|
547
|
+
definition: table,
|
|
548
|
+
dictionary: this.generateTableDictionary(table),
|
|
549
|
+
acls: this.generateTableACLs(table, app.scope)
|
|
550
|
+
};
|
|
551
|
+
appPackage.artifacts.push(this.createArtifact('table_definition', table.name, appPackage.tables[table.name]));
|
|
552
|
+
});
|
|
553
|
+
// Generate menu definitions
|
|
554
|
+
app.menus.forEach(menu => {
|
|
555
|
+
appPackage.menus[menu.name] = {
|
|
556
|
+
definition: menu,
|
|
557
|
+
modules: menu.modules
|
|
558
|
+
};
|
|
559
|
+
appPackage.artifacts.push(this.createArtifact('menu_definition', menu.name, appPackage.menus[menu.name]));
|
|
560
|
+
});
|
|
561
|
+
// Generate security rules
|
|
562
|
+
appPackage.security = this.generateSecurityRules(app);
|
|
563
|
+
// Generate application scripts
|
|
564
|
+
appPackage.scripts = this.generateApplicationScripts(app);
|
|
565
|
+
// Generate UI components
|
|
566
|
+
appPackage.ui = this.generateApplicationUI(app);
|
|
567
|
+
// Generate workflows if needed
|
|
568
|
+
if (analysis.workflows.length > 0) {
|
|
569
|
+
appPackage.workflows = this.generateApplicationWorkflows(app, analysis);
|
|
570
|
+
}
|
|
571
|
+
return appPackage;
|
|
572
|
+
}
|
|
573
|
+
generateTableDictionary(table) {
|
|
574
|
+
return table.fields.map(field => ({
|
|
575
|
+
element: field.name,
|
|
576
|
+
column_label: field.label,
|
|
577
|
+
type: field.type,
|
|
578
|
+
max_length: field.max_length,
|
|
579
|
+
reference: field.reference,
|
|
580
|
+
mandatory: field.mandatory || false,
|
|
581
|
+
default_value: field.default_value,
|
|
582
|
+
attributes: this.getFieldAttributes(field)
|
|
583
|
+
}));
|
|
584
|
+
}
|
|
585
|
+
getFieldAttributes(field) {
|
|
586
|
+
const attributes = [];
|
|
587
|
+
if (field.type === 'reference') {
|
|
588
|
+
attributes.push(`ref_auto_completer=AJAXTableCompleter`);
|
|
589
|
+
attributes.push(`ref_ac_columns=${field.reference}.name`);
|
|
590
|
+
}
|
|
591
|
+
if (field.type === 'choice') {
|
|
592
|
+
attributes.push('edge_encryption_enabled=false');
|
|
593
|
+
}
|
|
594
|
+
return attributes.join(',');
|
|
595
|
+
}
|
|
596
|
+
generateTableACLs(table, scope) {
|
|
597
|
+
const operations = ['create', 'read', 'write', 'delete'];
|
|
598
|
+
const acls = [];
|
|
599
|
+
operations.forEach(operation => {
|
|
600
|
+
acls.push({
|
|
601
|
+
name: `${table.name}.${operation}`,
|
|
602
|
+
operation,
|
|
603
|
+
admin_overrides: true,
|
|
604
|
+
active: true,
|
|
605
|
+
condition: '',
|
|
606
|
+
description: `${operation} access to ${table.label}`,
|
|
607
|
+
script: '',
|
|
608
|
+
type: 'record'
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
return acls;
|
|
612
|
+
}
|
|
613
|
+
generateSecurityRules(app) {
|
|
614
|
+
return {
|
|
615
|
+
roles: [
|
|
616
|
+
{
|
|
617
|
+
name: `${app.scope}.user`,
|
|
618
|
+
description: `User role for ${app.name}`,
|
|
619
|
+
assignable_by: 'admin'
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
name: `${app.scope}.admin`,
|
|
623
|
+
description: `Admin role for ${app.name}`,
|
|
624
|
+
assignable_by: 'admin',
|
|
625
|
+
contains_roles: [`${app.scope}.user`]
|
|
626
|
+
}
|
|
627
|
+
],
|
|
628
|
+
acls: app.tables.map(table => ({
|
|
629
|
+
table: table.name,
|
|
630
|
+
rules: this.generateTableACLs(table, app.scope)
|
|
631
|
+
}))
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
generateApplicationScripts(app) {
|
|
635
|
+
const scripts = {
|
|
636
|
+
script_includes: [],
|
|
637
|
+
business_rules: [],
|
|
638
|
+
client_scripts: []
|
|
639
|
+
};
|
|
640
|
+
// Generate utility script include
|
|
641
|
+
scripts.script_includes.push({
|
|
642
|
+
name: `${app.vendorPrefix}_${app.scope}_Utils`,
|
|
643
|
+
api_name: `${app.vendorPrefix}_${app.scope}_Utils`,
|
|
644
|
+
description: `Utility functions for ${app.name}`,
|
|
645
|
+
script: this.generateUtilityScriptInclude(app),
|
|
646
|
+
access: 'public'
|
|
647
|
+
});
|
|
648
|
+
// Generate business rules for main tables
|
|
649
|
+
app.tables.forEach(table => {
|
|
650
|
+
if (table.fields.some(f => f.name.includes('number'))) {
|
|
651
|
+
scripts.business_rules.push({
|
|
652
|
+
name: `Generate ${table.label} Number`,
|
|
653
|
+
table: table.name,
|
|
654
|
+
when: 'before',
|
|
655
|
+
insert: true,
|
|
656
|
+
script: this.generateNumberingBusinessRule(table),
|
|
657
|
+
order: 100
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
return scripts;
|
|
662
|
+
}
|
|
663
|
+
generateUtilityScriptInclude(app) {
|
|
664
|
+
return `var ${app.vendorPrefix}_${app.scope}_Utils = Class.create();
|
|
665
|
+
${app.vendorPrefix}_${app.scope}_Utils.prototype = {
|
|
666
|
+
initialize: function() {
|
|
667
|
+
},
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Get application properties
|
|
671
|
+
*/
|
|
672
|
+
getAppProperties: function() {
|
|
673
|
+
return {
|
|
674
|
+
scope: '${app.scope}',
|
|
675
|
+
version: '${app.version}',
|
|
676
|
+
name: '${app.name}'
|
|
677
|
+
};
|
|
678
|
+
},
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Log application message
|
|
682
|
+
*/
|
|
683
|
+
log: function(message, source) {
|
|
684
|
+
gs.info('[${app.name}] ' + (source || 'General') + ': ' + message);
|
|
685
|
+
},
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Check user role
|
|
689
|
+
*/
|
|
690
|
+
hasRole: function(role) {
|
|
691
|
+
return gs.hasRole(role) || gs.hasRole('${app.scope}.admin') || gs.hasRole('admin');
|
|
692
|
+
},
|
|
693
|
+
|
|
694
|
+
type: '${app.vendorPrefix}_${app.scope}_Utils'
|
|
695
|
+
};`;
|
|
696
|
+
}
|
|
697
|
+
generateNumberingBusinessRule(table) {
|
|
698
|
+
return `(function executeRule(current, previous /*null when async*/) {
|
|
699
|
+
// Generate unique number for ${table.label}
|
|
700
|
+
if (!current.number) {
|
|
701
|
+
var prefix = '${table.label.substring(0, 3).toUpperCase()}';
|
|
702
|
+
var gr = new GlideRecord('${table.name}');
|
|
703
|
+
gr.orderByDesc('sys_created_on');
|
|
704
|
+
gr.setLimit(1);
|
|
705
|
+
gr.query();
|
|
706
|
+
|
|
707
|
+
var lastNumber = 1000;
|
|
708
|
+
if (gr.next() && gr.number) {
|
|
709
|
+
var num = parseInt(gr.number.replace(/[^0-9]/g, ''));
|
|
710
|
+
if (!isNaN(num)) {
|
|
711
|
+
lastNumber = num;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
current.number = prefix + String(lastNumber + 1).padStart(7, '0');
|
|
716
|
+
}
|
|
717
|
+
})(current, previous);`;
|
|
718
|
+
}
|
|
719
|
+
generateApplicationUI(app) {
|
|
720
|
+
return {
|
|
721
|
+
ui_pages: [],
|
|
722
|
+
ui_macros: [],
|
|
723
|
+
widgets: [
|
|
724
|
+
{
|
|
725
|
+
name: `${app.scope}_dashboard`,
|
|
726
|
+
title: `${app.name} Dashboard`,
|
|
727
|
+
template: this.generateDashboardWidget(app),
|
|
728
|
+
css: this.generateDashboardCSS(),
|
|
729
|
+
server_script: this.generateDashboardServerScript(app),
|
|
730
|
+
client_script: this.generateDashboardClientScript()
|
|
731
|
+
}
|
|
732
|
+
]
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
generateDashboardWidget(app) {
|
|
736
|
+
return `<div class="app-dashboard">
|
|
737
|
+
<div class="dashboard-header">
|
|
738
|
+
<h2>${app.name} Dashboard</h2>
|
|
739
|
+
</div>
|
|
740
|
+
|
|
741
|
+
<div class="dashboard-stats">
|
|
742
|
+
${app.tables.map(table => `
|
|
743
|
+
<div class="stat-card">
|
|
744
|
+
<h3>${table.label}</h3>
|
|
745
|
+
<div class="stat-value">{{data.${table.name}_count || 0}}</div>
|
|
746
|
+
<a href="?id=${table.name}_list" class="stat-link">View All</a>
|
|
747
|
+
</div>
|
|
748
|
+
`).join('')}
|
|
749
|
+
</div>
|
|
750
|
+
|
|
751
|
+
<div class="dashboard-charts">
|
|
752
|
+
<div class="chart-container">
|
|
753
|
+
<canvas id="main-chart"></canvas>
|
|
754
|
+
</div>
|
|
755
|
+
</div>
|
|
756
|
+
</div>`;
|
|
757
|
+
}
|
|
758
|
+
generateDashboardCSS() {
|
|
759
|
+
return `.app-dashboard {
|
|
760
|
+
padding: 20px;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.dashboard-header {
|
|
764
|
+
margin-bottom: 30px;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.dashboard-stats {
|
|
768
|
+
display: grid;
|
|
769
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
770
|
+
gap: 20px;
|
|
771
|
+
margin-bottom: 30px;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.stat-card {
|
|
775
|
+
background: #fff;
|
|
776
|
+
padding: 20px;
|
|
777
|
+
border-radius: 8px;
|
|
778
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
779
|
+
text-align: center;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.stat-value {
|
|
783
|
+
font-size: 36px;
|
|
784
|
+
font-weight: bold;
|
|
785
|
+
color: #0078d4;
|
|
786
|
+
margin: 10px 0;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.stat-link {
|
|
790
|
+
color: #0078d4;
|
|
791
|
+
text-decoration: none;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.chart-container {
|
|
795
|
+
background: #fff;
|
|
796
|
+
padding: 20px;
|
|
797
|
+
border-radius: 8px;
|
|
798
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
799
|
+
}`;
|
|
800
|
+
}
|
|
801
|
+
generateDashboardServerScript(app) {
|
|
802
|
+
return `(function() {
|
|
803
|
+
data.tables = [];
|
|
804
|
+
|
|
805
|
+
${app.tables.map(table => `
|
|
806
|
+
// Count ${table.label} records
|
|
807
|
+
var ${table.name}_count = new GlideAggregate('${table.name}');
|
|
808
|
+
${table.name}_count.addAggregate('COUNT');
|
|
809
|
+
${table.name}_count.query();
|
|
810
|
+
if (${table.name}_count.next()) {
|
|
811
|
+
data.${table.name}_count = ${table.name}_count.getAggregate('COUNT');
|
|
812
|
+
}
|
|
813
|
+
`).join('\n')}
|
|
814
|
+
})();`;
|
|
815
|
+
}
|
|
816
|
+
generateDashboardClientScript() {
|
|
817
|
+
return `function() {
|
|
818
|
+
var c = this;
|
|
819
|
+
|
|
820
|
+
c.$onInit = function() {
|
|
821
|
+
initializeCharts();
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
function initializeCharts() {
|
|
825
|
+
// Initialize dashboard charts
|
|
826
|
+
console.log('Dashboard initialized');
|
|
827
|
+
}
|
|
828
|
+
}`;
|
|
829
|
+
}
|
|
830
|
+
generateApplicationWorkflows(app, analysis) {
|
|
831
|
+
const workflows = {};
|
|
832
|
+
if (analysis.features.includes('approval_workflow')) {
|
|
833
|
+
workflows.approval = {
|
|
834
|
+
name: `${app.scope}_approval_workflow`,
|
|
835
|
+
table: app.tables[0]?.name,
|
|
836
|
+
description: `Approval workflow for ${app.name}`,
|
|
837
|
+
stages: [
|
|
838
|
+
{
|
|
839
|
+
name: 'Submit for Approval',
|
|
840
|
+
type: 'begin'
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
name: 'Manager Approval',
|
|
844
|
+
type: 'approval',
|
|
845
|
+
approvers: 'current.opened_by.manager'
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
name: 'Update Status',
|
|
849
|
+
type: 'script',
|
|
850
|
+
script: 'current.state = "approved"; current.update();'
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
name: 'Send Notification',
|
|
854
|
+
type: 'notification',
|
|
855
|
+
recipients: 'current.opened_by'
|
|
856
|
+
}
|
|
857
|
+
]
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
return workflows;
|
|
861
|
+
}
|
|
862
|
+
generateApplicationCommands(app, appPackage) {
|
|
863
|
+
const commands = [];
|
|
864
|
+
const baseDir = `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${app.scope}`;
|
|
865
|
+
// Create directory structure
|
|
866
|
+
commands.push(this.generateCommand('Bash', 'create', {
|
|
867
|
+
command: `mkdir -p ${baseDir}/{sys_app,tables,menus,security,scripts,ui,workflows,docs,export}`,
|
|
868
|
+
description: 'Create complete application directory structure'
|
|
869
|
+
}, 'Create directories'));
|
|
870
|
+
// Generate table files
|
|
871
|
+
Object.entries(appPackage.tables).forEach(([tableName, tableData]) => {
|
|
872
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
873
|
+
file_path: `${baseDir}/tables/${tableName}.json`,
|
|
874
|
+
content: JSON.stringify(tableData, null, 2)
|
|
875
|
+
}, `Create table definition: ${tableName}`));
|
|
876
|
+
});
|
|
877
|
+
// Generate menu files
|
|
878
|
+
Object.entries(appPackage.menus).forEach(([menuName, menuData]) => {
|
|
879
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
880
|
+
file_path: `${baseDir}/menus/${menuName}.json`,
|
|
881
|
+
content: JSON.stringify(menuData, null, 2)
|
|
882
|
+
}, `Create menu definition: ${menuName}`));
|
|
883
|
+
});
|
|
884
|
+
// Generate security files
|
|
885
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
886
|
+
file_path: `${baseDir}/security/roles.json`,
|
|
887
|
+
content: JSON.stringify(appPackage.security.roles, null, 2)
|
|
888
|
+
}, 'Create security roles'), this.generateCommand('Write', 'create', {
|
|
889
|
+
file_path: `${baseDir}/security/acls.json`,
|
|
890
|
+
content: JSON.stringify(appPackage.security.acls, null, 2)
|
|
891
|
+
}, 'Create access control lists'));
|
|
892
|
+
// Generate script files
|
|
893
|
+
if (appPackage.scripts.script_includes.length > 0) {
|
|
894
|
+
appPackage.scripts.script_includes.forEach((script) => {
|
|
895
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
896
|
+
file_path: `${baseDir}/scripts/script_includes/${script.api_name}.js`,
|
|
897
|
+
content: script.script
|
|
898
|
+
}, `Create script include: ${script.api_name}`));
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
// Generate UI files
|
|
902
|
+
if (appPackage.ui.widgets.length > 0) {
|
|
903
|
+
appPackage.ui.widgets.forEach((widget) => {
|
|
904
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
905
|
+
file_path: `${baseDir}/ui/widgets/${widget.name}.json`,
|
|
906
|
+
content: JSON.stringify(widget, null, 2)
|
|
907
|
+
}, `Create widget: ${widget.name}`));
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
// Generate documentation
|
|
911
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
912
|
+
file_path: `${baseDir}/README.md`,
|
|
913
|
+
content: this.generateApplicationReadme(app)
|
|
914
|
+
}, 'Create application README'), this.generateCommand('Write', 'create', {
|
|
915
|
+
file_path: `${baseDir}/docs/developer-guide.md`,
|
|
916
|
+
content: this.generateDeveloperGuide(app)
|
|
917
|
+
}, 'Create developer guide'));
|
|
918
|
+
return commands;
|
|
919
|
+
}
|
|
920
|
+
generateComponentCommands(scope, components) {
|
|
921
|
+
const commands = [];
|
|
922
|
+
const baseDir = `/Users/nielsvanderwerf/Projects/servicenow_multiagent/output/applications/${scope}`;
|
|
923
|
+
// Generate commands for tables
|
|
924
|
+
components.tables.forEach((table) => {
|
|
925
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
926
|
+
file_path: `${baseDir}/tables/${table.name}.json`,
|
|
927
|
+
content: JSON.stringify({
|
|
928
|
+
definition: table,
|
|
929
|
+
dictionary: this.generateTableDictionary(table),
|
|
930
|
+
acls: this.generateTableACLs(table, scope)
|
|
931
|
+
}, null, 2)
|
|
932
|
+
}, `Create table: ${table.name}`));
|
|
933
|
+
});
|
|
934
|
+
// Generate commands for menus
|
|
935
|
+
components.menus.forEach((menu) => {
|
|
936
|
+
commands.push(this.generateCommand('Write', 'create', {
|
|
937
|
+
file_path: `${baseDir}/menus/${menu.name}.json`,
|
|
938
|
+
content: JSON.stringify({
|
|
939
|
+
definition: menu,
|
|
940
|
+
modules: menu.modules
|
|
941
|
+
}, null, 2)
|
|
942
|
+
}, `Create menu: ${menu.name}`));
|
|
943
|
+
});
|
|
944
|
+
return commands;
|
|
945
|
+
}
|
|
946
|
+
createApplicationTable(tableSpec, scope) {
|
|
947
|
+
return {
|
|
948
|
+
name: tableSpec.name || `u_${tableSpec.label.toLowerCase().replace(/\s+/g, '_')}`,
|
|
949
|
+
label: tableSpec.label,
|
|
950
|
+
parent: tableSpec.extends || 'task',
|
|
951
|
+
fields: tableSpec.fields?.map((field) => this.createFieldFromSpec(field)) || this.generateDefaultFields()
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
createFieldFromSpec(fieldSpec) {
|
|
955
|
+
return {
|
|
956
|
+
name: fieldSpec.name || `u_${fieldSpec.label.toLowerCase().replace(/\s+/g, '_')}`,
|
|
957
|
+
label: fieldSpec.label,
|
|
958
|
+
type: fieldSpec.type || 'string',
|
|
959
|
+
max_length: fieldSpec.max_length,
|
|
960
|
+
reference: fieldSpec.reference,
|
|
961
|
+
mandatory: fieldSpec.mandatory || false,
|
|
962
|
+
default_value: fieldSpec.default_value
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
createApplicationMenu(menuSpec, scope) {
|
|
966
|
+
return {
|
|
967
|
+
name: menuSpec.name || 'custom_menu',
|
|
968
|
+
label: menuSpec.label,
|
|
969
|
+
application: menuSpec.application || scope,
|
|
970
|
+
modules: menuSpec.modules?.map((module, index) => ({
|
|
971
|
+
name: module.name,
|
|
972
|
+
label: module.label,
|
|
973
|
+
table: module.table,
|
|
974
|
+
view: module.view,
|
|
975
|
+
filter: module.filter,
|
|
976
|
+
order: module.order || (index + 1) * 100
|
|
977
|
+
})) || []
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
generateManifest(app) {
|
|
981
|
+
return {
|
|
982
|
+
name: app.name,
|
|
983
|
+
scope: app.scope,
|
|
984
|
+
version: app.version,
|
|
985
|
+
vendor: app.vendor,
|
|
986
|
+
vendor_prefix: app.vendorPrefix,
|
|
987
|
+
runtime_access_tracking: 'permissive',
|
|
988
|
+
install_date: new Date().toISOString(),
|
|
989
|
+
dependencies: [],
|
|
990
|
+
repository_url: ''
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
generateMetadata(app) {
|
|
994
|
+
return {
|
|
995
|
+
sys_id: this.generateSysId(),
|
|
996
|
+
sys_created_on: new Date().toISOString(),
|
|
997
|
+
sys_created_by: 'admin',
|
|
998
|
+
sys_updated_on: new Date().toISOString(),
|
|
999
|
+
sys_updated_by: 'admin',
|
|
1000
|
+
sys_class_name: 'sys_app',
|
|
1001
|
+
sys_scope: app.scope
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
generateSysId() {
|
|
1005
|
+
// Generate a mock sys_id (32 character hex string)
|
|
1006
|
+
return Array.from({ length: 32 }, () => Math.floor(Math.random() * 16).toString(16)).join('');
|
|
1007
|
+
}
|
|
1008
|
+
generateSampleData(app) {
|
|
1009
|
+
const sampleData = {};
|
|
1010
|
+
app.tables.forEach(table => {
|
|
1011
|
+
sampleData[table.name] = this.generateTableSampleData(table);
|
|
1012
|
+
});
|
|
1013
|
+
return sampleData;
|
|
1014
|
+
}
|
|
1015
|
+
generateTableSampleData(table) {
|
|
1016
|
+
const samples = [];
|
|
1017
|
+
for (let i = 1; i <= 5; i++) {
|
|
1018
|
+
const record = {
|
|
1019
|
+
number: `${table.label.substring(0, 3).toUpperCase()}000000${i}`,
|
|
1020
|
+
short_description: `Sample ${table.label} ${i}`,
|
|
1021
|
+
sys_created_on: new Date().toISOString(),
|
|
1022
|
+
sys_created_by: 'admin'
|
|
1023
|
+
};
|
|
1024
|
+
// Add field values
|
|
1025
|
+
table.fields.forEach(field => {
|
|
1026
|
+
if (!record[field.name]) {
|
|
1027
|
+
record[field.name] = this.generateFieldSampleValue(field, i);
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
samples.push(record);
|
|
1031
|
+
}
|
|
1032
|
+
return samples;
|
|
1033
|
+
}
|
|
1034
|
+
generateFieldSampleValue(field, index) {
|
|
1035
|
+
switch (field.type) {
|
|
1036
|
+
case 'string':
|
|
1037
|
+
return `Sample ${field.label} ${index}`;
|
|
1038
|
+
case 'integer':
|
|
1039
|
+
return index;
|
|
1040
|
+
case 'boolean':
|
|
1041
|
+
return index % 2 === 0;
|
|
1042
|
+
case 'reference':
|
|
1043
|
+
return ''; // Empty reference
|
|
1044
|
+
case 'choice':
|
|
1045
|
+
return 'option_' + index;
|
|
1046
|
+
case 'glide_date_time':
|
|
1047
|
+
return new Date().toISOString();
|
|
1048
|
+
case 'currency':
|
|
1049
|
+
return (index * 100).toFixed(2);
|
|
1050
|
+
default:
|
|
1051
|
+
return `Value ${index}`;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
generateXMLExport(appPackage) {
|
|
1055
|
+
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
|
1056
|
+
xml += '<unload unload_date="' + new Date().toISOString() + '">\n';
|
|
1057
|
+
// Add application record
|
|
1058
|
+
xml += ' <sys_app>\n';
|
|
1059
|
+
xml += ' ' + this.objectToXML(appPackage.manifest) + '\n';
|
|
1060
|
+
xml += ' </sys_app>\n';
|
|
1061
|
+
// Add tables
|
|
1062
|
+
Object.values(appPackage.tables).forEach((table) => {
|
|
1063
|
+
xml += ' <sys_db_object>\n';
|
|
1064
|
+
xml += ' ' + this.objectToXML(table.definition) + '\n';
|
|
1065
|
+
xml += ' </sys_db_object>\n';
|
|
1066
|
+
});
|
|
1067
|
+
xml += '</unload>';
|
|
1068
|
+
return xml;
|
|
1069
|
+
}
|
|
1070
|
+
generateUpdateSetXML(appPackage) {
|
|
1071
|
+
// Simplified update set XML
|
|
1072
|
+
return this.generateXMLExport(appPackage);
|
|
1073
|
+
}
|
|
1074
|
+
objectToXML(obj, indent = '') {
|
|
1075
|
+
let xml = '';
|
|
1076
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
1077
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
1078
|
+
xml += `${indent}<${key}>\n${this.objectToXML(value, indent + ' ')}\n${indent}</${key}>`;
|
|
1079
|
+
}
|
|
1080
|
+
else if (Array.isArray(value)) {
|
|
1081
|
+
xml += `${indent}<${key}>${JSON.stringify(value)}</${key}>`;
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
xml += `${indent}<${key}>${value}</${key}>`;
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
return xml;
|
|
1088
|
+
}
|
|
1089
|
+
generateInstallationGuide(app) {
|
|
1090
|
+
return `# Installation Guide - ${app.name}
|
|
1091
|
+
|
|
1092
|
+
## Prerequisites
|
|
1093
|
+
- ServiceNow instance (version Madrid or later)
|
|
1094
|
+
- Admin access to the instance
|
|
1095
|
+
- Update set or application repository access
|
|
1096
|
+
|
|
1097
|
+
## Installation Steps
|
|
1098
|
+
|
|
1099
|
+
### Method 1: Update Set Installation
|
|
1100
|
+
1. Download the update set file: ${app.scope}_update_set.xml
|
|
1101
|
+
2. Log in to your ServiceNow instance as an administrator
|
|
1102
|
+
3. Navigate to **System Update Sets > Retrieved Update Sets**
|
|
1103
|
+
4. Click **Import Update Set from XML**
|
|
1104
|
+
5. Choose the downloaded file and click **Upload**
|
|
1105
|
+
6. Preview the update set to check for conflicts
|
|
1106
|
+
7. Commit the update set
|
|
1107
|
+
|
|
1108
|
+
### Method 2: Application Repository
|
|
1109
|
+
1. Navigate to **System Applications > Applications**
|
|
1110
|
+
2. Click **New** > **Import from Source Control**
|
|
1111
|
+
3. Enter the repository URL (if available)
|
|
1112
|
+
4. Follow the import wizard
|
|
1113
|
+
|
|
1114
|
+
### Method 3: Manual Installation
|
|
1115
|
+
1. Navigate to **System Applications > Studio**
|
|
1116
|
+
2. Create a new application with scope: ${app.scope}
|
|
1117
|
+
3. Import the application files from the export directory
|
|
1118
|
+
|
|
1119
|
+
## Post-Installation Configuration
|
|
1120
|
+
|
|
1121
|
+
### 1. Security Setup
|
|
1122
|
+
- Navigate to **User Administration > Roles**
|
|
1123
|
+
- Verify the following roles were created:
|
|
1124
|
+
- ${app.scope}.user
|
|
1125
|
+
- ${app.scope}.admin
|
|
1126
|
+
- Assign roles to appropriate users or groups
|
|
1127
|
+
|
|
1128
|
+
### 2. Data Migration (if applicable)
|
|
1129
|
+
- If migrating existing data, use the Transform Maps feature
|
|
1130
|
+
- Map fields from legacy tables to new application tables
|
|
1131
|
+
|
|
1132
|
+
### 3. Integration Setup
|
|
1133
|
+
- Configure any required integrations
|
|
1134
|
+
- Update REST endpoints if needed
|
|
1135
|
+
- Set up scheduled jobs if applicable
|
|
1136
|
+
|
|
1137
|
+
## Verification Steps
|
|
1138
|
+
|
|
1139
|
+
1. **Check Application Status**
|
|
1140
|
+
- Navigate to **System Applications > Applications**
|
|
1141
|
+
- Verify ${app.name} shows as "Installed"
|
|
1142
|
+
|
|
1143
|
+
2. **Test Basic Functionality**
|
|
1144
|
+
- Access the application menu
|
|
1145
|
+
- Create a test record
|
|
1146
|
+
- Verify workflows trigger correctly
|
|
1147
|
+
|
|
1148
|
+
3. **Validate Security**
|
|
1149
|
+
- Test with different user roles
|
|
1150
|
+
- Verify access controls work as expected
|
|
1151
|
+
|
|
1152
|
+
## Troubleshooting
|
|
1153
|
+
|
|
1154
|
+
### Common Issues
|
|
1155
|
+
|
|
1156
|
+
**Issue**: Application menu not visible
|
|
1157
|
+
- **Solution**: Clear browser cache and refresh, check role assignments
|
|
1158
|
+
|
|
1159
|
+
**Issue**: Tables not accessible
|
|
1160
|
+
- **Solution**: Verify ACLs are active, check user roles
|
|
1161
|
+
|
|
1162
|
+
**Issue**: Workflows not triggering
|
|
1163
|
+
- **Solution**: Check workflow status, verify conditions
|
|
1164
|
+
|
|
1165
|
+
## Support
|
|
1166
|
+
For issues or questions:
|
|
1167
|
+
- Check application logs in System Logs
|
|
1168
|
+
- Contact your ServiceNow administrator
|
|
1169
|
+
- Refer to the developer guide for customization
|
|
1170
|
+
|
|
1171
|
+
Generated on: ${new Date().toISOString()}
|
|
1172
|
+
`;
|
|
1173
|
+
}
|
|
1174
|
+
generateDeveloperGuide(app) {
|
|
1175
|
+
return `# Developer Guide - ${app.name}
|
|
1176
|
+
|
|
1177
|
+
## Application Overview
|
|
1178
|
+
- **Scope**: ${app.scope}
|
|
1179
|
+
- **Version**: ${app.version}
|
|
1180
|
+
- **Tables**: ${app.tables.length}
|
|
1181
|
+
- **Menus**: ${app.menus.length}
|
|
1182
|
+
|
|
1183
|
+
## Architecture
|
|
1184
|
+
|
|
1185
|
+
### Data Model
|
|
1186
|
+
${app.tables.map(table => `
|
|
1187
|
+
#### ${table.label} (${table.name})
|
|
1188
|
+
- **Extends**: ${table.extends}
|
|
1189
|
+
- **Purpose**: Primary table for storing ${table.label.toLowerCase()} records
|
|
1190
|
+
|
|
1191
|
+
**Fields**:
|
|
1192
|
+
${table.fields.map(field => `- **${field.label}** (${field.name}): ${field.type}${field.reference ? ` -> ${field.reference}` : ''}`).join('\n')}
|
|
1193
|
+
`).join('\n')}
|
|
1194
|
+
|
|
1195
|
+
### Security Model
|
|
1196
|
+
- **Roles**:
|
|
1197
|
+
- ${app.scope}.user: Basic user access
|
|
1198
|
+
- ${app.scope}.admin: Administrative access
|
|
1199
|
+
- **ACLs**: Table-level access controls for CRUD operations
|
|
1200
|
+
|
|
1201
|
+
## Development Guidelines
|
|
1202
|
+
|
|
1203
|
+
### Naming Conventions
|
|
1204
|
+
- Tables: u_[descriptive_name]
|
|
1205
|
+
- Fields: u_[field_name]
|
|
1206
|
+
- Script Includes: ${app.vendorPrefix}_[ClassName]
|
|
1207
|
+
- Business Rules: [Table] - [Action] - [Description]
|
|
1208
|
+
|
|
1209
|
+
### Coding Standards
|
|
1210
|
+
\`\`\`javascript
|
|
1211
|
+
// Use the application's utility class
|
|
1212
|
+
var utils = new ${app.vendorPrefix}_${app.scope}_Utils();
|
|
1213
|
+
utils.log('Debug message', 'MethodName');
|
|
1214
|
+
|
|
1215
|
+
// Check permissions
|
|
1216
|
+
if (!utils.hasRole('${app.scope}.user')) {
|
|
1217
|
+
gs.addErrorMessage('Insufficient permissions');
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
\`\`\`
|
|
1221
|
+
|
|
1222
|
+
### Best Practices
|
|
1223
|
+
1. Always use scoped APIs when available
|
|
1224
|
+
2. Implement proper error handling
|
|
1225
|
+
3. Log important operations for debugging
|
|
1226
|
+
4. Follow ServiceNow development best practices
|
|
1227
|
+
|
|
1228
|
+
## Extending the Application
|
|
1229
|
+
|
|
1230
|
+
### Adding New Tables
|
|
1231
|
+
1. Create table extending appropriate base table
|
|
1232
|
+
2. Add necessary fields with u_ prefix
|
|
1233
|
+
3. Create ACLs for the new table
|
|
1234
|
+
4. Update navigation menus
|
|
1235
|
+
|
|
1236
|
+
### Creating Business Rules
|
|
1237
|
+
\`\`\`javascript
|
|
1238
|
+
(function executeRule(current, previous /*null when async*/) {
|
|
1239
|
+
// Your business logic here
|
|
1240
|
+
var utils = new ${app.vendorPrefix}_${app.scope}_Utils();
|
|
1241
|
+
utils.log('Business rule triggered', 'RuleName');
|
|
1242
|
+
})(current, previous);
|
|
1243
|
+
\`\`\`
|
|
1244
|
+
|
|
1245
|
+
### Adding UI Components
|
|
1246
|
+
1. Service Portal Widgets: Use provided dashboard widget as template
|
|
1247
|
+
2. UI Pages: Follow existing UI page patterns
|
|
1248
|
+
3. Client Scripts: Ensure proper form context usage
|
|
1249
|
+
|
|
1250
|
+
## API Reference
|
|
1251
|
+
|
|
1252
|
+
### ${app.vendorPrefix}_${app.scope}_Utils
|
|
1253
|
+
Main utility class for the application.
|
|
1254
|
+
|
|
1255
|
+
**Methods**:
|
|
1256
|
+
- getAppProperties(): Returns application metadata
|
|
1257
|
+
- log(message, source): Logs application messages
|
|
1258
|
+
- hasRole(role): Checks user permissions
|
|
1259
|
+
|
|
1260
|
+
## Testing
|
|
1261
|
+
|
|
1262
|
+
### Unit Testing
|
|
1263
|
+
\`\`\`javascript
|
|
1264
|
+
// Test script for Script Includes
|
|
1265
|
+
var utils = new ${app.vendorPrefix}_${app.scope}_Utils();
|
|
1266
|
+
gs.info('Testing utility class: ' + utils.type);
|
|
1267
|
+
\`\`\`
|
|
1268
|
+
|
|
1269
|
+
### Integration Testing
|
|
1270
|
+
1. Test all CRUD operations
|
|
1271
|
+
2. Verify workflow execution
|
|
1272
|
+
3. Check security controls
|
|
1273
|
+
4. Validate UI functionality
|
|
1274
|
+
|
|
1275
|
+
## Deployment
|
|
1276
|
+
|
|
1277
|
+
### Moving Between Instances
|
|
1278
|
+
1. Use Update Sets for controlled deployments
|
|
1279
|
+
2. Export application to source control
|
|
1280
|
+
3. Use application repository for version control
|
|
1281
|
+
|
|
1282
|
+
### Version Management
|
|
1283
|
+
- Follow semantic versioning (MAJOR.MINOR.PATCH)
|
|
1284
|
+
- Document all changes in release notes
|
|
1285
|
+
- Test thoroughly before version updates
|
|
1286
|
+
|
|
1287
|
+
Generated by: ServiceNow Multi-Agent Framework
|
|
1288
|
+
`;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
exports.AppCreatorAgent = AppCreatorAgent;
|
|
1292
|
+
//# sourceMappingURL=app-creator.agent.js.map
|