snow-flow 2.9.9 → 3.0.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/.mcp.json +13 -141
- package/.mcp.json.template +11 -25
- package/README.md +18 -0
- package/claude-flow +81 -0
- package/claude-flow.bat +18 -0
- package/claude-flow.config.json +20 -0
- package/claude-flow.ps1 +24 -0
- package/dist/agents/index.d.ts +3 -10
- package/dist/agents/index.js +10 -50
- package/dist/agents/queen-agent.d.ts +0 -2
- package/dist/agents/queen-agent.js +25 -42
- package/dist/cli.js +1 -1
- package/dist/mcp/servicenow-automation-mcp.js +10 -10
- package/dist/mcp/servicenow-deployment-mcp.js +1050 -169
- package/dist/mcp/servicenow-development-assistant-mcp.js +13 -65
- package/dist/mcp/servicenow-integration-mcp.js +10 -10
- package/dist/mcp/servicenow-machine-learning-mcp.js +15 -15
- package/dist/mcp/servicenow-operations-mcp.js +23 -23
- package/dist/mcp/servicenow-platform-development-mcp.js +9 -9
- package/dist/mcp/servicenow-reporting-analytics-mcp.js +11 -11
- package/dist/mcp/servicenow-security-compliance-mcp.js +11 -11
- package/dist/mcp/servicenow-update-set-mcp.js +9 -9
- package/dist/mcp/shared/reliable-memory-manager.d.ts +78 -0
- package/dist/mcp/shared/reliable-memory-manager.js +268 -0
- package/dist/mcp/snow-flow-mcp.js +341 -87
- package/dist/queen/agent-factory.d.ts +4 -2
- package/dist/queen/agent-factory.js +72 -25
- package/dist/services/tensorflow-ml-service.d.ts +105 -0
- package/dist/services/tensorflow-ml-service.js +456 -0
- package/dist/services/widget-deployment-service.d.ts +107 -0
- package/dist/services/widget-deployment-service.js +332 -0
- package/dist/utils/file-storage-fallback.d.ts +62 -0
- package/dist/utils/file-storage-fallback.js +289 -0
- package/dist/utils/mcp-singleton-enforcer.d.ts +36 -0
- package/dist/utils/mcp-singleton-enforcer.js +201 -0
- package/dist/utils/mcp-timeout-fix.d.ts +53 -0
- package/dist/utils/mcp-timeout-fix.js +221 -0
- package/memory/agents/README.md +31 -0
- package/memory/claude-flow-data.json +1 -1
- package/memory/sessions/README.md +1 -1
- package/package.json +4 -2
- package/src/agents/README.md +192 -0
- package/src/health/README.md +161 -0
- package/src/memory/README.md +240 -0
- package/src/queen/README.md +403 -0
- package/src/schemas/deployment.schema.json +58 -0
- package/src/schemas/flow.schema.json +79 -0
- package/src/schemas/widget.schema.json +72 -0
- package/src/templates/base/application.template.json +45 -0
- package/src/templates/base/business_rule.template.json +33 -0
- package/src/templates/base/script_include.template.json +18 -0
- package/src/templates/base/table.template.json +64 -0
- package/src/templates/base/widget.template.json +25 -0
- package/src/templates/patterns/composite.incident-management.template.json +140 -0
- package/src/templates/patterns/widget.dashboard.template.json +238 -0
- package/src/templates/patterns/widget.datatable.template.json +292 -0
- package/dist/mcp/servicenow-graph-memory-mcp.js +0 -728
- package/servicenow/widgets/openai_incident_classifier/client_controller.js +0 -284
- package/servicenow/widgets/openai_incident_classifier/server_script.js +0 -314
- package/servicenow/widgets/openai_incident_classifier/style.css +0 -354
- package/servicenow/widgets/openai_incident_classifier/template.html +0 -167
- package/servicenow/widgets/openai_incident_classifier/widget.json +0 -86
- package/test-ml-improvements.sh +0 -76
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TensorFlow.js ML Service
|
|
4
|
+
* REAL machine learning implementation for ServiceNow predictions
|
|
5
|
+
* No more fake regex matching!
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.tensorflowML = exports.TensorFlowMLService = void 0;
|
|
42
|
+
const tf = __importStar(require("@tensorflow/tfjs-node"));
|
|
43
|
+
const logger_js_1 = require("../utils/logger.js");
|
|
44
|
+
class TensorFlowMLService {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.models = new Map();
|
|
47
|
+
this.vocabularies = new Map();
|
|
48
|
+
this.MODEL_DIR = '.snow-flow/ml-models';
|
|
49
|
+
this.logger = new logger_js_1.Logger('TensorFlowMLService');
|
|
50
|
+
this.initializeModels();
|
|
51
|
+
}
|
|
52
|
+
static getInstance() {
|
|
53
|
+
if (!TensorFlowMLService.instance) {
|
|
54
|
+
TensorFlowMLService.instance = new TensorFlowMLService();
|
|
55
|
+
}
|
|
56
|
+
return TensorFlowMLService.instance;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Initialize pre-trained models
|
|
60
|
+
*/
|
|
61
|
+
async initializeModels() {
|
|
62
|
+
try {
|
|
63
|
+
// Create model directory if doesn't exist
|
|
64
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
65
|
+
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
66
|
+
const modelPath = path.join(process.cwd(), this.MODEL_DIR);
|
|
67
|
+
if (!fs.existsSync(modelPath)) {
|
|
68
|
+
fs.mkdirSync(modelPath, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
// Initialize default models if not trained yet
|
|
71
|
+
await this.createDefaultModels();
|
|
72
|
+
this.logger.info('✅ TensorFlow.js ML models initialized (REAL ML!)');
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
this.logger.error('Failed to initialize ML models:', error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Create default neural network models
|
|
80
|
+
*/
|
|
81
|
+
async createDefaultModels() {
|
|
82
|
+
// Incident Classification Model
|
|
83
|
+
if (!this.models.has('incident_classifier')) {
|
|
84
|
+
const model = tf.sequential({
|
|
85
|
+
layers: [
|
|
86
|
+
tf.layers.dense({ inputShape: [100], units: 128, activation: 'relu' }),
|
|
87
|
+
tf.layers.dropout({ rate: 0.2 }),
|
|
88
|
+
tf.layers.dense({ units: 64, activation: 'relu' }),
|
|
89
|
+
tf.layers.dropout({ rate: 0.2 }),
|
|
90
|
+
tf.layers.dense({ units: 32, activation: 'relu' }),
|
|
91
|
+
tf.layers.dense({ units: 10, activation: 'softmax' }) // 10 categories
|
|
92
|
+
]
|
|
93
|
+
});
|
|
94
|
+
model.compile({
|
|
95
|
+
optimizer: tf.train.adam(0.001),
|
|
96
|
+
loss: 'categoricalCrossentropy',
|
|
97
|
+
metrics: ['accuracy']
|
|
98
|
+
});
|
|
99
|
+
this.models.set('incident_classifier', model);
|
|
100
|
+
this.logger.info('Created incident classification neural network');
|
|
101
|
+
}
|
|
102
|
+
// Change Risk Prediction Model
|
|
103
|
+
if (!this.models.has('change_risk')) {
|
|
104
|
+
const model = tf.sequential({
|
|
105
|
+
layers: [
|
|
106
|
+
tf.layers.dense({ inputShape: [20], units: 64, activation: 'relu' }),
|
|
107
|
+
tf.layers.dropout({ rate: 0.3 }),
|
|
108
|
+
tf.layers.dense({ units: 32, activation: 'relu' }),
|
|
109
|
+
tf.layers.dense({ units: 16, activation: 'relu' }),
|
|
110
|
+
tf.layers.dense({ units: 3, activation: 'softmax' }) // Low, Medium, High risk
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
model.compile({
|
|
114
|
+
optimizer: tf.train.adam(0.001),
|
|
115
|
+
loss: 'categoricalCrossentropy',
|
|
116
|
+
metrics: ['accuracy']
|
|
117
|
+
});
|
|
118
|
+
this.models.set('change_risk', model);
|
|
119
|
+
this.logger.info('Created change risk prediction neural network');
|
|
120
|
+
}
|
|
121
|
+
// Anomaly Detection Model (Autoencoder)
|
|
122
|
+
if (!this.models.has('anomaly_detector')) {
|
|
123
|
+
const encoder = tf.sequential({
|
|
124
|
+
layers: [
|
|
125
|
+
tf.layers.dense({ inputShape: [50], units: 32, activation: 'relu' }),
|
|
126
|
+
tf.layers.dense({ units: 16, activation: 'relu' }),
|
|
127
|
+
tf.layers.dense({ units: 8, activation: 'relu' }) // Bottleneck
|
|
128
|
+
]
|
|
129
|
+
});
|
|
130
|
+
const decoder = tf.sequential({
|
|
131
|
+
layers: [
|
|
132
|
+
tf.layers.dense({ inputShape: [8], units: 16, activation: 'relu' }),
|
|
133
|
+
tf.layers.dense({ units: 32, activation: 'relu' }),
|
|
134
|
+
tf.layers.dense({ units: 50, activation: 'sigmoid' })
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
// Combine encoder and decoder
|
|
138
|
+
const autoencoder = tf.sequential({
|
|
139
|
+
layers: [...encoder.layers, ...decoder.layers]
|
|
140
|
+
});
|
|
141
|
+
autoencoder.compile({
|
|
142
|
+
optimizer: tf.train.adam(0.001),
|
|
143
|
+
loss: 'meanSquaredError'
|
|
144
|
+
});
|
|
145
|
+
this.models.set('anomaly_detector', autoencoder);
|
|
146
|
+
this.logger.info('Created anomaly detection autoencoder');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Train incident classification model with real data
|
|
151
|
+
*/
|
|
152
|
+
async trainIncidentClassifier(incidents) {
|
|
153
|
+
this.logger.info(`Training incident classifier with ${incidents.length} samples`);
|
|
154
|
+
// Prepare training data
|
|
155
|
+
const { features, labels } = await this.prepareIncidentData(incidents);
|
|
156
|
+
// Get or create model
|
|
157
|
+
let model = this.models.get('incident_classifier');
|
|
158
|
+
if (!model) {
|
|
159
|
+
await this.createDefaultModels();
|
|
160
|
+
model = this.models.get('incident_classifier');
|
|
161
|
+
}
|
|
162
|
+
// Train the model
|
|
163
|
+
const history = await model.fit(features, labels, {
|
|
164
|
+
epochs: 50,
|
|
165
|
+
batchSize: 32,
|
|
166
|
+
validationSplit: 0.2,
|
|
167
|
+
callbacks: {
|
|
168
|
+
onEpochEnd: (epoch, logs) => {
|
|
169
|
+
if (epoch % 10 === 0) {
|
|
170
|
+
this.logger.debug(`Epoch ${epoch}: loss=${logs?.loss?.toFixed(4)}, accuracy=${logs?.acc?.toFixed(4)}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// Clean up tensors
|
|
176
|
+
features.dispose();
|
|
177
|
+
labels.dispose();
|
|
178
|
+
const finalAccuracy = history.history.acc[history.history.acc.length - 1];
|
|
179
|
+
const finalLoss = history.history.loss[history.history.loss.length - 1];
|
|
180
|
+
this.logger.info(`✅ Training complete: accuracy=${(finalAccuracy * 100).toFixed(2)}%, loss=${finalLoss.toFixed(4)}`);
|
|
181
|
+
// Save the model
|
|
182
|
+
await this.saveModel('incident_classifier', model);
|
|
183
|
+
return {
|
|
184
|
+
accuracy: finalAccuracy,
|
|
185
|
+
loss: finalLoss,
|
|
186
|
+
epochs: 50
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Classify an incident using the neural network
|
|
191
|
+
*/
|
|
192
|
+
async classifyIncident(incident) {
|
|
193
|
+
const model = this.models.get('incident_classifier');
|
|
194
|
+
if (!model) {
|
|
195
|
+
throw new Error('Incident classifier model not loaded. Please train the model first.');
|
|
196
|
+
}
|
|
197
|
+
// Convert incident to features
|
|
198
|
+
const features = await this.incidentToFeatures(incident);
|
|
199
|
+
// Make prediction
|
|
200
|
+
const prediction = model.predict(features);
|
|
201
|
+
const probabilities = await prediction.array();
|
|
202
|
+
// Get classification categories
|
|
203
|
+
const categories = [
|
|
204
|
+
'Hardware', 'Software', 'Network', 'Database', 'Application',
|
|
205
|
+
'Security', 'Access', 'Performance', 'Data', 'Other'
|
|
206
|
+
];
|
|
207
|
+
// Find highest probability
|
|
208
|
+
const probs = probabilities[0];
|
|
209
|
+
let maxProb = 0;
|
|
210
|
+
let maxIndex = 0;
|
|
211
|
+
const probabilityMap = {};
|
|
212
|
+
for (let i = 0; i < probs.length; i++) {
|
|
213
|
+
probabilityMap[categories[i]] = probs[i];
|
|
214
|
+
if (probs[i] > maxProb) {
|
|
215
|
+
maxProb = probs[i];
|
|
216
|
+
maxIndex = i;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Clean up tensors
|
|
220
|
+
features.dispose();
|
|
221
|
+
prediction.dispose();
|
|
222
|
+
return {
|
|
223
|
+
classification: categories[maxIndex],
|
|
224
|
+
confidence: maxProb,
|
|
225
|
+
probabilities: probabilityMap,
|
|
226
|
+
modelVersion: '1.0.0',
|
|
227
|
+
isRealML: true
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Predict change risk using neural network
|
|
232
|
+
*/
|
|
233
|
+
async predictChangeRisk(changeData) {
|
|
234
|
+
const model = this.models.get('change_risk');
|
|
235
|
+
if (!model) {
|
|
236
|
+
throw new Error('Change risk model not loaded. Please train the model first.');
|
|
237
|
+
}
|
|
238
|
+
// Convert change data to features
|
|
239
|
+
const features = this.changeToFeatures(changeData);
|
|
240
|
+
// Make prediction
|
|
241
|
+
const prediction = model.predict(features);
|
|
242
|
+
const probabilities = await prediction.array();
|
|
243
|
+
const riskLevels = ['Low', 'Medium', 'High'];
|
|
244
|
+
const probs = probabilities[0];
|
|
245
|
+
let maxProb = 0;
|
|
246
|
+
let maxIndex = 0;
|
|
247
|
+
const probabilityMap = {};
|
|
248
|
+
for (let i = 0; i < probs.length; i++) {
|
|
249
|
+
probabilityMap[riskLevels[i]] = probs[i];
|
|
250
|
+
if (probs[i] > maxProb) {
|
|
251
|
+
maxProb = probs[i];
|
|
252
|
+
maxIndex = i;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Clean up tensors
|
|
256
|
+
features.dispose();
|
|
257
|
+
prediction.dispose();
|
|
258
|
+
return {
|
|
259
|
+
classification: riskLevels[maxIndex],
|
|
260
|
+
confidence: maxProb,
|
|
261
|
+
probabilities: probabilityMap,
|
|
262
|
+
modelVersion: '1.0.0',
|
|
263
|
+
isRealML: true
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Detect anomalies using autoencoder
|
|
268
|
+
*/
|
|
269
|
+
async detectAnomaly(data) {
|
|
270
|
+
const model = this.models.get('anomaly_detector');
|
|
271
|
+
if (!model) {
|
|
272
|
+
throw new Error('Anomaly detector not loaded');
|
|
273
|
+
}
|
|
274
|
+
// Normalize input data
|
|
275
|
+
const input = tf.tensor2d([data]);
|
|
276
|
+
// Get reconstruction
|
|
277
|
+
const reconstruction = model.predict(input);
|
|
278
|
+
// Calculate reconstruction error
|
|
279
|
+
const error = tf.losses.meanSquaredError(input, reconstruction);
|
|
280
|
+
const errorValue = await error.array();
|
|
281
|
+
// Clean up tensors
|
|
282
|
+
input.dispose();
|
|
283
|
+
reconstruction.dispose();
|
|
284
|
+
error.dispose();
|
|
285
|
+
// Dynamic threshold based on training data
|
|
286
|
+
const threshold = 0.1; // This should be calculated from training data
|
|
287
|
+
return {
|
|
288
|
+
isAnomaly: errorValue > threshold,
|
|
289
|
+
reconstructionError: errorValue,
|
|
290
|
+
threshold
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Prepare incident data for training
|
|
295
|
+
*/
|
|
296
|
+
async prepareIncidentData(incidents) {
|
|
297
|
+
// Build vocabulary if not exists
|
|
298
|
+
if (!this.vocabularies.has('incident')) {
|
|
299
|
+
this.buildVocabulary(incidents);
|
|
300
|
+
}
|
|
301
|
+
const featureArrays = [];
|
|
302
|
+
const labelArrays = [];
|
|
303
|
+
for (const incident of incidents) {
|
|
304
|
+
// Convert to feature vector
|
|
305
|
+
const features = await this.incidentToFeatureArray(incident);
|
|
306
|
+
featureArrays.push(features);
|
|
307
|
+
// One-hot encode category
|
|
308
|
+
const categories = [
|
|
309
|
+
'Hardware', 'Software', 'Network', 'Database', 'Application',
|
|
310
|
+
'Security', 'Access', 'Performance', 'Data', 'Other'
|
|
311
|
+
];
|
|
312
|
+
const categoryIndex = categories.indexOf(incident.category) || 9; // Default to 'Other'
|
|
313
|
+
const oneHot = new Array(10).fill(0);
|
|
314
|
+
oneHot[categoryIndex] = 1;
|
|
315
|
+
labelArrays.push(oneHot);
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
features: tf.tensor2d(featureArrays),
|
|
319
|
+
labels: tf.tensor2d(labelArrays)
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Convert incident to feature tensor
|
|
324
|
+
*/
|
|
325
|
+
async incidentToFeatures(incident) {
|
|
326
|
+
const features = await this.incidentToFeatureArray(incident);
|
|
327
|
+
return tf.tensor2d([features]);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Convert incident to feature array
|
|
331
|
+
*/
|
|
332
|
+
async incidentToFeatureArray(incident) {
|
|
333
|
+
const features = [];
|
|
334
|
+
// Numerical features
|
|
335
|
+
features.push(incident.priority / 5); // Normalize 1-5 to 0-1
|
|
336
|
+
features.push(incident.urgency / 3); // Normalize 1-3 to 0-1
|
|
337
|
+
features.push(incident.impact / 3); // Normalize 1-3 to 0-1
|
|
338
|
+
// Text features - use simple bag of words for now
|
|
339
|
+
const vocab = this.vocabularies.get('incident') || new Map();
|
|
340
|
+
const words = (incident.shortDescription + ' ' + incident.description)
|
|
341
|
+
.toLowerCase()
|
|
342
|
+
.split(/\s+/)
|
|
343
|
+
.slice(0, 97); // Use first 97 words to fit in 100 features
|
|
344
|
+
// Create feature vector
|
|
345
|
+
const textFeatures = new Array(97).fill(0);
|
|
346
|
+
for (let i = 0; i < words.length && i < 97; i++) {
|
|
347
|
+
const wordIndex = vocab.get(words[i]);
|
|
348
|
+
if (wordIndex !== undefined && wordIndex < 97) {
|
|
349
|
+
textFeatures[wordIndex] = 1;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
features.push(...textFeatures);
|
|
353
|
+
// Ensure we have exactly 100 features
|
|
354
|
+
while (features.length < 100)
|
|
355
|
+
features.push(0);
|
|
356
|
+
if (features.length > 100)
|
|
357
|
+
features.length = 100;
|
|
358
|
+
return features;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Convert change data to features
|
|
362
|
+
*/
|
|
363
|
+
changeToFeatures(changeData) {
|
|
364
|
+
const features = [];
|
|
365
|
+
// Simple feature extraction
|
|
366
|
+
features.push(changeData.type === 'Emergency' ? 1 : 0);
|
|
367
|
+
features.push(changeData.type === 'Normal' ? 1 : 0);
|
|
368
|
+
features.push(changeData.type === 'Standard' ? 1 : 0);
|
|
369
|
+
// Text length features
|
|
370
|
+
features.push(Math.min(changeData.implementation_plan?.length || 0, 1000) / 1000);
|
|
371
|
+
features.push(Math.min(changeData.backout_plan?.length || 0, 1000) / 1000);
|
|
372
|
+
features.push(Math.min(changeData.test_plan?.length || 0, 1000) / 1000);
|
|
373
|
+
// Risk keywords
|
|
374
|
+
const riskKeywords = ['critical', 'major', 'production', 'outage', 'downtime'];
|
|
375
|
+
const text = (changeData.risk_assessment || '').toLowerCase();
|
|
376
|
+
for (const keyword of riskKeywords) {
|
|
377
|
+
features.push(text.includes(keyword) ? 1 : 0);
|
|
378
|
+
}
|
|
379
|
+
// Pad to 20 features
|
|
380
|
+
while (features.length < 20)
|
|
381
|
+
features.push(0);
|
|
382
|
+
if (features.length > 20)
|
|
383
|
+
features.length = 20;
|
|
384
|
+
return tf.tensor2d([features]);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Build vocabulary from training data
|
|
388
|
+
*/
|
|
389
|
+
buildVocabulary(incidents) {
|
|
390
|
+
const vocab = new Map();
|
|
391
|
+
const wordCounts = new Map();
|
|
392
|
+
// Count word frequencies
|
|
393
|
+
for (const incident of incidents) {
|
|
394
|
+
const words = (incident.shortDescription + ' ' + incident.description)
|
|
395
|
+
.toLowerCase()
|
|
396
|
+
.split(/\s+/);
|
|
397
|
+
for (const word of words) {
|
|
398
|
+
wordCounts.set(word, (wordCounts.get(word) || 0) + 1);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// Take top 97 most frequent words
|
|
402
|
+
const sortedWords = Array.from(wordCounts.entries())
|
|
403
|
+
.sort((a, b) => b[1] - a[1])
|
|
404
|
+
.slice(0, 97);
|
|
405
|
+
sortedWords.forEach(([word], index) => {
|
|
406
|
+
vocab.set(word, index);
|
|
407
|
+
});
|
|
408
|
+
this.vocabularies.set('incident', vocab);
|
|
409
|
+
this.logger.info(`Built vocabulary with ${vocab.size} words`);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Save model to disk
|
|
413
|
+
*/
|
|
414
|
+
async saveModel(name, model) {
|
|
415
|
+
try {
|
|
416
|
+
const path = `file://${this.MODEL_DIR}/${name}`;
|
|
417
|
+
await model.save(path);
|
|
418
|
+
this.logger.info(`Saved model ${name} to ${path}`);
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
this.logger.error(`Failed to save model ${name}:`, error);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Load model from disk
|
|
426
|
+
*/
|
|
427
|
+
async loadModel(name) {
|
|
428
|
+
try {
|
|
429
|
+
const path = `file://${this.MODEL_DIR}/${name}/model.json`;
|
|
430
|
+
const model = await tf.loadLayersModel(path);
|
|
431
|
+
this.models.set(name, model);
|
|
432
|
+
this.logger.info(`Loaded model ${name} from ${path}`);
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
this.logger.warn(`Could not load model ${name}, using default:`, error.message);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Get model summary
|
|
440
|
+
*/
|
|
441
|
+
getModelSummary(modelName) {
|
|
442
|
+
const model = this.models.get(modelName);
|
|
443
|
+
if (!model) {
|
|
444
|
+
return `Model ${modelName} not found`;
|
|
445
|
+
}
|
|
446
|
+
let summary = '';
|
|
447
|
+
model.summary(undefined, undefined, (line) => {
|
|
448
|
+
summary += line + '\n';
|
|
449
|
+
});
|
|
450
|
+
return summary;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
exports.TensorFlowMLService = TensorFlowMLService;
|
|
454
|
+
// Export singleton instance
|
|
455
|
+
exports.tensorflowML = TensorFlowMLService.getInstance();
|
|
456
|
+
//# sourceMappingURL=tensorflow-ml-service.js.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Deployment Service
|
|
3
|
+
* Direct ServiceNow API implementation for widget deployment
|
|
4
|
+
* No more MCP failures!
|
|
5
|
+
*/
|
|
6
|
+
export interface WidgetConfig {
|
|
7
|
+
name: string;
|
|
8
|
+
title: string;
|
|
9
|
+
template: string;
|
|
10
|
+
css?: string;
|
|
11
|
+
server_script?: string;
|
|
12
|
+
client_script?: string;
|
|
13
|
+
demo_data?: string;
|
|
14
|
+
option_schema?: string;
|
|
15
|
+
category?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface DeploymentResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
sys_id?: string;
|
|
21
|
+
portalUrl?: string;
|
|
22
|
+
apiEndpoint?: string;
|
|
23
|
+
message: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
verificationStatus?: 'verified' | 'unverified' | 'failed';
|
|
26
|
+
}
|
|
27
|
+
export declare class WidgetDeploymentService {
|
|
28
|
+
private static instance;
|
|
29
|
+
private logger;
|
|
30
|
+
private client;
|
|
31
|
+
private constructor();
|
|
32
|
+
static getInstance(): WidgetDeploymentService;
|
|
33
|
+
/**
|
|
34
|
+
* Initialize ServiceNow client
|
|
35
|
+
*/
|
|
36
|
+
private getClient;
|
|
37
|
+
/**
|
|
38
|
+
* Deploy widget to ServiceNow using direct API
|
|
39
|
+
*/
|
|
40
|
+
deployWidget(config: WidgetConfig): Promise<DeploymentResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Prepare widget data for ServiceNow API
|
|
43
|
+
*/
|
|
44
|
+
private prepareWidgetData;
|
|
45
|
+
/**
|
|
46
|
+
* Find existing widget by name
|
|
47
|
+
*/
|
|
48
|
+
private findExistingWidget;
|
|
49
|
+
/**
|
|
50
|
+
* Create new widget
|
|
51
|
+
*/
|
|
52
|
+
private createWidget;
|
|
53
|
+
/**
|
|
54
|
+
* Update existing widget
|
|
55
|
+
*/
|
|
56
|
+
private updateWidget;
|
|
57
|
+
/**
|
|
58
|
+
* Verify widget deployment
|
|
59
|
+
*/
|
|
60
|
+
private verifyDeployment;
|
|
61
|
+
/**
|
|
62
|
+
* Get widget details
|
|
63
|
+
*/
|
|
64
|
+
private getWidgetDetails;
|
|
65
|
+
/**
|
|
66
|
+
* Build portal URL for widget
|
|
67
|
+
*/
|
|
68
|
+
private buildPortalUrl;
|
|
69
|
+
/**
|
|
70
|
+
* Build API endpoint for widget
|
|
71
|
+
*/
|
|
72
|
+
private buildApiEndpoint;
|
|
73
|
+
/**
|
|
74
|
+
* Deploy widget with Update Set tracking
|
|
75
|
+
*/
|
|
76
|
+
deployWidgetWithUpdateSet(config: WidgetConfig, updateSetId?: string): Promise<DeploymentResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Switch to update set
|
|
79
|
+
*/
|
|
80
|
+
private switchToUpdateSet;
|
|
81
|
+
/**
|
|
82
|
+
* Log artifact to update set
|
|
83
|
+
*/
|
|
84
|
+
private logToUpdateSet;
|
|
85
|
+
/**
|
|
86
|
+
* Batch deploy multiple widgets
|
|
87
|
+
*/
|
|
88
|
+
batchDeployWidgets(widgets: WidgetConfig[]): Promise<DeploymentResult[]>;
|
|
89
|
+
/**
|
|
90
|
+
* Test widget deployment
|
|
91
|
+
*/
|
|
92
|
+
testDeployment(config: WidgetConfig): Promise<{
|
|
93
|
+
canConnect: boolean;
|
|
94
|
+
hasPermissions: boolean;
|
|
95
|
+
testResult: string;
|
|
96
|
+
}>;
|
|
97
|
+
/**
|
|
98
|
+
* Test ServiceNow connection
|
|
99
|
+
*/
|
|
100
|
+
private testConnection;
|
|
101
|
+
/**
|
|
102
|
+
* Test write permissions
|
|
103
|
+
*/
|
|
104
|
+
private testPermissions;
|
|
105
|
+
}
|
|
106
|
+
export declare const widgetDeployment: WidgetDeploymentService;
|
|
107
|
+
//# sourceMappingURL=widget-deployment-service.d.ts.map
|