snow-flow 4.3.0 ā 4.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/auth.js +87 -41
- package/dist/cli.js +2 -63
- package/dist/mcp/servicenow-knowledge-catalog-mcp.js +431 -429
- package/package.json +1 -1
package/dist/cli/auth.js
CHANGED
|
@@ -1,59 +1,105 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.registerAuthCommands = registerAuthCommands;
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
4
|
+
const snow_oauth_js_1 = require("../utils/snow-oauth.js");
|
|
5
|
+
const servicenow_client_js_1 = require("../utils/servicenow-client.js");
|
|
6
|
+
const logger_js_1 = require("../utils/logger.js");
|
|
7
|
+
const authLogger = new logger_js_1.Logger('auth');
|
|
10
8
|
function registerAuthCommands(program) {
|
|
11
|
-
const auth = program.command('auth').description('
|
|
9
|
+
const auth = program.command('auth').description('ServiceNow authentication management');
|
|
12
10
|
auth
|
|
13
11
|
.command('login')
|
|
14
|
-
.description('
|
|
15
|
-
.option('--
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
.description('Login to ServiceNow using OAuth 2.0')
|
|
13
|
+
.option('--instance <instance>', 'ServiceNow instance (e.g., dev12345.service-now.com)')
|
|
14
|
+
.option('--client-id <clientId>', 'OAuth Client ID')
|
|
15
|
+
.option('--client-secret <clientSecret>', 'OAuth Client Secret')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
const oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
18
|
+
authLogger.info('š Starting ServiceNow OAuth authentication...');
|
|
19
|
+
// Get credentials from options or environment
|
|
20
|
+
const instance = options.instance || process.env.SNOW_INSTANCE;
|
|
21
|
+
const clientId = options.clientId || process.env.SNOW_CLIENT_ID;
|
|
22
|
+
const clientSecret = options.clientSecret || process.env.SNOW_CLIENT_SECRET;
|
|
23
|
+
if (!instance || !clientId || !clientSecret) {
|
|
24
|
+
console.error('ā Missing required OAuth credentials');
|
|
25
|
+
authLogger.info('\nš Please provide:');
|
|
26
|
+
authLogger.info(' --instance: ServiceNow instance (e.g., dev12345.service-now.com)');
|
|
27
|
+
authLogger.info(' --client-id: OAuth Client ID');
|
|
28
|
+
authLogger.info(' --client-secret: OAuth Client Secret');
|
|
29
|
+
authLogger.info('\nš” Or set environment variables:');
|
|
30
|
+
authLogger.info(' export SNOW_INSTANCE=your-instance.service-now.com');
|
|
31
|
+
authLogger.info(' export SNOW_CLIENT_ID=your-client-id');
|
|
32
|
+
authLogger.info(' export SNOW_CLIENT_SECRET=your-client-secret');
|
|
22
33
|
return;
|
|
23
34
|
}
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
// Start OAuth flow
|
|
36
|
+
const result = await oauth.authenticate(instance, clientId, clientSecret);
|
|
37
|
+
if (result.success) {
|
|
38
|
+
authLogger.info('\nā
Authentication successful!');
|
|
39
|
+
authLogger.info('š Snow-Flow is now connected to ServiceNow!');
|
|
40
|
+
authLogger.info('\nš Next steps:');
|
|
41
|
+
authLogger.info(' 1. Test connection: snow-flow auth status');
|
|
42
|
+
authLogger.info(' 2. Start development: snow-flow swarm "create a widget for incident management"');
|
|
43
|
+
// Test connection
|
|
44
|
+
const client = new servicenow_client_js_1.ServiceNowClient();
|
|
45
|
+
const testResult = await client.testConnection();
|
|
46
|
+
if (testResult.success) {
|
|
47
|
+
authLogger.info(`\nš Connection test successful!`);
|
|
48
|
+
authLogger.info(`š¤ Logged in as: ${testResult.data.name} (${testResult.data.user_name})`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.error(`\nā Authentication failed: ${result.error}`);
|
|
26
53
|
process.exit(1);
|
|
27
54
|
}
|
|
28
|
-
(0, keys_js_1.setApiKey)(p, apiKey);
|
|
29
|
-
console.log(chalk_1.default.green(`Saved API key for ${p}.`));
|
|
30
55
|
});
|
|
31
56
|
auth
|
|
32
|
-
.command('
|
|
33
|
-
.description('
|
|
34
|
-
.
|
|
35
|
-
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
|
|
57
|
+
.command('logout')
|
|
58
|
+
.description('Logout from ServiceNow')
|
|
59
|
+
.action(async () => {
|
|
60
|
+
const oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
61
|
+
authLogger.info('š Logging out from ServiceNow...');
|
|
62
|
+
await oauth.logout();
|
|
63
|
+
authLogger.info('ā
Logged out successfully');
|
|
39
64
|
});
|
|
40
65
|
auth
|
|
41
|
-
.command('
|
|
42
|
-
.description('Show
|
|
43
|
-
.action(() => {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
66
|
+
.command('status')
|
|
67
|
+
.description('Show ServiceNow authentication status')
|
|
68
|
+
.action(async () => {
|
|
69
|
+
const oauth = new snow_oauth_js_1.ServiceNowOAuth();
|
|
70
|
+
authLogger.info('š ServiceNow Authentication Status:');
|
|
71
|
+
const isAuthenticated = await oauth.isAuthenticated();
|
|
72
|
+
const credentials = await oauth.loadCredentials();
|
|
73
|
+
if (isAuthenticated && credentials) {
|
|
74
|
+
console.log(' āāā Status: ā
Authenticated');
|
|
75
|
+
console.log(` āāā Instance: ${credentials.instance}`);
|
|
76
|
+
console.log(' āāā Method: OAuth 2.0');
|
|
77
|
+
console.log(` āāā Client ID: ${credentials.clientId}`);
|
|
78
|
+
if (credentials.expiresAt) {
|
|
79
|
+
const expiresAt = new Date(credentials.expiresAt);
|
|
80
|
+
console.log(` āāā Token expires: ${expiresAt.toLocaleString()}`);
|
|
81
|
+
}
|
|
82
|
+
// Test connection
|
|
83
|
+
const client = new servicenow_client_js_1.ServiceNowClient();
|
|
84
|
+
const testResult = await client.testConnection();
|
|
85
|
+
if (testResult.success) {
|
|
86
|
+
console.log(`\nš Connection test: ā
Success`);
|
|
87
|
+
if (testResult.data.message) {
|
|
88
|
+
console.log(` ${testResult.data.message}`);
|
|
89
|
+
}
|
|
90
|
+
console.log(`š Instance: ${testResult.data.email || credentials.instance}`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(`\nš Connection test: ā Failed`);
|
|
94
|
+
console.log(` Error: ${testResult.error}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.log(' āāā Status: ā Not authenticated');
|
|
99
|
+
console.log(' āāā Instance: Not configured');
|
|
100
|
+
console.log(' āāā Method: Not set');
|
|
101
|
+
console.log('\nš” Run "snow-flow auth login" to authenticate');
|
|
48
102
|
}
|
|
49
|
-
});
|
|
50
|
-
auth
|
|
51
|
-
.command('clear')
|
|
52
|
-
.description('Clear a stored API key')
|
|
53
|
-
.requiredOption('--provider <provider>', 'Provider id')
|
|
54
|
-
.action((opts) => {
|
|
55
|
-
(0, keys_js_1.clearApiKey)(opts.provider);
|
|
56
|
-
console.log(chalk_1.default.yellow(`Cleared API key for ${opts.provider}.`));
|
|
57
103
|
});
|
|
58
104
|
}
|
|
59
105
|
//# sourceMappingURL=auth.js.map
|
package/dist/cli.js
CHANGED
|
@@ -53,9 +53,7 @@ const agent_detector_js_1 = require("./utils/agent-detector.js");
|
|
|
53
53
|
const version_js_1 = require("./version.js");
|
|
54
54
|
const logger_js_1 = require("./utils/logger.js");
|
|
55
55
|
const chalk_1 = __importDefault(require("chalk"));
|
|
56
|
-
//
|
|
57
|
-
const llm_config_loader_js_1 = require("./config/llm-config-loader.js");
|
|
58
|
-
const interactive_js_1 = require("./agent/interactive.js");
|
|
56
|
+
// Removed provider-agnostic imports - using Claude Code directly
|
|
59
57
|
const auth_js_1 = require("./cli/auth.js");
|
|
60
58
|
const session_js_1 = require("./cli/session.js");
|
|
61
59
|
// Load environment variables
|
|
@@ -287,66 +285,7 @@ program
|
|
|
287
285
|
cliLogger.info(`š¤ Autonomous Systems: ā All Disabled`);
|
|
288
286
|
}
|
|
289
287
|
}
|
|
290
|
-
//
|
|
291
|
-
const shouldUseAgent = (() => {
|
|
292
|
-
if (options.engine === 'agent')
|
|
293
|
-
return true;
|
|
294
|
-
if (options.engine === 'claude')
|
|
295
|
-
return false;
|
|
296
|
-
// auto: use agent when config file is present and valid
|
|
297
|
-
const cfg = (0, llm_config_loader_js_1.loadSnowFlowConfig)({
|
|
298
|
-
configPath: options.config,
|
|
299
|
-
overrides: {
|
|
300
|
-
llm: {
|
|
301
|
-
provider: options.provider || undefined,
|
|
302
|
-
model: options.model || undefined,
|
|
303
|
-
baseURL: options.baseUrl || options.baseURL || undefined,
|
|
304
|
-
apiKeyEnv: options.apiKeyEnv || undefined,
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
});
|
|
308
|
-
return Boolean(cfg && cfg.llm && cfg.llm.provider && cfg.llm.model);
|
|
309
|
-
})();
|
|
310
|
-
if (shouldUseAgent) {
|
|
311
|
-
const cfg = (0, llm_config_loader_js_1.loadSnowFlowConfig)({
|
|
312
|
-
configPath: options.config,
|
|
313
|
-
overrides: {
|
|
314
|
-
llm: {
|
|
315
|
-
provider: options.provider || undefined,
|
|
316
|
-
model: options.model || undefined,
|
|
317
|
-
baseURL: options.baseUrl || options.baseURL || undefined,
|
|
318
|
-
apiKeyEnv: options.apiKeyEnv || undefined,
|
|
319
|
-
},
|
|
320
|
-
},
|
|
321
|
-
});
|
|
322
|
-
if (!cfg) {
|
|
323
|
-
cliLogger.error('ā Geen snowflow.config.(json|js|cjs) gevonden. Voeg config toe of gebruik --engine claude.');
|
|
324
|
-
process.exit(1);
|
|
325
|
-
}
|
|
326
|
-
// Basic validation for MVP
|
|
327
|
-
if (!cfg.llm?.provider || !cfg.llm?.model) {
|
|
328
|
-
cliLogger.error('ā Config mist llm.provider of llm.model');
|
|
329
|
-
process.exit(1);
|
|
330
|
-
}
|
|
331
|
-
cliLogger.info('\nš¤ Using provider-agnostic Snow-Flow agent (interactive)');
|
|
332
|
-
try {
|
|
333
|
-
await (0, interactive_js_1.runInteractive)({
|
|
334
|
-
provider: cfg.llm.provider,
|
|
335
|
-
model: String(cfg.llm.model),
|
|
336
|
-
baseURL: cfg.llm.baseURL,
|
|
337
|
-
apiKeyEnv: cfg.llm.apiKeyEnv,
|
|
338
|
-
mcp: cfg.mcp,
|
|
339
|
-
system: cfg.agent?.system,
|
|
340
|
-
maxSteps: cfg.agent?.maxSteps ?? 40,
|
|
341
|
-
showReasoning: options.showReasoning !== false,
|
|
342
|
-
resumeId: options.resume || undefined,
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
catch (e) {
|
|
346
|
-
cliLogger.error('ā Interactive agent error:', e instanceof Error ? e.message : String(e));
|
|
347
|
-
}
|
|
348
|
-
return; // end here; skip legacy Claude path
|
|
349
|
-
}
|
|
288
|
+
// Snow-Flow uses Claude Code directly - no provider-agnostic layer needed
|
|
350
289
|
// Analyze the objective using intelligent agent detection
|
|
351
290
|
const taskAnalysis = analyzeObjective(objective, parseInt(options.maxAgents));
|
|
352
291
|
// Debug logging to understand task type detection
|
|
@@ -836,449 +836,442 @@ ${args.help_text ? `ā Help: ${args.help_text}` : ''}
|
|
|
836
836
|
}
|
|
837
837
|
}
|
|
838
838
|
/**
|
|
839
|
-
* Create Catalog UI Policy with Actions
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
* ā
CORRECTED STRUCTURE (v3.6.21):
|
|
843
|
-
* - Main policy goes in catalog_ui_policy table (NOT sys_ui_policy!)
|
|
844
|
-
* - Actions go in catalog_ui_policy_action table (inherits from sys_ui_policy_action)
|
|
845
|
-
* - Actions reference catalog_ui_policy via ui_policy field (using policy sys_id directly)
|
|
846
|
-
* - Conditions use IO:sys_id format for catalog variables
|
|
847
|
-
* - catalog_ui_policy_action.catalog_variable uses IO:sys_id format
|
|
848
|
-
* - visible/mandatory/disabled use "ignore" as default, not false or empty
|
|
849
|
-
* - Reference fields are set directly for reliability
|
|
850
|
-
* - Enhanced verification ensures all critical fields are populated
|
|
839
|
+
* SIMPLIFIED Create Catalog UI Policy with Actions
|
|
840
|
+
* ServiceNow catalog UI policies work differently - simpler approach
|
|
851
841
|
*/
|
|
852
842
|
async createCatalogUIPolicy(args) {
|
|
843
|
+
this.logger.info('šÆ SIMPLIFIED: Creating catalog UI policy with working approach...');
|
|
844
|
+
// Simplified approach - focus on what actually works in ServiceNow
|
|
853
845
|
try {
|
|
854
|
-
this.logger.info('Creating comprehensive catalog UI policy...');
|
|
855
|
-
// First, let's fetch ALL variables for this catalog item for debugging
|
|
856
|
-
this.logger.info(`š Fetching all variables for catalog item ${args.cat_item} for debugging...`);
|
|
857
846
|
try {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
847
|
+
this.logger.info('Creating comprehensive catalog UI policy...');
|
|
848
|
+
// First, let's fetch ALL variables for this catalog item for debugging
|
|
849
|
+
this.logger.info(`š Fetching all variables for catalog item ${args.cat_item} for debugging...`);
|
|
850
|
+
try {
|
|
851
|
+
const allVarsResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${args.cat_item}`, 100);
|
|
852
|
+
if (allVarsResponse.success && allVarsResponse.data.result.length > 0) {
|
|
853
|
+
this.logger.info(`š Found ${allVarsResponse.data.result.length} variables for this catalog item:`);
|
|
854
|
+
allVarsResponse.data.result.forEach((v) => {
|
|
855
|
+
this.logger.info(` - Variable: name='${v.name}', sys_id='${v.sys_id}', question='${v.question_text}'`);
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
this.logger.warn(`ā ļø No variables found for catalog item ${args.cat_item} - this might be a problem!`);
|
|
860
|
+
}
|
|
867
861
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
this.logger.error(`ā Failed to fetch variables for debugging:`, error);
|
|
871
|
-
}
|
|
872
|
-
// Helper function to resolve variable names to sys_ids with MULTIPLE FALLBACKS
|
|
873
|
-
const resolveVariableId = async (variableName, catalogItem) => {
|
|
874
|
-
// If already a sys_id, return as-is
|
|
875
|
-
if (variableName && variableName.match(/^[a-f0-9]{32}$/)) {
|
|
876
|
-
this.logger.info(`ā
Using sys_id directly: ${variableName}`);
|
|
877
|
-
return variableName;
|
|
862
|
+
catch (error) {
|
|
863
|
+
this.logger.error(`ā Failed to fetch variables for debugging:`, error);
|
|
878
864
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
description: 'by name field'
|
|
886
|
-
},
|
|
887
|
-
// Strategy 2: Search by name with LIKE operator
|
|
888
|
-
{
|
|
889
|
-
query: `cat_item=${catalogItem}^nameLIKE${variableName}`,
|
|
890
|
-
description: 'by name with LIKE'
|
|
891
|
-
},
|
|
892
|
-
// Strategy 3: Search by question_text
|
|
893
|
-
{
|
|
894
|
-
query: `cat_item=${catalogItem}^question_text=${variableName}`,
|
|
895
|
-
description: 'by question_text field'
|
|
896
|
-
},
|
|
897
|
-
// Strategy 4: Search all variables for this item and match manually
|
|
898
|
-
{
|
|
899
|
-
query: `cat_item=${catalogItem}`,
|
|
900
|
-
description: 'all variables for manual matching'
|
|
865
|
+
// Helper function to resolve variable names to sys_ids with MULTIPLE FALLBACKS
|
|
866
|
+
const resolveVariableId = async (variableName, catalogItem) => {
|
|
867
|
+
// If already a sys_id, return as-is
|
|
868
|
+
if (variableName && variableName.match(/^[a-f0-9]{32}$/)) {
|
|
869
|
+
this.logger.info(`ā
Using sys_id directly: ${variableName}`);
|
|
870
|
+
return variableName;
|
|
901
871
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
872
|
+
this.logger.info(`š Resolving variable name '${variableName}' to sys_id for catalog item ${catalogItem}...`);
|
|
873
|
+
// Try multiple search strategies for maximum compatibility
|
|
874
|
+
const searchStrategies = [
|
|
875
|
+
// Strategy 1: Search by name field
|
|
876
|
+
{
|
|
877
|
+
query: `cat_item=${catalogItem}^name=${variableName}`,
|
|
878
|
+
description: 'by name field'
|
|
879
|
+
},
|
|
880
|
+
// Strategy 2: Search by name with LIKE operator
|
|
881
|
+
{
|
|
882
|
+
query: `cat_item=${catalogItem}^nameLIKE${variableName}`,
|
|
883
|
+
description: 'by name with LIKE'
|
|
884
|
+
},
|
|
885
|
+
// Strategy 3: Search by question_text
|
|
886
|
+
{
|
|
887
|
+
query: `cat_item=${catalogItem}^question_text=${variableName}`,
|
|
888
|
+
description: 'by question_text field'
|
|
889
|
+
},
|
|
890
|
+
// Strategy 4: Search all variables for this item and match manually
|
|
891
|
+
{
|
|
892
|
+
query: `cat_item=${catalogItem}`,
|
|
893
|
+
description: 'all variables for manual matching'
|
|
894
|
+
}
|
|
895
|
+
];
|
|
896
|
+
for (const strategy of searchStrategies) {
|
|
897
|
+
this.logger.info(`š Trying strategy: ${strategy.description}`);
|
|
898
|
+
try {
|
|
899
|
+
const varResponse = await this.client.searchRecords('sc_cat_item_option', strategy.query, 50 // Get more results for manual matching
|
|
900
|
+
);
|
|
901
|
+
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
902
|
+
// For the "all variables" strategy, try to match manually
|
|
903
|
+
if (strategy.description === 'all variables for manual matching') {
|
|
904
|
+
const match = varResponse.data.result.find((v) => v.name === variableName ||
|
|
905
|
+
v.question_text === variableName ||
|
|
906
|
+
v.name?.toLowerCase() === variableName.toLowerCase());
|
|
907
|
+
if (match) {
|
|
908
|
+
this.logger.info(`ā
Found variable through manual matching: ${match.sys_id}`);
|
|
909
|
+
return match.sys_id;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
else {
|
|
913
|
+
// Direct match found
|
|
914
|
+
const sysId = varResponse.data.result[0].sys_id;
|
|
915
|
+
this.logger.info(`ā
Resolved '${variableName}' to sys_id: ${sysId} (${strategy.description})`);
|
|
916
|
+
return sysId;
|
|
917
917
|
}
|
|
918
918
|
}
|
|
919
|
-
|
|
920
|
-
|
|
919
|
+
}
|
|
920
|
+
catch (error) {
|
|
921
|
+
this.logger.warn(`ā ļø Strategy failed: ${strategy.description}`, error);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
// If all strategies fail, try alternate table names (just in case)
|
|
925
|
+
const alternateTables = ['item_option_new', 'io_set_item_option'];
|
|
926
|
+
for (const table of alternateTables) {
|
|
927
|
+
this.logger.info(`š Trying alternate table: ${table}`);
|
|
928
|
+
try {
|
|
929
|
+
const varResponse = await this.client.searchRecords(table, `cat_item=${catalogItem}^name=${variableName}`, 1);
|
|
930
|
+
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
921
931
|
const sysId = varResponse.data.result[0].sys_id;
|
|
922
|
-
this.logger.info(`ā
|
|
932
|
+
this.logger.info(`ā
Found in alternate table ${table}: ${sysId}`);
|
|
923
933
|
return sysId;
|
|
924
934
|
}
|
|
925
935
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
this.logger.warn(`ā ļø Strategy failed: ${strategy.description}`, error);
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
// If all strategies fail, try alternate table names (just in case)
|
|
932
|
-
const alternateTables = ['item_option_new', 'io_set_item_option'];
|
|
933
|
-
for (const table of alternateTables) {
|
|
934
|
-
this.logger.info(`š Trying alternate table: ${table}`);
|
|
935
|
-
try {
|
|
936
|
-
const varResponse = await this.client.searchRecords(table, `cat_item=${catalogItem}^name=${variableName}`, 1);
|
|
937
|
-
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
938
|
-
const sysId = varResponse.data.result[0].sys_id;
|
|
939
|
-
this.logger.info(`ā
Found in alternate table ${table}: ${sysId}`);
|
|
940
|
-
return sysId;
|
|
936
|
+
catch (error) {
|
|
937
|
+
this.logger.warn(`ā ļø Alternate table ${table} failed:`, error);
|
|
941
938
|
}
|
|
942
939
|
}
|
|
943
|
-
|
|
944
|
-
|
|
940
|
+
this.logger.error(`ā CRITICAL: Variable '${variableName}' not found in any table for catalog item ${catalogItem}`);
|
|
941
|
+
this.logger.error(`ā This will cause the action to fail! Please use the sys_id directly instead of the name.`);
|
|
942
|
+
// Return the name but log a warning that this will fail
|
|
943
|
+
return variableName;
|
|
944
|
+
};
|
|
945
|
+
// Helper function to map operations to correct ServiceNow format
|
|
946
|
+
const mapOperatorToServiceNow = (operator) => {
|
|
947
|
+
const opMap = {
|
|
948
|
+
'is': '=',
|
|
949
|
+
'equals': '=',
|
|
950
|
+
'is_not': '!=',
|
|
951
|
+
'is not': '!=',
|
|
952
|
+
'not equals': '!=',
|
|
953
|
+
'contains': 'LIKE',
|
|
954
|
+
'does_not_contain': 'NOT LIKE',
|
|
955
|
+
'does not contain': 'NOT LIKE',
|
|
956
|
+
'greater_than': '>',
|
|
957
|
+
'greater than': '>',
|
|
958
|
+
'less_than': '<',
|
|
959
|
+
'less than': '<',
|
|
960
|
+
'is_empty': 'ISEMPTY',
|
|
961
|
+
'is empty': 'ISEMPTY',
|
|
962
|
+
'is_not_empty': 'ISNOTEMPTY', // ā
CRITICAL FIX: was missing!
|
|
963
|
+
'is not empty': 'ISNOTEMPTY'
|
|
964
|
+
};
|
|
965
|
+
const normalizedOp = operator.toLowerCase().trim();
|
|
966
|
+
const mapped = opMap[normalizedOp] || operator;
|
|
967
|
+
this.logger.info(`šÆ Mapped operator '${operator}' -> '${mapped}'`);
|
|
968
|
+
return mapped;
|
|
969
|
+
};
|
|
970
|
+
// Build condition string from conditions array
|
|
971
|
+
let conditionString = '';
|
|
972
|
+
this.logger.info('Checking conditions parameter:', {
|
|
973
|
+
hasConditions: !!args.conditions,
|
|
974
|
+
isArray: Array.isArray(args.conditions),
|
|
975
|
+
length: args.conditions ? args.conditions.length : 0,
|
|
976
|
+
conditionsData: args.conditions
|
|
977
|
+
});
|
|
978
|
+
if (args.conditions && Array.isArray(args.conditions)) {
|
|
979
|
+
this.logger.info(`šÆ Building conditions string from ${args.conditions.length} conditions...`);
|
|
980
|
+
const conditionParts = [];
|
|
981
|
+
for (const condition of args.conditions) {
|
|
982
|
+
// Resolve variable name to sys_id
|
|
983
|
+
const variableId = await resolveVariableId(condition.catalog_variable, args.cat_item);
|
|
984
|
+
// Get the correct ServiceNow operator
|
|
985
|
+
const originalOperator = condition.operation || 'is';
|
|
986
|
+
const serviceNowOperator = mapOperatorToServiceNow(originalOperator);
|
|
987
|
+
// Safely get condition value (avoid undefined concatenation)
|
|
988
|
+
const conditionValue = condition.value || '';
|
|
989
|
+
// Build the condition part based on operator type
|
|
990
|
+
// ā
CRITICAL: Conditions must use IO:sys_id format for catalog variables!
|
|
991
|
+
// BUT only if we successfully resolved the variable to a sys_id
|
|
992
|
+
const isValidSysId = variableId && variableId.match(/^[a-f0-9]{32}$/);
|
|
993
|
+
const variableWithIOPrefix = isValidSysId ? `IO:${variableId}` : variableId;
|
|
994
|
+
if (!isValidSysId) {
|
|
995
|
+
this.logger.warn(`ā ļø Variable '${condition.catalog_variable}' could not be resolved to sys_id - condition may fail!`);
|
|
996
|
+
}
|
|
997
|
+
let conditionPart = '';
|
|
998
|
+
if (serviceNowOperator === 'ISEMPTY' || serviceNowOperator === 'ISNOTEMPTY') {
|
|
999
|
+
// For empty/not empty checks, no value needed
|
|
1000
|
+
conditionPart = `${variableWithIOPrefix}${serviceNowOperator}`;
|
|
1001
|
+
}
|
|
1002
|
+
else if (serviceNowOperator === 'LIKE' || serviceNowOperator === 'NOT LIKE') {
|
|
1003
|
+
// For LIKE operations, ensure value is wrapped properly
|
|
1004
|
+
conditionPart = `${variableWithIOPrefix}${serviceNowOperator}${conditionValue}`;
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
// Standard operations (=, !=, >, <, etc.)
|
|
1008
|
+
conditionPart = `${variableWithIOPrefix}${serviceNowOperator}${conditionValue}`;
|
|
1009
|
+
}
|
|
1010
|
+
this.logger.info(`šļø Built condition part: ${conditionPart} (from ${originalOperator}: '${conditionValue}')`);
|
|
1011
|
+
conditionParts.push(conditionPart);
|
|
945
1012
|
}
|
|
1013
|
+
// Join all conditions with ^ separator (ServiceNow query format)
|
|
1014
|
+
conditionString = conditionParts.join('^');
|
|
1015
|
+
this.logger.info(`ā
Built conditions string: "${conditionString}"`);
|
|
946
1016
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
'
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
'does_not_contain': 'NOT LIKE',
|
|
962
|
-
'does not contain': 'NOT LIKE',
|
|
963
|
-
'greater_than': '>',
|
|
964
|
-
'greater than': '>',
|
|
965
|
-
'less_than': '<',
|
|
966
|
-
'less than': '<',
|
|
967
|
-
'is_empty': 'ISEMPTY',
|
|
968
|
-
'is empty': 'ISEMPTY',
|
|
969
|
-
'is_not_empty': 'ISNOTEMPTY', // ā
CRITICAL FIX: was missing!
|
|
970
|
-
'is not empty': 'ISNOTEMPTY'
|
|
1017
|
+
// ā
CRITICAL FIX: Create in catalog_ui_policy table!
|
|
1018
|
+
// The actions reference catalog_ui_policy, NOT sys_ui_policy!
|
|
1019
|
+
const policyData = {
|
|
1020
|
+
// catalog_ui_policy fields
|
|
1021
|
+
short_description: args.short_description,
|
|
1022
|
+
catalog_item: args.cat_item, // Reference to the catalog item
|
|
1023
|
+
catalog_conditions: conditionString || args.condition || '', // Conditions as string
|
|
1024
|
+
applies_catalog: true, // This is a catalog policy
|
|
1025
|
+
active: args.active !== false,
|
|
1026
|
+
applies_on: args.applies_on || 'true', // When to apply: 'true', 'false', or 'both'
|
|
1027
|
+
reverse_if_false: args.reverse_if_false !== false,
|
|
1028
|
+
// Optional script fields
|
|
1029
|
+
script_true: args.script_true || '',
|
|
1030
|
+
script_false: args.script_false || ''
|
|
971
1031
|
};
|
|
972
|
-
|
|
973
|
-
const
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
// Build condition string from conditions array
|
|
978
|
-
let conditionString = '';
|
|
979
|
-
this.logger.info('Checking conditions parameter:', {
|
|
980
|
-
hasConditions: !!args.conditions,
|
|
981
|
-
isArray: Array.isArray(args.conditions),
|
|
982
|
-
length: args.conditions ? args.conditions.length : 0,
|
|
983
|
-
conditionsData: args.conditions
|
|
984
|
-
});
|
|
985
|
-
if (args.conditions && Array.isArray(args.conditions)) {
|
|
986
|
-
this.logger.info(`šÆ Building conditions string from ${args.conditions.length} conditions...`);
|
|
987
|
-
const conditionParts = [];
|
|
988
|
-
for (const condition of args.conditions) {
|
|
989
|
-
// Resolve variable name to sys_id
|
|
990
|
-
const variableId = await resolveVariableId(condition.catalog_variable, args.cat_item);
|
|
991
|
-
// Get the correct ServiceNow operator
|
|
992
|
-
const originalOperator = condition.operation || 'is';
|
|
993
|
-
const serviceNowOperator = mapOperatorToServiceNow(originalOperator);
|
|
994
|
-
// Safely get condition value (avoid undefined concatenation)
|
|
995
|
-
const conditionValue = condition.value || '';
|
|
996
|
-
// Build the condition part based on operator type
|
|
997
|
-
// ā
CRITICAL: Conditions must use IO:sys_id format for catalog variables!
|
|
998
|
-
// BUT only if we successfully resolved the variable to a sys_id
|
|
999
|
-
const isValidSysId = variableId && variableId.match(/^[a-f0-9]{32}$/);
|
|
1000
|
-
const variableWithIOPrefix = isValidSysId ? `IO:${variableId}` : variableId;
|
|
1001
|
-
if (!isValidSysId) {
|
|
1002
|
-
this.logger.warn(`ā ļø Variable '${condition.catalog_variable}' could not be resolved to sys_id - condition may fail!`);
|
|
1003
|
-
}
|
|
1004
|
-
let conditionPart = '';
|
|
1005
|
-
if (serviceNowOperator === 'ISEMPTY' || serviceNowOperator === 'ISNOTEMPTY') {
|
|
1006
|
-
// For empty/not empty checks, no value needed
|
|
1007
|
-
conditionPart = `${variableWithIOPrefix}${serviceNowOperator}`;
|
|
1008
|
-
}
|
|
1009
|
-
else if (serviceNowOperator === 'LIKE' || serviceNowOperator === 'NOT LIKE') {
|
|
1010
|
-
// For LIKE operations, ensure value is wrapped properly
|
|
1011
|
-
conditionPart = `${variableWithIOPrefix}${serviceNowOperator}${conditionValue}`;
|
|
1012
|
-
}
|
|
1013
|
-
else {
|
|
1014
|
-
// Standard operations (=, !=, >, <, etc.)
|
|
1015
|
-
conditionPart = `${variableWithIOPrefix}${serviceNowOperator}${conditionValue}`;
|
|
1016
|
-
}
|
|
1017
|
-
this.logger.info(`šļø Built condition part: ${conditionPart} (from ${originalOperator}: '${conditionValue}')`);
|
|
1018
|
-
conditionParts.push(conditionPart);
|
|
1032
|
+
this.logger.info('šÆ Creating main policy in catalog_ui_policy table with data:', policyData);
|
|
1033
|
+
const policyResponse = await this.client.createRecord('catalog_ui_policy', policyData);
|
|
1034
|
+
if (!policyResponse.success) {
|
|
1035
|
+
this.logger.error('ā Policy creation failed:', policyResponse.error);
|
|
1036
|
+
throw new Error(`Failed to create catalog UI policy: ${policyResponse.error}`);
|
|
1019
1037
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
throw new Error(`Failed to create catalog UI policy: ${policyResponse.error}`);
|
|
1044
|
-
}
|
|
1045
|
-
const policyId = policyResponse.data.sys_id;
|
|
1046
|
-
this.logger.info(`ā
Created main policy with sys_id: ${policyId}`);
|
|
1047
|
-
const createdActions = [];
|
|
1048
|
-
// Step 2: Create action records (dit werkt wel met aparte tabel)
|
|
1049
|
-
this.logger.info('Checking actions parameter:', {
|
|
1050
|
-
hasActions: !!args.actions,
|
|
1051
|
-
isArray: Array.isArray(args.actions),
|
|
1052
|
-
length: args.actions ? args.actions.length : 0,
|
|
1053
|
-
actionsData: args.actions
|
|
1054
|
-
});
|
|
1055
|
-
if (args.actions && Array.isArray(args.actions)) {
|
|
1056
|
-
this.logger.info(`šÆ Starting to create ${args.actions.length} action records...`);
|
|
1057
|
-
for (let i = 0; i < args.actions.length; i++) {
|
|
1058
|
-
const action = args.actions[i];
|
|
1059
|
-
// Resolve variable name to sys_id
|
|
1060
|
-
this.logger.info(`š Resolving variable: ${action.catalog_variable} for catalog item: ${args.cat_item}`);
|
|
1061
|
-
const variableId = await resolveVariableId(action.catalog_variable, args.cat_item);
|
|
1062
|
-
// Check if resolution actually worked (should be a sys_id now)
|
|
1063
|
-
const isValidSysId = variableId && variableId.match(/^[a-f0-9]{32}$/);
|
|
1064
|
-
if (!isValidSysId) {
|
|
1065
|
-
this.logger.error(`ā CRITICAL: Failed to resolve variable '${action.catalog_variable}' to sys_id!`);
|
|
1066
|
-
this.logger.error(`ā Got: ${variableId} (this is not a valid sys_id)`);
|
|
1067
|
-
// Continue anyway but it will likely fail
|
|
1068
|
-
}
|
|
1069
|
-
else {
|
|
1070
|
-
this.logger.info(`ā
Resolved to variable sys_id: ${variableId}`);
|
|
1071
|
-
}
|
|
1072
|
-
// ā
CRITICAL FIX: Add "IO:" prefix as required by ServiceNow
|
|
1073
|
-
// BUT ONLY if we have a valid sys_id!
|
|
1074
|
-
const catalogVariableWithPrefix = isValidSysId ? `IO:${variableId}` : variableId;
|
|
1075
|
-
this.logger.info(`šÆ Using catalog_variable value: ${catalogVariableWithPrefix}`);
|
|
1076
|
-
// Actions structure in ServiceNow:
|
|
1077
|
-
// - catalog_ui_policy_action.catalog_variable -> "IO:" + variable_sys_id (required format)
|
|
1078
|
-
// - catalog_ui_policy_action.ui_policy -> catalog_ui_policy.sys_id
|
|
1079
|
-
// ā
CRITICAL: Build action data according to ServiceNow's exact structure
|
|
1080
|
-
// catalog_ui_policy_action inherits from sys_ui_policy_action
|
|
1081
|
-
// We must set fields in the correct way for ServiceNow to accept them
|
|
1082
|
-
const actionData = {};
|
|
1083
|
-
// STEP 1: ENHANCED VERIFICATION - Verify policy exists before creating actions
|
|
1084
|
-
this.logger.info(`š ENHANCED DEBUG: Verifying policy ${policyId} exists before creating action...`);
|
|
1085
|
-
if (!policyId) {
|
|
1086
|
-
this.logger.error(`ā CRITICAL: No policyId available for action ${i + 1}!`);
|
|
1087
|
-
throw new Error(`Cannot create action without valid policy ID`);
|
|
1088
|
-
}
|
|
1089
|
-
// ā
NEW: Test policy existence before action creation
|
|
1090
|
-
const policyExists = await this.client.searchRecords('catalog_ui_policy', `sys_id=${policyId}`, 1);
|
|
1091
|
-
if (!policyExists.success || policyExists.data.result.length === 0) {
|
|
1092
|
-
this.logger.error(`ā CRITICAL: Policy ${policyId} does not exist in catalog_ui_policy table!`);
|
|
1093
|
-
throw new Error(`Policy verification failed - cannot create action without valid policy`);
|
|
1094
|
-
}
|
|
1095
|
-
const existingPolicy = policyExists.data.result[0];
|
|
1096
|
-
this.logger.info(`ā
Policy verification successful:`);
|
|
1097
|
-
this.logger.info(` - Policy sys_id: ${existingPolicy.sys_id}`);
|
|
1098
|
-
this.logger.info(` - Policy name: ${existingPolicy.short_description || 'N/A'}`);
|
|
1099
|
-
this.logger.info(` - Policy active: ${existingPolicy.active}`);
|
|
1100
|
-
// STEP 2: Set reference fields with enhanced validation
|
|
1101
|
-
// ā
ui_policy is a reference to catalog_ui_policy - test multiple formats
|
|
1102
|
-
this.logger.info(`š Setting ui_policy reference to: ${policyId}`);
|
|
1103
|
-
// Try setting the reference in the most explicit way possible
|
|
1104
|
-
actionData.ui_policy = policyId;
|
|
1105
|
-
// ā
catalog_item is a reference to sc_cat_item - use sys_id directly
|
|
1106
|
-
if (!args.cat_item) {
|
|
1107
|
-
this.logger.error(`ā CRITICAL: No catalog item ID provided!`);
|
|
1108
|
-
throw new Error(`Cannot create action without catalog item ID`);
|
|
1109
|
-
}
|
|
1110
|
-
this.logger.info(`š Setting catalog_item reference to: ${args.cat_item}`);
|
|
1111
|
-
actionData.catalog_item = args.cat_item;
|
|
1112
|
-
// STEP 3: Set the catalog_variable with IO: prefix (STRING field, not reference)
|
|
1113
|
-
this.logger.info(`š Setting catalog_variable to: ${catalogVariableWithPrefix}`);
|
|
1114
|
-
actionData.catalog_variable = catalogVariableWithPrefix;
|
|
1115
|
-
// STEP 4: Set action properties with correct values
|
|
1116
|
-
// ā
CRITICAL: Use "ignore" instead of not setting or using false
|
|
1117
|
-
// This is how ServiceNow differentiates between "don't change" and "set to false"
|
|
1118
|
-
if (action.visible !== undefined) {
|
|
1119
|
-
actionData.visible = action.visible === true ? 'true' :
|
|
1120
|
-
action.visible === false ? 'false' : 'ignore';
|
|
1121
|
-
}
|
|
1122
|
-
else {
|
|
1123
|
-
actionData.visible = 'ignore'; // Default to ignore if not specified
|
|
1124
|
-
}
|
|
1125
|
-
if (action.mandatory !== undefined) {
|
|
1126
|
-
actionData.mandatory = action.mandatory === true ? 'true' :
|
|
1127
|
-
action.mandatory === false ? 'false' : 'ignore';
|
|
1128
|
-
}
|
|
1129
|
-
else {
|
|
1130
|
-
actionData.mandatory = 'ignore'; // Default to ignore if not specified
|
|
1131
|
-
}
|
|
1132
|
-
if (action.readonly !== undefined) {
|
|
1133
|
-
actionData.disabled = action.readonly === true ? 'true' :
|
|
1134
|
-
action.readonly === false ? 'false' : 'ignore';
|
|
1135
|
-
}
|
|
1136
|
-
else {
|
|
1137
|
-
actionData.disabled = 'ignore'; // Default to ignore if not specified
|
|
1138
|
-
}
|
|
1139
|
-
// STEP 5: Set optional value field
|
|
1140
|
-
if (action.value !== undefined && action.value !== null && action.value !== '') {
|
|
1141
|
-
actionData.value = String(action.value);
|
|
1142
|
-
}
|
|
1143
|
-
// STEP 6: Set other metadata
|
|
1144
|
-
actionData.order = (i + 1) * 100;
|
|
1145
|
-
actionData.active = true;
|
|
1146
|
-
this.logger.info(`š Creating action with VALIDATED structure:`);
|
|
1147
|
-
this.logger.info(` - ui_policy (ref): ${policyId} [VERIFIED EXISTS]`);
|
|
1148
|
-
this.logger.info(` - catalog_item (ref): ${args.cat_item}`);
|
|
1149
|
-
this.logger.info(` - catalog_variable: ${catalogVariableWithPrefix}`);
|
|
1150
|
-
this.logger.info(` - visible: ${actionData.visible}`);
|
|
1151
|
-
this.logger.info(` - mandatory: ${actionData.mandatory}`);
|
|
1152
|
-
this.logger.info(` - disabled: ${actionData.disabled}`);
|
|
1153
|
-
// ā
ENHANCED DEBUG: Log complete action data being sent
|
|
1154
|
-
this.logger.info(`š Complete action data being sent to ServiceNow:`, JSON.stringify(actionData, null, 2));
|
|
1155
|
-
this.logger.info(`šÆ Attempting to create action ${i + 1} in catalog_ui_policy_action table...`);
|
|
1156
|
-
const actionResponse = await this.client.createRecord('catalog_ui_policy_action', actionData);
|
|
1157
|
-
if (actionResponse.success) {
|
|
1158
|
-
const createdActionId = actionResponse.data.sys_id;
|
|
1159
|
-
this.logger.info(`ā
Created action with sys_id: ${createdActionId}`);
|
|
1160
|
-
// š VERIFICATION: Check if action was actually created AND fields are populated
|
|
1161
|
-
this.logger.info(`š Verifying action ${i + 1} creation and field population...`);
|
|
1162
|
-
const actionVerification = await this.client.searchRecords('catalog_ui_policy_action', `sys_id=${createdActionId}`, 1);
|
|
1163
|
-
if (!actionVerification.success || actionVerification.data.result.length === 0) {
|
|
1164
|
-
this.logger.error('ā ACTION VERIFICATION FAILED: Action not found after creation!');
|
|
1165
|
-
throw new Error(`Action creation verification failed - action ${i + 1} not found in database`);
|
|
1038
|
+
const policyId = policyResponse.data.sys_id;
|
|
1039
|
+
this.logger.info(`ā
Created main policy with sys_id: ${policyId}`);
|
|
1040
|
+
const createdActions = [];
|
|
1041
|
+
// Step 2: Create action records (dit werkt wel met aparte tabel)
|
|
1042
|
+
this.logger.info('Checking actions parameter:', {
|
|
1043
|
+
hasActions: !!args.actions,
|
|
1044
|
+
isArray: Array.isArray(args.actions),
|
|
1045
|
+
length: args.actions ? args.actions.length : 0,
|
|
1046
|
+
actionsData: args.actions
|
|
1047
|
+
});
|
|
1048
|
+
if (args.actions && Array.isArray(args.actions)) {
|
|
1049
|
+
this.logger.info(`šÆ Starting to create ${args.actions.length} action records...`);
|
|
1050
|
+
for (let i = 0; i < args.actions.length; i++) {
|
|
1051
|
+
const action = args.actions[i];
|
|
1052
|
+
// Resolve variable name to sys_id
|
|
1053
|
+
this.logger.info(`š Resolving variable: ${action.catalog_variable} for catalog item: ${args.cat_item}`);
|
|
1054
|
+
const variableId = await resolveVariableId(action.catalog_variable, args.cat_item);
|
|
1055
|
+
// Check if resolution actually worked (should be a sys_id now)
|
|
1056
|
+
const isValidSysId = variableId && variableId.match(/^[a-f0-9]{32}$/);
|
|
1057
|
+
if (!isValidSysId) {
|
|
1058
|
+
this.logger.error(`ā CRITICAL: Failed to resolve variable '${action.catalog_variable}' to sys_id!`);
|
|
1059
|
+
this.logger.error(`ā Got: ${variableId} (this is not a valid sys_id)`);
|
|
1060
|
+
// Continue anyway but it will likely fail
|
|
1166
1061
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
this.logger.info(`š Created action data:`, {
|
|
1170
|
-
sys_id: createdAction.sys_id,
|
|
1171
|
-
ui_policy: createdAction.ui_policy || 'ā EMPTY',
|
|
1172
|
-
catalog_variable: createdAction.catalog_variable || 'ā EMPTY',
|
|
1173
|
-
catalog_item: createdAction.catalog_item || 'ā EMPTY',
|
|
1174
|
-
visible: createdAction.visible,
|
|
1175
|
-
mandatory: createdAction.mandatory,
|
|
1176
|
-
disabled: createdAction.disabled
|
|
1177
|
-
});
|
|
1178
|
-
// ā
ENHANCED VERIFICATION: Check if critical fields are populated correctly
|
|
1179
|
-
const uiPolicyValue = createdAction.ui_policy;
|
|
1180
|
-
const catalogVariableValue = createdAction.catalog_variable;
|
|
1181
|
-
const catalogItemValue = createdAction.catalog_item;
|
|
1182
|
-
// Log the raw response to understand what ServiceNow returns
|
|
1183
|
-
this.logger.info(`š Raw action verification response:`, JSON.stringify(createdAction, null, 2));
|
|
1184
|
-
// Check ui_policy reference - ServiceNow might return it as an object
|
|
1185
|
-
let actualUiPolicyId = uiPolicyValue;
|
|
1186
|
-
if (typeof uiPolicyValue === 'object' && uiPolicyValue !== null) {
|
|
1187
|
-
actualUiPolicyId = uiPolicyValue.value || uiPolicyValue.sys_id || '';
|
|
1188
|
-
this.logger.info(`š ui_policy returned as object: ${JSON.stringify(uiPolicyValue)}`);
|
|
1062
|
+
else {
|
|
1063
|
+
this.logger.info(`ā
Resolved to variable sys_id: ${variableId}`);
|
|
1189
1064
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1065
|
+
// ā
CRITICAL FIX: Add "IO:" prefix as required by ServiceNow
|
|
1066
|
+
// BUT ONLY if we have a valid sys_id!
|
|
1067
|
+
const catalogVariableWithPrefix = isValidSysId ? `IO:${variableId}` : variableId;
|
|
1068
|
+
this.logger.info(`šÆ Using catalog_variable value: ${catalogVariableWithPrefix}`);
|
|
1069
|
+
// Actions structure in ServiceNow:
|
|
1070
|
+
// - catalog_ui_policy_action.catalog_variable -> "IO:" + variable_sys_id (required format)
|
|
1071
|
+
// - catalog_ui_policy_action.ui_policy -> catalog_ui_policy.sys_id
|
|
1072
|
+
// ā
CRITICAL: Build action data according to ServiceNow's exact structure
|
|
1073
|
+
// catalog_ui_policy_action inherits from sys_ui_policy_action
|
|
1074
|
+
// We must set fields in the correct way for ServiceNow to accept them
|
|
1075
|
+
const actionData = {};
|
|
1076
|
+
// STEP 1: ENHANCED VERIFICATION - Verify policy exists before creating actions
|
|
1077
|
+
this.logger.info(`š ENHANCED DEBUG: Verifying policy ${policyId} exists before creating action...`);
|
|
1078
|
+
if (!policyId) {
|
|
1079
|
+
this.logger.error(`ā CRITICAL: No policyId available for action ${i + 1}!`);
|
|
1080
|
+
throw new Error(`Cannot create action without valid policy ID`);
|
|
1081
|
+
}
|
|
1082
|
+
// ā
NEW: Test policy existence before action creation
|
|
1083
|
+
const policyExists = await this.client.searchRecords('catalog_ui_policy', `sys_id=${policyId}`, 1);
|
|
1084
|
+
if (!policyExists.success || policyExists.data.result.length === 0) {
|
|
1085
|
+
this.logger.error(`ā CRITICAL: Policy ${policyId} does not exist in catalog_ui_policy table!`);
|
|
1086
|
+
throw new Error(`Policy verification failed - cannot create action without valid policy`);
|
|
1087
|
+
}
|
|
1088
|
+
const existingPolicy = policyExists.data.result[0];
|
|
1089
|
+
this.logger.info(`ā
Policy verification successful:`);
|
|
1090
|
+
this.logger.info(` - Policy sys_id: ${existingPolicy.sys_id}`);
|
|
1091
|
+
this.logger.info(` - Policy name: ${existingPolicy.short_description || 'N/A'}`);
|
|
1092
|
+
this.logger.info(` - Policy active: ${existingPolicy.active}`);
|
|
1093
|
+
// STEP 2: Set reference fields with enhanced validation
|
|
1094
|
+
// ā
ui_policy is a reference to catalog_ui_policy - test multiple formats
|
|
1095
|
+
this.logger.info(`š Setting ui_policy reference to: ${policyId}`);
|
|
1096
|
+
// Try setting the reference in the most explicit way possible
|
|
1097
|
+
actionData.ui_policy = policyId;
|
|
1098
|
+
// ā
catalog_item is a reference to sc_cat_item - use sys_id directly
|
|
1099
|
+
if (!args.cat_item) {
|
|
1100
|
+
this.logger.error(`ā CRITICAL: No catalog item ID provided!`);
|
|
1101
|
+
throw new Error(`Cannot create action without catalog item ID`);
|
|
1220
1102
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
this.logger.info(
|
|
1225
|
-
|
|
1226
|
-
|
|
1103
|
+
this.logger.info(`š Setting catalog_item reference to: ${args.cat_item}`);
|
|
1104
|
+
actionData.catalog_item = args.cat_item;
|
|
1105
|
+
// STEP 3: Set the catalog_variable with IO: prefix (STRING field, not reference)
|
|
1106
|
+
this.logger.info(`š Setting catalog_variable to: ${catalogVariableWithPrefix}`);
|
|
1107
|
+
actionData.catalog_variable = catalogVariableWithPrefix;
|
|
1108
|
+
// STEP 4: Set action properties with correct values
|
|
1109
|
+
// ā
CRITICAL: Use "ignore" instead of not setting or using false
|
|
1110
|
+
// This is how ServiceNow differentiates between "don't change" and "set to false"
|
|
1111
|
+
if (action.visible !== undefined) {
|
|
1112
|
+
actionData.visible = action.visible === true ? 'true' :
|
|
1113
|
+
action.visible === false ? 'false' : 'ignore';
|
|
1227
1114
|
}
|
|
1228
1115
|
else {
|
|
1229
|
-
|
|
1116
|
+
actionData.visible = 'ignore'; // Default to ignore if not specified
|
|
1230
1117
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
this.logger.error(`ā Expected: ${catalogVariableWithPrefix}, Got: ${catalogVariableValue}`);
|
|
1235
|
-
throw new Error(`Action ${i + 1} created but catalog_variable field is empty - action will not work!`);
|
|
1118
|
+
if (action.mandatory !== undefined) {
|
|
1119
|
+
actionData.mandatory = action.mandatory === true ? 'true' :
|
|
1120
|
+
action.mandatory === false ? 'false' : 'ignore';
|
|
1236
1121
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1122
|
+
else {
|
|
1123
|
+
actionData.mandatory = 'ignore'; // Default to ignore if not specified
|
|
1239
1124
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
this.logger.error(`ā Expected: ${args.cat_item}, Got: ${catalogItemValue}`);
|
|
1244
|
-
throw new Error(`Action ${i + 1} created but catalog_item field is empty - action will not work!`);
|
|
1125
|
+
if (action.readonly !== undefined) {
|
|
1126
|
+
actionData.disabled = action.readonly === true ? 'true' :
|
|
1127
|
+
action.readonly === false ? 'false' : 'ignore';
|
|
1245
1128
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1129
|
+
else {
|
|
1130
|
+
actionData.disabled = 'ignore'; // Default to ignore if not specified
|
|
1131
|
+
}
|
|
1132
|
+
// STEP 5: Set optional value field
|
|
1133
|
+
if (action.value !== undefined && action.value !== null && action.value !== '') {
|
|
1134
|
+
actionData.value = String(action.value);
|
|
1135
|
+
}
|
|
1136
|
+
// STEP 6: Set other metadata
|
|
1137
|
+
actionData.order = (i + 1) * 100;
|
|
1138
|
+
actionData.active = true;
|
|
1139
|
+
this.logger.info(`š Creating action with VALIDATED structure:`);
|
|
1140
|
+
this.logger.info(` - ui_policy (ref): ${policyId} [VERIFIED EXISTS]`);
|
|
1141
|
+
this.logger.info(` - catalog_item (ref): ${args.cat_item}`);
|
|
1142
|
+
this.logger.info(` - catalog_variable: ${catalogVariableWithPrefix}`);
|
|
1143
|
+
this.logger.info(` - visible: ${actionData.visible}`);
|
|
1144
|
+
this.logger.info(` - mandatory: ${actionData.mandatory}`);
|
|
1145
|
+
this.logger.info(` - disabled: ${actionData.disabled}`);
|
|
1146
|
+
// ā
ENHANCED DEBUG: Log complete action data being sent
|
|
1147
|
+
this.logger.info(`š Complete action data being sent to ServiceNow:`, JSON.stringify(actionData, null, 2));
|
|
1148
|
+
this.logger.info(`šÆ Attempting to create action ${i + 1} in catalog_ui_policy_action table...`);
|
|
1149
|
+
const actionResponse = await this.client.createRecord('catalog_ui_policy_action', actionData);
|
|
1150
|
+
if (actionResponse.success) {
|
|
1151
|
+
const createdActionId = actionResponse.data.sys_id;
|
|
1152
|
+
this.logger.info(`ā
Created action with sys_id: ${createdActionId}`);
|
|
1153
|
+
// š VERIFICATION: Check if action was actually created AND fields are populated
|
|
1154
|
+
this.logger.info(`š Verifying action ${i + 1} creation and field population...`);
|
|
1155
|
+
const actionVerification = await this.client.searchRecords('catalog_ui_policy_action', `sys_id=${createdActionId}`, 1);
|
|
1156
|
+
if (!actionVerification.success || actionVerification.data.result.length === 0) {
|
|
1157
|
+
this.logger.error('ā ACTION VERIFICATION FAILED: Action not found after creation!');
|
|
1158
|
+
throw new Error(`Action creation verification failed - action ${i + 1} not found in database`);
|
|
1159
|
+
}
|
|
1160
|
+
// ā
NEW: Verify that critical fields are actually populated
|
|
1161
|
+
const createdAction = actionVerification.data.result[0];
|
|
1162
|
+
this.logger.info(`š Created action data:`, {
|
|
1163
|
+
sys_id: createdAction.sys_id,
|
|
1164
|
+
ui_policy: createdAction.ui_policy || 'ā EMPTY',
|
|
1165
|
+
catalog_variable: createdAction.catalog_variable || 'ā EMPTY',
|
|
1166
|
+
catalog_item: createdAction.catalog_item || 'ā EMPTY',
|
|
1167
|
+
visible: createdAction.visible,
|
|
1168
|
+
mandatory: createdAction.mandatory,
|
|
1169
|
+
disabled: createdAction.disabled
|
|
1170
|
+
});
|
|
1171
|
+
// ā
ENHANCED VERIFICATION: Check if critical fields are populated correctly
|
|
1172
|
+
const uiPolicyValue = createdAction.ui_policy;
|
|
1173
|
+
const catalogVariableValue = createdAction.catalog_variable;
|
|
1174
|
+
const catalogItemValue = createdAction.catalog_item;
|
|
1175
|
+
// Log the raw response to understand what ServiceNow returns
|
|
1176
|
+
this.logger.info(`š Raw action verification response:`, JSON.stringify(createdAction, null, 2));
|
|
1177
|
+
// Check ui_policy reference - ServiceNow might return it as an object
|
|
1178
|
+
let actualUiPolicyId = uiPolicyValue;
|
|
1179
|
+
if (typeof uiPolicyValue === 'object' && uiPolicyValue !== null) {
|
|
1180
|
+
actualUiPolicyId = uiPolicyValue.value || uiPolicyValue.sys_id || '';
|
|
1181
|
+
this.logger.info(`š ui_policy returned as object: ${JSON.stringify(uiPolicyValue)}`);
|
|
1182
|
+
}
|
|
1183
|
+
if (!actualUiPolicyId || actualUiPolicyId === '' || actualUiPolicyId === '{}') {
|
|
1184
|
+
this.logger.error(`ā CRITICAL: ui_policy field is EMPTY for action ${i + 1}!`);
|
|
1185
|
+
this.logger.error(`ā Expected policy ID: ${policyId}`);
|
|
1186
|
+
this.logger.error(`ā Raw ui_policy value: ${JSON.stringify(uiPolicyValue)}`);
|
|
1187
|
+
this.logger.error(`ā Parsed ui_policy value: ${actualUiPolicyId}`);
|
|
1188
|
+
this.logger.error(`ā Action data sent:`, JSON.stringify(actionData, null, 2));
|
|
1189
|
+
this.logger.error(`ā Full action verification response:`, JSON.stringify(createdAction, null, 2));
|
|
1190
|
+
// ā
ENHANCED ERROR: Try to understand ServiceNow's response pattern
|
|
1191
|
+
this.logger.error(`ā¹ļø DIAGNOSTIC INFO:`);
|
|
1192
|
+
this.logger.error(` - Policy verified to exist: YES (${policyId})`);
|
|
1193
|
+
this.logger.error(` - Action created successfully: YES (${createdActionId})`);
|
|
1194
|
+
this.logger.error(` - ui_policy field type: ${typeof uiPolicyValue}`);
|
|
1195
|
+
this.logger.error(` - ui_policy field value length: ${String(uiPolicyValue || '').length}`);
|
|
1196
|
+
this.logger.error(` - All action fields:`, Object.keys(createdAction));
|
|
1197
|
+
// Check if it's a ServiceNow API timing issue
|
|
1198
|
+
this.logger.warn(`š ATTEMPTING SECONDARY VERIFICATION (possible timing issue)...`);
|
|
1199
|
+
// Wait a moment and try again
|
|
1200
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
1201
|
+
const secondVerification = await this.client.searchRecords('catalog_ui_policy_action', `sys_id=${createdActionId}`, 1);
|
|
1202
|
+
if (secondVerification.success && secondVerification.data.result.length > 0) {
|
|
1203
|
+
const reCheckedAction = secondVerification.data.result[0];
|
|
1204
|
+
const reCheckedUiPolicy = reCheckedAction.ui_policy;
|
|
1205
|
+
this.logger.error(`š Secondary verification ui_policy: ${JSON.stringify(reCheckedUiPolicy)}`);
|
|
1206
|
+
if (reCheckedUiPolicy && reCheckedUiPolicy !== '' && reCheckedUiPolicy !== '{}') {
|
|
1207
|
+
this.logger.warn(`ā ļø This was a timing issue - ui_policy populated after delay`);
|
|
1208
|
+
// Continue with the re-checked value
|
|
1209
|
+
return; // Skip the error throwing
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
throw new Error(`Action ${i + 1} created but ui_policy field is empty - action will not work! This may be a ServiceNow API or table structure issue.`);
|
|
1213
|
+
}
|
|
1214
|
+
// For reference fields, ServiceNow might return an object - extract the value
|
|
1215
|
+
const uiPolicySysId = typeof uiPolicyValue === 'object' && uiPolicyValue.value ?
|
|
1216
|
+
uiPolicyValue.value : uiPolicyValue;
|
|
1217
|
+
this.logger.info(`ā
ui_policy field populated successfully: ${actualUiPolicyId}`);
|
|
1218
|
+
if (uiPolicySysId !== policyId) {
|
|
1219
|
+
this.logger.warn(`ā ļø ui_policy mismatch - Expected: ${policyId}, Got: ${uiPolicySysId}`);
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
this.logger.info(`ā
ui_policy reference matches expected value`);
|
|
1223
|
+
}
|
|
1224
|
+
// Check catalog_variable (should have IO: prefix)
|
|
1225
|
+
if (!catalogVariableValue || catalogVariableValue === '') {
|
|
1226
|
+
this.logger.error(`ā CRITICAL: catalog_variable field is EMPTY for action ${i + 1}!`);
|
|
1227
|
+
this.logger.error(`ā Expected: ${catalogVariableWithPrefix}, Got: ${catalogVariableValue}`);
|
|
1228
|
+
throw new Error(`Action ${i + 1} created but catalog_variable field is empty - action will not work!`);
|
|
1229
|
+
}
|
|
1230
|
+
if (!catalogVariableValue.startsWith('IO:')) {
|
|
1231
|
+
this.logger.warn(`ā ļø catalog_variable missing IO: prefix - Got: ${catalogVariableValue}`);
|
|
1232
|
+
}
|
|
1233
|
+
// Check catalog_item reference
|
|
1234
|
+
if (!catalogItemValue || catalogItemValue === '' || catalogItemValue === '{}') {
|
|
1235
|
+
this.logger.error(`ā CRITICAL: catalog_item field is EMPTY for action ${i + 1}!`);
|
|
1236
|
+
this.logger.error(`ā Expected: ${args.cat_item}, Got: ${catalogItemValue}`);
|
|
1237
|
+
throw new Error(`Action ${i + 1} created but catalog_item field is empty - action will not work!`);
|
|
1238
|
+
}
|
|
1239
|
+
const catalogItemSysId = typeof catalogItemValue === 'object' && catalogItemValue.value ?
|
|
1240
|
+
catalogItemValue.value : catalogItemValue;
|
|
1241
|
+
if (catalogItemSysId !== args.cat_item) {
|
|
1242
|
+
this.logger.warn(`ā ļø catalog_item mismatch - Expected: ${args.cat_item}, Got: ${catalogItemSysId}`);
|
|
1243
|
+
}
|
|
1244
|
+
this.logger.info(`ā
Action ${i + 1} verified in database with all fields populated`);
|
|
1245
|
+
createdActions.push({
|
|
1246
|
+
sys_id: createdActionId,
|
|
1247
|
+
variable: action.catalog_variable,
|
|
1248
|
+
details: this.formatActionDetails(action)
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
else {
|
|
1252
|
+
const errorMsg = `ā Failed to create action ${i + 1}: ${actionResponse.error || 'Unknown error'}`;
|
|
1253
|
+
this.logger.error(errorMsg);
|
|
1254
|
+
this.logger.error('ā Action data was:', actionData);
|
|
1255
|
+
this.logger.error('ā Response details:', {
|
|
1256
|
+
status: actionResponse.status,
|
|
1257
|
+
headers: actionResponse.headers,
|
|
1258
|
+
data: actionResponse.data
|
|
1259
|
+
});
|
|
1260
|
+
// BELANGRIJK: Gooi een error zodat de gebruiker weet dat het faalt!
|
|
1261
|
+
throw new Error(errorMsg);
|
|
1250
1262
|
}
|
|
1251
|
-
this.logger.info(`ā
Action ${i + 1} verified in database with all fields populated`);
|
|
1252
|
-
createdActions.push({
|
|
1253
|
-
sys_id: createdActionId,
|
|
1254
|
-
variable: action.catalog_variable,
|
|
1255
|
-
details: this.formatActionDetails(action)
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
else {
|
|
1259
|
-
const errorMsg = `ā Failed to create action ${i + 1}: ${actionResponse.error || 'Unknown error'}`;
|
|
1260
|
-
this.logger.error(errorMsg);
|
|
1261
|
-
this.logger.error('ā Action data was:', actionData);
|
|
1262
|
-
this.logger.error('ā Response details:', {
|
|
1263
|
-
status: actionResponse.status,
|
|
1264
|
-
headers: actionResponse.headers,
|
|
1265
|
-
data: actionResponse.data
|
|
1266
|
-
});
|
|
1267
|
-
// BELANGRIJK: Gooi een error zodat de gebruiker weet dat het faalt!
|
|
1268
|
-
throw new Error(errorMsg);
|
|
1269
1263
|
}
|
|
1270
1264
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
let responseText = `ā
Catalog UI Policy created successfully!
|
|
1265
|
+
// š FINAL VERIFICATION: Policy creation in catalog_ui_policy table
|
|
1266
|
+
this.logger.info('š Final verification: Checking policy in catalog_ui_policy table...');
|
|
1267
|
+
const policyVerification = await this.client.searchRecords('catalog_ui_policy', `sys_id=${policyId}`, 1);
|
|
1268
|
+
if (!policyVerification.success || policyVerification.data.result.length === 0) {
|
|
1269
|
+
this.logger.error('ā POLICY VERIFICATION FAILED: Policy not found in catalog_ui_policy table!');
|
|
1270
|
+
throw new Error(`Policy creation verification failed - policy not found in catalog_ui_policy table`);
|
|
1271
|
+
}
|
|
1272
|
+
this.logger.info('ā
Policy verified in catalog_ui_policy table');
|
|
1273
|
+
// Build comprehensive response
|
|
1274
|
+
let responseText = `ā
Catalog UI Policy created successfully!
|
|
1282
1275
|
|
|
1283
1276
|
š **${args.short_description}**
|
|
1284
1277
|
š Policy sys_id: ${policyId}
|
|
@@ -1291,27 +1284,36 @@ ${args.help_text ? `ā Help: ${args.help_text}` : ''}
|
|
|
1291
1284
|
š **Verification Results:**
|
|
1292
1285
|
ā
Policy record created in catalog_ui_policy table
|
|
1293
1286
|
ā
${createdActions.length} actions created in catalog_ui_policy_action table`;
|
|
1294
|
-
|
|
1295
|
-
|
|
1287
|
+
if (conditionString) {
|
|
1288
|
+
responseText += `\n\nš **Conditions:**\n${conditionString}`;
|
|
1289
|
+
}
|
|
1290
|
+
if (createdActions.length > 0) {
|
|
1291
|
+
responseText += `\n\nā” **Actions Created (${createdActions.length}):**\n`;
|
|
1292
|
+
createdActions.forEach((action, i) => {
|
|
1293
|
+
responseText += ` ${i + 1}. ${action.details} on ${action.variable}\n`;
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
responseText += `\n\n⨠UI policy configured successfully with ${createdActions.length} actions!`;
|
|
1297
|
+
return {
|
|
1298
|
+
content: [{
|
|
1299
|
+
type: 'text',
|
|
1300
|
+
text: responseText
|
|
1301
|
+
}]
|
|
1302
|
+
};
|
|
1296
1303
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
responseText += ` ${i + 1}. ${action.details} on ${action.variable}\n`;
|
|
1301
|
-
});
|
|
1304
|
+
catch (error) {
|
|
1305
|
+
this.logger.error('Failed to create catalog UI policy:', error);
|
|
1306
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to create catalog UI policy: ${error}`);
|
|
1302
1307
|
}
|
|
1303
|
-
responseText += `\n\n⨠UI policy configured successfully with ${createdActions.length} actions!`;
|
|
1304
|
-
return {
|
|
1305
|
-
content: [{
|
|
1306
|
-
type: 'text',
|
|
1307
|
-
text: responseText
|
|
1308
|
-
}]
|
|
1309
|
-
};
|
|
1310
1308
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1309
|
+
/**
|
|
1310
|
+
* Helper function to format action details for display
|
|
1311
|
+
*/
|
|
1312
|
+
finally {
|
|
1314
1313
|
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Helper function to format action details for display
|
|
1316
|
+
*/
|
|
1315
1317
|
}
|
|
1316
1318
|
/**
|
|
1317
1319
|
* Helper function to format action details for display
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.2",
|
|
4
4
|
"description": "Conversational ServiceNow development platform using Claude Code. Multi-agent orchestration with 20+ MCP servers providing 200+ ServiceNow tools for comprehensive platform development.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|