@terminals-tech/sdk 1.0.0-rc.1 → 1.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/README.md +15 -19
- package/dist/WebContainerManager-4LIOGRVM.js +22 -0
- package/dist/browser-http-client-ZQLDWZMU.js +317 -0
- package/dist/cache-VKYSQRXX.js +45 -0
- package/dist/capabilities-MIPUMBLL.js +96 -0
- package/dist/chunk-2ESYSVXG.js +48 -0
- package/dist/chunk-2WTYE4SW.js +190 -0
- package/dist/chunk-3LFMIVJM.js +40 -0
- package/dist/chunk-ABCK4FWN.js +136 -0
- package/dist/chunk-AFDUOYHD.js +2060 -0
- package/dist/chunk-BCOQMFKT.js +265 -0
- package/dist/chunk-BYXBJQAS.js +0 -0
- package/dist/chunk-DKFJIILR.js +9798 -0
- package/dist/chunk-EXI3LJVJ.js +51 -0
- package/dist/chunk-FOXUEYWK.js +42 -0
- package/dist/chunk-GJWAJAX3.js +173 -0
- package/dist/chunk-H3POJCFA.js +333 -0
- package/dist/chunk-KASHT6C5.js +784 -0
- package/dist/chunk-KHR7ZYCX.js +4034 -0
- package/dist/chunk-L45BSQDJ.js +296 -0
- package/dist/chunk-LLGZTP3G.js +5521 -0
- package/dist/chunk-NTMBOESX.js +152 -0
- package/dist/chunk-OCLSAUCD.js +474 -0
- package/dist/chunk-OSSRZOGC.js +190 -0
- package/dist/chunk-PPFTKJDB.js +497 -0
- package/dist/chunk-PWAHFID5.js +381 -0
- package/dist/chunk-Q2VI6ICE.js +188 -0
- package/dist/chunk-QJFKEQHF.js +6460 -0
- package/dist/chunk-QWXPVB2L.js +320 -0
- package/dist/chunk-QWZRZKLZ.js +896 -0
- package/dist/chunk-STMI72WH.js +1005 -0
- package/dist/chunk-TSQ3BGLA.js +11945 -0
- package/dist/chunk-UJDUQNE2.js +79 -0
- package/dist/chunk-VZA2NUH3.js +118 -0
- package/dist/chunk-WGBCRNMB.js +1817 -0
- package/dist/chunk-WU4OTGJE.js +752 -0
- package/dist/chunk-XPJ63Y6T.js +70 -0
- package/dist/chunk-Y2EULKA2.js +172 -0
- package/dist/chunk-YJEZWCYV.js +94 -0
- package/dist/chunk-ZVO47SQV.js +150 -0
- package/dist/container-lite-QD3CRLS4.js +327 -0
- package/dist/core-H2UUDATO.js +146 -0
- package/dist/crypto-D4LMI2RN.js +45 -0
- package/dist/db-BWC2GGBN.js +50 -0
- package/dist/demo-T655Z5S4.js +87 -0
- package/dist/diagnostics-6RQTBR6I.js +113 -0
- package/dist/dist-OPDCWARF.js +727 -0
- package/dist/dist-VXJEKX3T.js +2441 -0
- package/dist/dist-VYGJXGUS.js +1008 -0
- package/dist/embeddings-7QXTXUMC.js +15 -0
- package/dist/embeddings-MAEWWUHW.js +9 -0
- package/dist/graph-RKMNE2X5.js +36 -0
- package/dist/hvm-CBEP3M4F.js +126 -0
- package/dist/index.cjs +49874 -8001
- package/dist/index.d.cts +1629 -1363
- package/dist/index.d.ts +1629 -1363
- package/dist/index.js +2462 -8130
- package/dist/mcp-NK34ZNM5.js +101 -0
- package/dist/mcp-client-service-browser-SGB2K3VZ.js +14 -0
- package/dist/neuro-state-XHRGIRVO.js +498 -0
- package/dist/nodes-K6GKI2FM.js +364 -0
- package/dist/package-EXUIU2RL.js +93 -0
- package/dist/package-VGL7HYTO.js +106 -0
- package/dist/package-XHMLOAQ4.js +98 -0
- package/dist/pg-events-QJAM2HIP.js +15 -0
- package/dist/pglite-adapter-43IOUBMV.js +50 -0
- package/dist/pgliteService-IUGNNOVU.js +258 -0
- package/dist/policy-IRJCM6FS.js +13 -0
- package/dist/registry-5WTDYQVQ.js +26 -0
- package/dist/registry-FW63E7FE.js +16 -0
- package/dist/registry-ZQ2IBLF6.js +9 -0
- package/dist/resolver-ALOJSOK5.js +24 -0
- package/dist/scheduler-B5CEYKWT.js +127 -0
- package/dist/secret-store-H7273UIT.js +18 -0
- package/dist/server-VW6DYDLH.js +18 -0
- package/dist/skills-VN7IN7SJ.js +6375 -0
- package/dist/stack-4KWCQQP7.js +103 -0
- package/dist/storage-L7MWNSPG.js +13 -0
- package/dist/supabaseService-6AYP2VY3.js +476 -0
- package/dist/topology-CIWWNVAN.js +13 -0
- package/dist/webcontainer-XWCE56F3.js +281 -0
- package/package.json +9 -3
|
@@ -0,0 +1,1008 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__commonJS
|
|
3
|
+
} from "./chunk-2ESYSVXG.js";
|
|
4
|
+
|
|
5
|
+
// ../../node_modules/@terminals-tech/graph/dist/TextGraph.js
|
|
6
|
+
var require_TextGraph = __commonJS({
|
|
7
|
+
"../../node_modules/@terminals-tech/graph/dist/TextGraph.js"(exports) {
|
|
8
|
+
"use strict";
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.TextGraph = void 0;
|
|
11
|
+
var TextGraph = class {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.patterns = {
|
|
14
|
+
// Causal relationships
|
|
15
|
+
causal: /(?:caused?|led to|resulted in|triggered|because of|due to|therefore|hence|thus|so)/i,
|
|
16
|
+
// Temporal relationships
|
|
17
|
+
temporal: /(?:before|after|then|when|while|during|followed by|subsequently|prior to|next)/i,
|
|
18
|
+
// Dependency relationships
|
|
19
|
+
dependency: /(?:requires?|depends? on|needs?|uses?|based on|relies on|built on)/i,
|
|
20
|
+
// Named entities (capitalized words)
|
|
21
|
+
entity: /(?:[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)/g,
|
|
22
|
+
// References to previous context
|
|
23
|
+
reference: /(?:this|that|it|they|them|the \w+)/gi,
|
|
24
|
+
// Actions/verbs that indicate relationships
|
|
25
|
+
action: /(?:clicked|opened|closed|created|deleted|updated|modified|viewed|downloaded|uploaded)/i
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extract relationships from text using linguistic patterns
|
|
30
|
+
*/
|
|
31
|
+
extractRelations(text) {
|
|
32
|
+
if (!text)
|
|
33
|
+
return [];
|
|
34
|
+
const relations = [];
|
|
35
|
+
const sentences = text.split(/[.!?]+/).filter((s) => s.trim());
|
|
36
|
+
sentences.forEach((sentence, idx) => {
|
|
37
|
+
const trimmed = sentence.trim();
|
|
38
|
+
const causalMatch = trimmed.match(this.patterns.causal);
|
|
39
|
+
if (causalMatch) {
|
|
40
|
+
const parts = trimmed.split(causalMatch[0]);
|
|
41
|
+
if (parts.length === 2) {
|
|
42
|
+
relations.push({
|
|
43
|
+
type: "causal",
|
|
44
|
+
from: this.normalize(parts[0]),
|
|
45
|
+
to: this.normalize(parts[1]),
|
|
46
|
+
weight: 0.8,
|
|
47
|
+
context: causalMatch[0]
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const temporalMatch = trimmed.match(this.patterns.temporal);
|
|
52
|
+
if (temporalMatch) {
|
|
53
|
+
const parts = trimmed.split(temporalMatch[0]);
|
|
54
|
+
if (parts.length === 2) {
|
|
55
|
+
relations.push({
|
|
56
|
+
type: "temporal",
|
|
57
|
+
from: this.normalize(parts[0]),
|
|
58
|
+
to: this.normalize(parts[1]),
|
|
59
|
+
weight: 0.6,
|
|
60
|
+
context: temporalMatch[0]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const dependencyMatch = trimmed.match(this.patterns.dependency);
|
|
65
|
+
if (dependencyMatch) {
|
|
66
|
+
const parts = trimmed.split(dependencyMatch[0]);
|
|
67
|
+
if (parts.length === 2) {
|
|
68
|
+
relations.push({
|
|
69
|
+
type: "dependency",
|
|
70
|
+
from: this.normalize(parts[0]),
|
|
71
|
+
to: this.normalize(parts[1]),
|
|
72
|
+
weight: 0.7,
|
|
73
|
+
context: dependencyMatch[0]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const entities = trimmed.match(this.patterns.entity) || [];
|
|
78
|
+
entities.forEach((entity) => {
|
|
79
|
+
if (entity.length > 2) {
|
|
80
|
+
relations.push({
|
|
81
|
+
type: "mention",
|
|
82
|
+
from: `sentence_${idx}`,
|
|
83
|
+
to: entity,
|
|
84
|
+
weight: 0.3
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
return relations;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build a graph from events
|
|
93
|
+
*/
|
|
94
|
+
buildGraph(events) {
|
|
95
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
96
|
+
const edges = [];
|
|
97
|
+
const entityMap = /* @__PURE__ */ new Map();
|
|
98
|
+
events.forEach((event, idx) => {
|
|
99
|
+
nodes.set(event.id, {
|
|
100
|
+
id: event.id,
|
|
101
|
+
label: event.type,
|
|
102
|
+
data: event,
|
|
103
|
+
timestamp: event.timestamp
|
|
104
|
+
});
|
|
105
|
+
if (idx > 0) {
|
|
106
|
+
edges.push({
|
|
107
|
+
from: events[idx - 1].id,
|
|
108
|
+
to: event.id,
|
|
109
|
+
type: "temporal",
|
|
110
|
+
weight: 0.5
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (event.description) {
|
|
114
|
+
const relations = this.extractRelations(event.description);
|
|
115
|
+
relations.forEach((rel) => {
|
|
116
|
+
if (rel.type === "mention") {
|
|
117
|
+
entityMap.set(rel.to, event.id);
|
|
118
|
+
if (!nodes.has(rel.to)) {
|
|
119
|
+
nodes.set(rel.to, {
|
|
120
|
+
id: rel.to,
|
|
121
|
+
label: rel.to,
|
|
122
|
+
data: { type: "entity", name: rel.to },
|
|
123
|
+
timestamp: event.timestamp
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
edges.push({
|
|
127
|
+
from: event.id,
|
|
128
|
+
to: rel.to,
|
|
129
|
+
type: "mention",
|
|
130
|
+
weight: rel.weight
|
|
131
|
+
});
|
|
132
|
+
} else {
|
|
133
|
+
const fromId = this.resolveReference(rel.from, event.id, entityMap);
|
|
134
|
+
const toId = this.resolveReference(rel.to, event.id, entityMap);
|
|
135
|
+
edges.push({
|
|
136
|
+
from: fromId,
|
|
137
|
+
to: toId,
|
|
138
|
+
type: rel.type,
|
|
139
|
+
weight: rel.weight
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return { nodes, edges };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Find events that caused a given event
|
|
149
|
+
*/
|
|
150
|
+
findCauses(graph, eventId) {
|
|
151
|
+
return graph.edges.filter((e) => e.to === eventId && e.type === "causal").map((e) => graph.nodes.get(e.from)).filter((node) => node !== void 0);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find events that were caused by a given event
|
|
155
|
+
*/
|
|
156
|
+
findEffects(graph, eventId) {
|
|
157
|
+
return graph.edges.filter((e) => e.from === eventId && e.type === "causal").map((e) => graph.nodes.get(e.to)).filter((node) => node !== void 0);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Find temporal sequence around an event
|
|
161
|
+
*/
|
|
162
|
+
findTemporalContext(graph, eventId, windowSize = 5) {
|
|
163
|
+
const result = [];
|
|
164
|
+
const visited = /* @__PURE__ */ new Set();
|
|
165
|
+
let current = eventId;
|
|
166
|
+
for (let i = 0; i < windowSize; i++) {
|
|
167
|
+
const prev = graph.edges.find((e) => e.to === current && e.type === "temporal");
|
|
168
|
+
if (!prev || visited.has(prev.from))
|
|
169
|
+
break;
|
|
170
|
+
const node = graph.nodes.get(prev.from);
|
|
171
|
+
if (node) {
|
|
172
|
+
result.unshift(node);
|
|
173
|
+
visited.add(prev.from);
|
|
174
|
+
current = prev.from;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const currentNode = graph.nodes.get(eventId);
|
|
178
|
+
if (currentNode)
|
|
179
|
+
result.push(currentNode);
|
|
180
|
+
current = eventId;
|
|
181
|
+
visited.clear();
|
|
182
|
+
for (let i = 0; i < windowSize; i++) {
|
|
183
|
+
const next = graph.edges.find((e) => e.from === current && e.type === "temporal");
|
|
184
|
+
if (!next || visited.has(next.to))
|
|
185
|
+
break;
|
|
186
|
+
const node = graph.nodes.get(next.to);
|
|
187
|
+
if (node) {
|
|
188
|
+
result.push(node);
|
|
189
|
+
visited.add(next.to);
|
|
190
|
+
current = next.to;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Find all related entities for an event
|
|
197
|
+
*/
|
|
198
|
+
findRelatedEntities(graph, eventId) {
|
|
199
|
+
return graph.edges.filter((e) => e.from === eventId && e.type === "mention").map((e) => graph.nodes.get(e.to)).filter((node) => node !== void 0 && node.data.type === "entity");
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Export graph to DOT format for visualization
|
|
203
|
+
*/
|
|
204
|
+
toDot(graph) {
|
|
205
|
+
const lines = ["digraph G {"];
|
|
206
|
+
graph.nodes.forEach((node) => {
|
|
207
|
+
const label = node.label.replace(/"/g, '\\"');
|
|
208
|
+
lines.push(` "${node.id}" [label="${label}"];`);
|
|
209
|
+
});
|
|
210
|
+
graph.edges.forEach((edge) => {
|
|
211
|
+
const style = this.getEdgeStyle(edge.type);
|
|
212
|
+
lines.push(` "${edge.from}" -> "${edge.to}" [${style}];`);
|
|
213
|
+
});
|
|
214
|
+
lines.push("}");
|
|
215
|
+
return lines.join("\n");
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Export graph to JSON for D3.js or other visualization libraries
|
|
219
|
+
*/
|
|
220
|
+
toJSON(graph) {
|
|
221
|
+
return {
|
|
222
|
+
nodes: Array.from(graph.nodes.values()),
|
|
223
|
+
links: graph.edges.map((e) => ({
|
|
224
|
+
source: e.from,
|
|
225
|
+
target: e.to,
|
|
226
|
+
type: e.type,
|
|
227
|
+
value: e.weight
|
|
228
|
+
}))
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// Private helper methods
|
|
232
|
+
normalize(text) {
|
|
233
|
+
return text.trim().toLowerCase().replace(/[^\w\s]/g, "");
|
|
234
|
+
}
|
|
235
|
+
resolveReference(ref, currentEventId, entityMap) {
|
|
236
|
+
const entityEvent = entityMap.get(ref);
|
|
237
|
+
if (entityEvent)
|
|
238
|
+
return entityEvent;
|
|
239
|
+
if (/^(this|that|it)/.test(ref.toLowerCase())) {
|
|
240
|
+
return currentEventId;
|
|
241
|
+
}
|
|
242
|
+
return ref;
|
|
243
|
+
}
|
|
244
|
+
getEdgeStyle(type) {
|
|
245
|
+
switch (type) {
|
|
246
|
+
case "causal":
|
|
247
|
+
return 'style="bold", color="red", label="causes"';
|
|
248
|
+
case "temporal":
|
|
249
|
+
return 'style="dashed", color="blue", label="then"';
|
|
250
|
+
case "dependency":
|
|
251
|
+
return 'style="dotted", color="green", label="depends"';
|
|
252
|
+
case "mention":
|
|
253
|
+
return 'style="dotted", color="gray", label="mentions"';
|
|
254
|
+
default:
|
|
255
|
+
return 'color="black"';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
exports.TextGraph = TextGraph;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// ../../node_modules/@terminals-tech/graph/dist/PatternMatcher.js
|
|
264
|
+
var require_PatternMatcher = __commonJS({
|
|
265
|
+
"../../node_modules/@terminals-tech/graph/dist/PatternMatcher.js"(exports) {
|
|
266
|
+
"use strict";
|
|
267
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
268
|
+
exports.PatternMatcher = void 0;
|
|
269
|
+
var PatternMatcher = class {
|
|
270
|
+
constructor() {
|
|
271
|
+
this.sequenceCache = /* @__PURE__ */ new Map();
|
|
272
|
+
this.transitionMatrix = /* @__PURE__ */ new Map();
|
|
273
|
+
this.eventTypeFrequency = /* @__PURE__ */ new Map();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Extract n-gram patterns from event sequences
|
|
277
|
+
*/
|
|
278
|
+
extractPatterns(events, n = 3) {
|
|
279
|
+
this.sequenceCache.clear();
|
|
280
|
+
for (let i = 0; i <= events.length - n; i++) {
|
|
281
|
+
const sequence = events.slice(i, i + n);
|
|
282
|
+
const key = sequence.map((e) => e.type).join("\u2192");
|
|
283
|
+
if (!this.sequenceCache.has(key)) {
|
|
284
|
+
this.sequenceCache.set(key, {
|
|
285
|
+
sequence: sequence.map((e) => e.type),
|
|
286
|
+
frequency: 0,
|
|
287
|
+
avgDuration: 0,
|
|
288
|
+
instances: []
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
const pattern = this.sequenceCache.get(key);
|
|
292
|
+
pattern.frequency++;
|
|
293
|
+
const instance = {
|
|
294
|
+
events: sequence,
|
|
295
|
+
timestamp: sequence[0].timestamp
|
|
296
|
+
};
|
|
297
|
+
if (sequence[n - 1].timestamp && sequence[0].timestamp) {
|
|
298
|
+
instance.duration = sequence[n - 1].timestamp - sequence[0].timestamp;
|
|
299
|
+
}
|
|
300
|
+
pattern.instances.push(instance);
|
|
301
|
+
}
|
|
302
|
+
this.sequenceCache.forEach((pattern) => {
|
|
303
|
+
const durations = pattern.instances.map((i) => i.duration).filter((d) => d !== void 0);
|
|
304
|
+
if (durations.length > 0) {
|
|
305
|
+
pattern.avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
this.buildTransitionMatrix(events);
|
|
309
|
+
return Array.from(this.sequenceCache.values()).filter((p) => p.frequency > 1).sort((a, b) => b.frequency - a.frequency);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Detect anomalies using statistical analysis
|
|
313
|
+
*/
|
|
314
|
+
detectAnomalies(events, threshold = 0.1) {
|
|
315
|
+
if (events.length < 2)
|
|
316
|
+
return [];
|
|
317
|
+
const anomalies = [];
|
|
318
|
+
const patterns = this.extractPatterns(events, 2);
|
|
319
|
+
const totalPairs = events.length - 1;
|
|
320
|
+
const avgFrequency = patterns.reduce((sum, p) => sum + p.frequency, 0) / patterns.length;
|
|
321
|
+
for (let i = 1; i < events.length; i++) {
|
|
322
|
+
const prevEvent = events[i - 1];
|
|
323
|
+
const currEvent = events[i];
|
|
324
|
+
const pair = `${prevEvent.type}\u2192${currEvent.type}`;
|
|
325
|
+
const pattern = patterns.find((p) => p.sequence.join("\u2192") === pair);
|
|
326
|
+
const frequency = pattern ? pattern.frequency : 0;
|
|
327
|
+
const relativeFreq = frequency / totalPairs;
|
|
328
|
+
if (relativeFreq < threshold) {
|
|
329
|
+
anomalies.push({
|
|
330
|
+
event: currEvent,
|
|
331
|
+
score: relativeFreq,
|
|
332
|
+
reason: `Rare transition: ${prevEvent.type} \u2192 ${currEvent.type}`,
|
|
333
|
+
context: [prevEvent, currEvent]
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
if (pattern && pattern.avgDuration > 0 && currEvent.timestamp && prevEvent.timestamp) {
|
|
337
|
+
const actualDuration = currEvent.timestamp - prevEvent.timestamp;
|
|
338
|
+
const expectedDuration = pattern.avgDuration;
|
|
339
|
+
const deviation = Math.abs(actualDuration - expectedDuration) / expectedDuration;
|
|
340
|
+
if (deviation > 2) {
|
|
341
|
+
anomalies.push({
|
|
342
|
+
event: currEvent,
|
|
343
|
+
score: 1 / (1 + deviation),
|
|
344
|
+
reason: `Unusual timing: expected ~${Math.round(expectedDuration)}ms, got ${actualDuration}ms`,
|
|
345
|
+
context: [prevEvent, currEvent]
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
this.calculateEventTypeFrequency(events);
|
|
351
|
+
const avgTypeFreq = Array.from(this.eventTypeFrequency.values()).reduce((a, b) => a + b, 0) / this.eventTypeFrequency.size;
|
|
352
|
+
events.forEach((event) => {
|
|
353
|
+
const typeFreq = this.eventTypeFrequency.get(event.type) || 0;
|
|
354
|
+
if (typeFreq < avgTypeFreq * threshold) {
|
|
355
|
+
anomalies.push({
|
|
356
|
+
event,
|
|
357
|
+
score: typeFreq / avgTypeFreq,
|
|
358
|
+
reason: `Rare event type: ${event.type} (${typeFreq} occurrences)`,
|
|
359
|
+
context: []
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
return anomalies.sort((a, b) => a.score - b.score);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Predict next event based on Markov chain
|
|
367
|
+
*/
|
|
368
|
+
predictNext(events, lookback = 3) {
|
|
369
|
+
if (events.length === 0)
|
|
370
|
+
return [];
|
|
371
|
+
const recent = events.slice(-lookback).map((e) => e.type);
|
|
372
|
+
const predictions = /* @__PURE__ */ new Map();
|
|
373
|
+
this.sequenceCache.forEach((pattern) => {
|
|
374
|
+
const patternPrefix = pattern.sequence.slice(0, lookback);
|
|
375
|
+
if (this.arraysEqual(patternPrefix, recent) && pattern.sequence.length > lookback) {
|
|
376
|
+
const nextEvent = pattern.sequence[lookback];
|
|
377
|
+
predictions.set(nextEvent, (predictions.get(nextEvent) || 0) + pattern.frequency);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
if (predictions.size === 0 && this.transitionMatrix.size > 0) {
|
|
381
|
+
const lastEvent = events[events.length - 1].type;
|
|
382
|
+
const transitions = this.transitionMatrix.get(lastEvent);
|
|
383
|
+
if (transitions) {
|
|
384
|
+
transitions.forEach((count, nextType) => {
|
|
385
|
+
predictions.set(nextType, count);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const total = Array.from(predictions.values()).reduce((a, b) => a + b, 0);
|
|
390
|
+
if (total === 0) {
|
|
391
|
+
return this.getMostCommonEventTypes(events, 3);
|
|
392
|
+
}
|
|
393
|
+
return Array.from(predictions.entries()).map(([type, count]) => ({
|
|
394
|
+
type,
|
|
395
|
+
probability: count / total,
|
|
396
|
+
confidence: Math.min(count / 10, 1),
|
|
397
|
+
// Confidence based on sample size
|
|
398
|
+
basedOn: this.findPatternsContaining(type, recent)
|
|
399
|
+
})).sort((a, b) => b.probability - a.probability).slice(0, 5);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Find cyclic patterns (loops in behavior)
|
|
403
|
+
*/
|
|
404
|
+
findCycles(events, minLength = 3, maxLength = 10) {
|
|
405
|
+
const cycles = [];
|
|
406
|
+
for (let len = minLength; len <= maxLength && len <= events.length / 2; len++) {
|
|
407
|
+
for (let start = 0; start <= events.length - len * 2; start++) {
|
|
408
|
+
const candidate = events.slice(start, start + len).map((e) => e.type);
|
|
409
|
+
for (let next = start + len; next <= events.length - len; next++) {
|
|
410
|
+
const comparison = events.slice(next, next + len).map((e) => e.type);
|
|
411
|
+
if (this.arraysEqual(candidate, comparison)) {
|
|
412
|
+
const key = candidate.join("\u2192");
|
|
413
|
+
if (!cycles.find((c) => c.sequence.join("\u2192") === key)) {
|
|
414
|
+
cycles.push({
|
|
415
|
+
sequence: candidate,
|
|
416
|
+
frequency: 2,
|
|
417
|
+
// Found at least twice
|
|
418
|
+
avgDuration: 0,
|
|
419
|
+
instances: [
|
|
420
|
+
{ events: events.slice(start, start + len), timestamp: events[start].timestamp },
|
|
421
|
+
{ events: events.slice(next, next + len), timestamp: events[next].timestamp }
|
|
422
|
+
]
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return cycles;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Calculate pattern complexity (entropy)
|
|
433
|
+
*/
|
|
434
|
+
calculateComplexity(events) {
|
|
435
|
+
if (events.length === 0)
|
|
436
|
+
return 0;
|
|
437
|
+
this.calculateEventTypeFrequency(events);
|
|
438
|
+
const total = events.length;
|
|
439
|
+
let entropy = 0;
|
|
440
|
+
this.eventTypeFrequency.forEach((count) => {
|
|
441
|
+
const probability = count / total;
|
|
442
|
+
if (probability > 0) {
|
|
443
|
+
entropy -= probability * Math.log2(probability);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
return entropy;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Find patterns that deviate from the norm
|
|
450
|
+
*/
|
|
451
|
+
findDeviations(events, windowSize = 20) {
|
|
452
|
+
const deviations = [];
|
|
453
|
+
if (events.length < windowSize * 2)
|
|
454
|
+
return deviations;
|
|
455
|
+
const baseline = events.slice(0, Math.floor(events.length / 2));
|
|
456
|
+
const baselinePatterns = this.extractPatterns(baseline, 2);
|
|
457
|
+
const baselineTransitions = /* @__PURE__ */ new Map();
|
|
458
|
+
baselinePatterns.forEach((p) => {
|
|
459
|
+
const key = p.sequence.join("\u2192");
|
|
460
|
+
baselineTransitions.set(key, p.frequency);
|
|
461
|
+
});
|
|
462
|
+
for (let i = 0; i <= events.length - windowSize; i++) {
|
|
463
|
+
const window = events.slice(i, i + windowSize);
|
|
464
|
+
const windowPatterns = this.extractPatterns(window, 2);
|
|
465
|
+
let deviationScore = 0;
|
|
466
|
+
windowPatterns.forEach((p) => {
|
|
467
|
+
const key = p.sequence.join("\u2192");
|
|
468
|
+
const baselineFreq = baselineTransitions.get(key) || 0;
|
|
469
|
+
const expectedFreq = baselineFreq / baseline.length * window.length;
|
|
470
|
+
const actualFreq = p.frequency;
|
|
471
|
+
if (expectedFreq > 0) {
|
|
472
|
+
deviationScore += Math.abs(actualFreq - expectedFreq) / expectedFreq;
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
if (deviationScore > 1) {
|
|
476
|
+
deviations.push({
|
|
477
|
+
event: window[0],
|
|
478
|
+
score: deviationScore,
|
|
479
|
+
reason: `Pattern deviation in window starting at index ${i}`,
|
|
480
|
+
context: window
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return deviations;
|
|
485
|
+
}
|
|
486
|
+
// Private helper methods
|
|
487
|
+
buildTransitionMatrix(events) {
|
|
488
|
+
this.transitionMatrix.clear();
|
|
489
|
+
for (let i = 0; i < events.length - 1; i++) {
|
|
490
|
+
const current = events[i].type;
|
|
491
|
+
const next = events[i + 1].type;
|
|
492
|
+
if (!this.transitionMatrix.has(current)) {
|
|
493
|
+
this.transitionMatrix.set(current, /* @__PURE__ */ new Map());
|
|
494
|
+
}
|
|
495
|
+
const transitions = this.transitionMatrix.get(current);
|
|
496
|
+
transitions.set(next, (transitions.get(next) || 0) + 1);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
calculateEventTypeFrequency(events) {
|
|
500
|
+
this.eventTypeFrequency.clear();
|
|
501
|
+
events.forEach((event) => {
|
|
502
|
+
this.eventTypeFrequency.set(event.type, (this.eventTypeFrequency.get(event.type) || 0) + 1);
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
arraysEqual(a, b) {
|
|
506
|
+
if (a.length !== b.length)
|
|
507
|
+
return false;
|
|
508
|
+
return a.every((val, idx) => val === b[idx]);
|
|
509
|
+
}
|
|
510
|
+
findPatternsContaining(eventType, prefix) {
|
|
511
|
+
return Array.from(this.sequenceCache.values()).filter((p) => {
|
|
512
|
+
const prefixMatch = prefix.every((type, idx) => p.sequence[idx] === type);
|
|
513
|
+
const containsType = p.sequence.includes(eventType);
|
|
514
|
+
return prefixMatch && containsType;
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
getMostCommonEventTypes(events, n) {
|
|
518
|
+
this.calculateEventTypeFrequency(events);
|
|
519
|
+
const total = events.length;
|
|
520
|
+
return Array.from(this.eventTypeFrequency.entries()).sort((a, b) => b[1] - a[1]).slice(0, n).map(([type, count]) => ({
|
|
521
|
+
type,
|
|
522
|
+
probability: count / total,
|
|
523
|
+
confidence: 0.3
|
|
524
|
+
// Low confidence for fallback predictions
|
|
525
|
+
}));
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
exports.PatternMatcher = PatternMatcher;
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
// ../../node_modules/@terminals-tech/graph/dist/GraphProcessor.js
|
|
533
|
+
var require_GraphProcessor = __commonJS({
|
|
534
|
+
"../../node_modules/@terminals-tech/graph/dist/GraphProcessor.js"(exports) {
|
|
535
|
+
"use strict";
|
|
536
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
537
|
+
exports.GraphProcessor = void 0;
|
|
538
|
+
var GraphProcessor = class {
|
|
539
|
+
constructor() {
|
|
540
|
+
this.adjacencyList = /* @__PURE__ */ new Map();
|
|
541
|
+
this.reverseIndex = /* @__PURE__ */ new Map();
|
|
542
|
+
this.edgeWeights = /* @__PURE__ */ new Map();
|
|
543
|
+
this.nodeData = /* @__PURE__ */ new Map();
|
|
544
|
+
this.pageRankCache = /* @__PURE__ */ new Map();
|
|
545
|
+
this.clusters = /* @__PURE__ */ new Map();
|
|
546
|
+
this.isDirty = false;
|
|
547
|
+
this.nodeCount = 0;
|
|
548
|
+
this.edgeCount = 0;
|
|
549
|
+
this.processedEvents = /* @__PURE__ */ new Set();
|
|
550
|
+
this.edgeHashes = /* @__PURE__ */ new Set();
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Add event to graph incrementally (idempotent)
|
|
554
|
+
*/
|
|
555
|
+
addEvent(event, relations) {
|
|
556
|
+
if (this.processedEvents.has(event.id)) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
const snapshot = this.createSnapshot();
|
|
560
|
+
try {
|
|
561
|
+
if (!this.adjacencyList.has(event.id)) {
|
|
562
|
+
this.adjacencyList.set(event.id, /* @__PURE__ */ new Set());
|
|
563
|
+
this.nodeData.set(event.id, event);
|
|
564
|
+
this.nodeCount++;
|
|
565
|
+
}
|
|
566
|
+
relations.forEach((rel) => {
|
|
567
|
+
this.addEdge(event.id, rel.to, rel.weight, rel.type);
|
|
568
|
+
});
|
|
569
|
+
this.processedEvents.add(event.id);
|
|
570
|
+
this.isDirty = true;
|
|
571
|
+
} catch (error) {
|
|
572
|
+
this.restoreSnapshot(snapshot);
|
|
573
|
+
throw error;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Add edge between nodes (idempotent)
|
|
578
|
+
*/
|
|
579
|
+
addEdge(from, to, weight = 1, type) {
|
|
580
|
+
const edgeHash = `${from}->${to}:${type || "default"}`;
|
|
581
|
+
if (this.edgeHashes.has(edgeHash)) {
|
|
582
|
+
const existingWeight = this.edgeWeights.get(from)?.get(to) || 0;
|
|
583
|
+
if (weight > existingWeight) {
|
|
584
|
+
this.edgeWeights.get(from).set(to, weight);
|
|
585
|
+
}
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (!this.adjacencyList.has(from)) {
|
|
589
|
+
this.adjacencyList.set(from, /* @__PURE__ */ new Set());
|
|
590
|
+
this.nodeCount++;
|
|
591
|
+
}
|
|
592
|
+
if (!this.adjacencyList.has(to)) {
|
|
593
|
+
this.adjacencyList.set(to, /* @__PURE__ */ new Set());
|
|
594
|
+
this.nodeCount++;
|
|
595
|
+
}
|
|
596
|
+
this.adjacencyList.get(from).add(to);
|
|
597
|
+
if (!this.reverseIndex.has(to)) {
|
|
598
|
+
this.reverseIndex.set(to, /* @__PURE__ */ new Set());
|
|
599
|
+
}
|
|
600
|
+
this.reverseIndex.get(to).add(from);
|
|
601
|
+
if (!this.edgeWeights.has(from)) {
|
|
602
|
+
this.edgeWeights.set(from, /* @__PURE__ */ new Map());
|
|
603
|
+
}
|
|
604
|
+
this.edgeWeights.get(from).set(to, weight);
|
|
605
|
+
this.edgeHashes.add(edgeHash);
|
|
606
|
+
this.edgeCount++;
|
|
607
|
+
this.isDirty = true;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Calculate PageRank scores using power iteration
|
|
611
|
+
*/
|
|
612
|
+
calculatePageRank(iterations = 20, damping = 0.85) {
|
|
613
|
+
if (!this.isDirty && this.pageRankCache.size > 0) {
|
|
614
|
+
return this.formatPageRankResults();
|
|
615
|
+
}
|
|
616
|
+
const nodes = Array.from(this.adjacencyList.keys());
|
|
617
|
+
const n = nodes.length;
|
|
618
|
+
if (n === 0)
|
|
619
|
+
return [];
|
|
620
|
+
const scores = /* @__PURE__ */ new Map();
|
|
621
|
+
const newScores = /* @__PURE__ */ new Map();
|
|
622
|
+
nodes.forEach((node) => scores.set(node, 1 / n));
|
|
623
|
+
for (let iter = 0; iter < iterations; iter++) {
|
|
624
|
+
newScores.clear();
|
|
625
|
+
nodes.forEach((node) => {
|
|
626
|
+
let score = (1 - damping) / n;
|
|
627
|
+
const incoming = this.reverseIndex.get(node) || /* @__PURE__ */ new Set();
|
|
628
|
+
incoming.forEach((source) => {
|
|
629
|
+
const outDegree = this.adjacencyList.get(source)?.size || 1;
|
|
630
|
+
const sourceScore = scores.get(source) || 0;
|
|
631
|
+
const edgeWeight = this.edgeWeights.get(source)?.get(node) || 1;
|
|
632
|
+
score += damping * sourceScore * edgeWeight / outDegree;
|
|
633
|
+
});
|
|
634
|
+
newScores.set(node, score);
|
|
635
|
+
});
|
|
636
|
+
scores.clear();
|
|
637
|
+
newScores.forEach((score, node) => scores.set(node, score));
|
|
638
|
+
}
|
|
639
|
+
this.pageRankCache = scores;
|
|
640
|
+
this.isDirty = false;
|
|
641
|
+
return this.formatPageRankResults();
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Find connected components (clusters)
|
|
645
|
+
*/
|
|
646
|
+
findClusters() {
|
|
647
|
+
this.clusters.clear();
|
|
648
|
+
const visited = /* @__PURE__ */ new Set();
|
|
649
|
+
const clusterList = [];
|
|
650
|
+
let clusterId = 0;
|
|
651
|
+
this.adjacencyList.forEach((_, startNode) => {
|
|
652
|
+
if (!visited.has(startNode)) {
|
|
653
|
+
const cluster = /* @__PURE__ */ new Set();
|
|
654
|
+
const queue = [startNode];
|
|
655
|
+
visited.add(startNode);
|
|
656
|
+
while (queue.length > 0) {
|
|
657
|
+
const node = queue.shift();
|
|
658
|
+
cluster.add(node);
|
|
659
|
+
this.clusters.set(node, clusterId);
|
|
660
|
+
const outgoing = this.adjacencyList.get(node) || /* @__PURE__ */ new Set();
|
|
661
|
+
const incoming = this.reverseIndex.get(node) || /* @__PURE__ */ new Set();
|
|
662
|
+
const neighbors = /* @__PURE__ */ new Set([...outgoing, ...incoming]);
|
|
663
|
+
neighbors.forEach((neighbor) => {
|
|
664
|
+
if (!visited.has(neighbor)) {
|
|
665
|
+
visited.add(neighbor);
|
|
666
|
+
queue.push(neighbor);
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
const density = this.calculateClusterDensity(cluster);
|
|
671
|
+
const center = this.findClusterCenter(cluster);
|
|
672
|
+
clusterList.push({
|
|
673
|
+
id: clusterId++,
|
|
674
|
+
nodes: cluster,
|
|
675
|
+
center,
|
|
676
|
+
density
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
return clusterList.sort((a, b) => b.nodes.size - a.nodes.size);
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Find shortest path using BFS
|
|
684
|
+
*/
|
|
685
|
+
findPath(from, to) {
|
|
686
|
+
if (!this.adjacencyList.has(from) || !this.adjacencyList.has(to)) {
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
const queue = [
|
|
690
|
+
{ node: from, path: [from], weight: 0 }
|
|
691
|
+
];
|
|
692
|
+
const visited = /* @__PURE__ */ new Set([from]);
|
|
693
|
+
while (queue.length > 0) {
|
|
694
|
+
const { node, path, weight } = queue.shift();
|
|
695
|
+
if (node === to) {
|
|
696
|
+
return {
|
|
697
|
+
nodes: path,
|
|
698
|
+
totalWeight: weight,
|
|
699
|
+
length: path.length - 1
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
const neighbors = this.adjacencyList.get(node) || /* @__PURE__ */ new Set();
|
|
703
|
+
neighbors.forEach((neighbor) => {
|
|
704
|
+
if (!visited.has(neighbor)) {
|
|
705
|
+
visited.add(neighbor);
|
|
706
|
+
const edgeWeight = this.edgeWeights.get(node)?.get(neighbor) || 1;
|
|
707
|
+
queue.push({
|
|
708
|
+
node: neighbor,
|
|
709
|
+
path: [...path, neighbor],
|
|
710
|
+
weight: weight + edgeWeight
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Find all paths between two nodes (limited depth)
|
|
719
|
+
*/
|
|
720
|
+
findAllPaths(from, to, maxDepth = 5) {
|
|
721
|
+
if (!this.adjacencyList.has(from) || !this.adjacencyList.has(to)) {
|
|
722
|
+
return [];
|
|
723
|
+
}
|
|
724
|
+
const paths = [];
|
|
725
|
+
const stack = [
|
|
726
|
+
{ node: from, path: [from], weight: 0, visited: /* @__PURE__ */ new Set([from]) }
|
|
727
|
+
];
|
|
728
|
+
while (stack.length > 0) {
|
|
729
|
+
const { node, path, weight, visited } = stack.pop();
|
|
730
|
+
if (path.length > maxDepth)
|
|
731
|
+
continue;
|
|
732
|
+
if (node === to) {
|
|
733
|
+
paths.push({
|
|
734
|
+
nodes: path,
|
|
735
|
+
totalWeight: weight,
|
|
736
|
+
length: path.length - 1
|
|
737
|
+
});
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
const neighbors = this.adjacencyList.get(node) || /* @__PURE__ */ new Set();
|
|
741
|
+
neighbors.forEach((neighbor) => {
|
|
742
|
+
if (!visited.has(neighbor)) {
|
|
743
|
+
const newVisited = new Set(visited);
|
|
744
|
+
newVisited.add(neighbor);
|
|
745
|
+
const edgeWeight = this.edgeWeights.get(node)?.get(neighbor) || 1;
|
|
746
|
+
stack.push({
|
|
747
|
+
node: neighbor,
|
|
748
|
+
path: [...path, neighbor],
|
|
749
|
+
weight: weight + edgeWeight,
|
|
750
|
+
visited: newVisited
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
return paths.sort((a, b) => a.totalWeight - b.totalWeight);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Get subgraph around a node
|
|
759
|
+
*/
|
|
760
|
+
getSubgraph(nodeId, depth = 2) {
|
|
761
|
+
if (!this.adjacencyList.has(nodeId)) {
|
|
762
|
+
return { nodes: /* @__PURE__ */ new Set(), edges: [] };
|
|
763
|
+
}
|
|
764
|
+
const subgraphNodes = /* @__PURE__ */ new Set();
|
|
765
|
+
const subgraphEdges = [];
|
|
766
|
+
const queue = [{ node: nodeId, d: 0 }];
|
|
767
|
+
const visited = /* @__PURE__ */ new Set();
|
|
768
|
+
while (queue.length > 0) {
|
|
769
|
+
const { node, d } = queue.shift();
|
|
770
|
+
if (visited.has(node) || d > depth)
|
|
771
|
+
continue;
|
|
772
|
+
visited.add(node);
|
|
773
|
+
subgraphNodes.add(node);
|
|
774
|
+
const neighbors = this.adjacencyList.get(node) || /* @__PURE__ */ new Set();
|
|
775
|
+
neighbors.forEach((neighbor) => {
|
|
776
|
+
if (d < depth) {
|
|
777
|
+
const weight = this.edgeWeights.get(node)?.get(neighbor) || 1;
|
|
778
|
+
subgraphEdges.push({
|
|
779
|
+
from: node,
|
|
780
|
+
to: neighbor,
|
|
781
|
+
weight
|
|
782
|
+
});
|
|
783
|
+
queue.push({ node: neighbor, d: d + 1 });
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
const incoming = this.reverseIndex.get(node) || /* @__PURE__ */ new Set();
|
|
787
|
+
incoming.forEach((source) => {
|
|
788
|
+
if (d < depth && !visited.has(source)) {
|
|
789
|
+
queue.push({ node: source, d: d + 1 });
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
return { nodes: subgraphNodes, edges: subgraphEdges };
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Detect cycles in the graph
|
|
797
|
+
*/
|
|
798
|
+
detectCycles() {
|
|
799
|
+
const cycles = [];
|
|
800
|
+
const visited = /* @__PURE__ */ new Set();
|
|
801
|
+
const recursionStack = /* @__PURE__ */ new Set();
|
|
802
|
+
const dfs = (node, path) => {
|
|
803
|
+
visited.add(node);
|
|
804
|
+
recursionStack.add(node);
|
|
805
|
+
path.push(node);
|
|
806
|
+
const neighbors = this.adjacencyList.get(node) || /* @__PURE__ */ new Set();
|
|
807
|
+
neighbors.forEach((neighbor) => {
|
|
808
|
+
if (!visited.has(neighbor)) {
|
|
809
|
+
dfs(neighbor, [...path]);
|
|
810
|
+
} else if (recursionStack.has(neighbor)) {
|
|
811
|
+
const cycleStart = path.indexOf(neighbor);
|
|
812
|
+
if (cycleStart !== -1) {
|
|
813
|
+
cycles.push(path.slice(cycleStart));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
recursionStack.delete(node);
|
|
818
|
+
};
|
|
819
|
+
this.adjacencyList.forEach((_, node) => {
|
|
820
|
+
if (!visited.has(node)) {
|
|
821
|
+
dfs(node, []);
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
return cycles;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Calculate graph statistics
|
|
828
|
+
*/
|
|
829
|
+
getStatistics() {
|
|
830
|
+
const degrees = Array.from(this.adjacencyList.values()).map((neighbors) => neighbors.size);
|
|
831
|
+
const maxDegree = Math.max(...degrees, 0);
|
|
832
|
+
const avgDegree = degrees.length > 0 ? degrees.reduce((a, b) => a + b, 0) / degrees.length : 0;
|
|
833
|
+
const maxPossibleEdges = this.nodeCount * (this.nodeCount - 1);
|
|
834
|
+
const density = maxPossibleEdges > 0 ? this.edgeCount / maxPossibleEdges : 0;
|
|
835
|
+
const clusters = this.findClusters();
|
|
836
|
+
const connected = clusters.length === 1;
|
|
837
|
+
const cycles = this.detectCycles();
|
|
838
|
+
const cyclic = cycles.length > 0;
|
|
839
|
+
return {
|
|
840
|
+
nodes: this.nodeCount,
|
|
841
|
+
edges: this.edgeCount,
|
|
842
|
+
density,
|
|
843
|
+
avgDegree,
|
|
844
|
+
maxDegree,
|
|
845
|
+
connected,
|
|
846
|
+
cyclic
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Clear the graph
|
|
851
|
+
*/
|
|
852
|
+
clear() {
|
|
853
|
+
this.adjacencyList.clear();
|
|
854
|
+
this.reverseIndex.clear();
|
|
855
|
+
this.edgeWeights.clear();
|
|
856
|
+
this.nodeData.clear();
|
|
857
|
+
this.pageRankCache.clear();
|
|
858
|
+
this.clusters.clear();
|
|
859
|
+
this.processedEvents.clear();
|
|
860
|
+
this.edgeHashes.clear();
|
|
861
|
+
this.nodeCount = 0;
|
|
862
|
+
this.edgeCount = 0;
|
|
863
|
+
this.isDirty = false;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Create a snapshot for rollback
|
|
867
|
+
*/
|
|
868
|
+
createSnapshot() {
|
|
869
|
+
return {
|
|
870
|
+
nodeCount: this.nodeCount,
|
|
871
|
+
edgeCount: this.edgeCount,
|
|
872
|
+
processedEvents: new Set(this.processedEvents),
|
|
873
|
+
edgeHashes: new Set(this.edgeHashes)
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* Restore from snapshot
|
|
878
|
+
*/
|
|
879
|
+
restoreSnapshot(snapshot) {
|
|
880
|
+
this.nodeCount = snapshot.nodeCount;
|
|
881
|
+
this.edgeCount = snapshot.edgeCount;
|
|
882
|
+
this.processedEvents = snapshot.processedEvents;
|
|
883
|
+
this.edgeHashes = snapshot.edgeHashes;
|
|
884
|
+
this.isDirty = true;
|
|
885
|
+
}
|
|
886
|
+
// Private helper methods
|
|
887
|
+
formatPageRankResults() {
|
|
888
|
+
const results = Array.from(this.pageRankCache.entries()).map(([node, score]) => ({ node, score, rank: 0 })).sort((a, b) => b.score - a.score);
|
|
889
|
+
results.forEach((result, idx) => {
|
|
890
|
+
result.rank = idx + 1;
|
|
891
|
+
});
|
|
892
|
+
return results;
|
|
893
|
+
}
|
|
894
|
+
calculateClusterDensity(cluster) {
|
|
895
|
+
if (cluster.size <= 1)
|
|
896
|
+
return 0;
|
|
897
|
+
let internalEdges = 0;
|
|
898
|
+
cluster.forEach((node) => {
|
|
899
|
+
const neighbors = this.adjacencyList.get(node) || /* @__PURE__ */ new Set();
|
|
900
|
+
neighbors.forEach((neighbor) => {
|
|
901
|
+
if (cluster.has(neighbor)) {
|
|
902
|
+
internalEdges++;
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
});
|
|
906
|
+
const maxPossibleEdges = cluster.size * (cluster.size - 1);
|
|
907
|
+
return maxPossibleEdges > 0 ? internalEdges / maxPossibleEdges : 0;
|
|
908
|
+
}
|
|
909
|
+
findClusterCenter(cluster) {
|
|
910
|
+
let maxDegree = 0;
|
|
911
|
+
let center;
|
|
912
|
+
cluster.forEach((node) => {
|
|
913
|
+
const outDegree = (this.adjacencyList.get(node) || /* @__PURE__ */ new Set()).size;
|
|
914
|
+
const inDegree = (this.reverseIndex.get(node) || /* @__PURE__ */ new Set()).size;
|
|
915
|
+
const totalDegree = outDegree + inDegree;
|
|
916
|
+
if (totalDegree > maxDegree) {
|
|
917
|
+
maxDegree = totalDegree;
|
|
918
|
+
center = node;
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
return center;
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
exports.GraphProcessor = GraphProcessor;
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
// ../../node_modules/@terminals-tech/graph/dist/index.js
|
|
929
|
+
var require_dist = __commonJS({
|
|
930
|
+
"../../node_modules/@terminals-tech/graph/dist/index.js"(exports) {
|
|
931
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
932
|
+
exports.EventGraph = exports.GraphProcessor = exports.PatternMatcher = exports.TextGraph = void 0;
|
|
933
|
+
var TextGraph_1 = require_TextGraph();
|
|
934
|
+
var PatternMatcher_1 = require_PatternMatcher();
|
|
935
|
+
var GraphProcessor_1 = require_GraphProcessor();
|
|
936
|
+
var TextGraph_2 = require_TextGraph();
|
|
937
|
+
Object.defineProperty(exports, "TextGraph", { enumerable: true, get: function() {
|
|
938
|
+
return TextGraph_2.TextGraph;
|
|
939
|
+
} });
|
|
940
|
+
var PatternMatcher_2 = require_PatternMatcher();
|
|
941
|
+
Object.defineProperty(exports, "PatternMatcher", { enumerable: true, get: function() {
|
|
942
|
+
return PatternMatcher_2.PatternMatcher;
|
|
943
|
+
} });
|
|
944
|
+
var GraphProcessor_2 = require_GraphProcessor();
|
|
945
|
+
Object.defineProperty(exports, "GraphProcessor", { enumerable: true, get: function() {
|
|
946
|
+
return GraphProcessor_2.GraphProcessor;
|
|
947
|
+
} });
|
|
948
|
+
var EventGraph = class {
|
|
949
|
+
constructor() {
|
|
950
|
+
this.textGraph = new TextGraph_1.TextGraph();
|
|
951
|
+
this.patternMatcher = new PatternMatcher_1.PatternMatcher();
|
|
952
|
+
this.processor = new GraphProcessor_1.GraphProcessor();
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Process events and build graph
|
|
956
|
+
*/
|
|
957
|
+
processEvents(events) {
|
|
958
|
+
const graph = this.textGraph.buildGraph(events);
|
|
959
|
+
events.forEach((event) => {
|
|
960
|
+
if (event.description) {
|
|
961
|
+
const relations = this.textGraph.extractRelations(event.description);
|
|
962
|
+
this.processor.addEvent(event, relations);
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
this.patternMatcher.extractPatterns(events);
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Find what caused an event
|
|
969
|
+
*/
|
|
970
|
+
findCauses(eventId) {
|
|
971
|
+
const graph = this.textGraph.buildGraph([]);
|
|
972
|
+
return this.textGraph.findCauses(graph, eventId);
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Detect anomalies
|
|
976
|
+
*/
|
|
977
|
+
detectAnomalies(events) {
|
|
978
|
+
return this.patternMatcher.detectAnomalies(events);
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Predict next event
|
|
982
|
+
*/
|
|
983
|
+
predictNext(events) {
|
|
984
|
+
return this.patternMatcher.predictNext(events);
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Find important events
|
|
988
|
+
*/
|
|
989
|
+
findImportantEvents(limit = 10) {
|
|
990
|
+
return this.processor.calculatePageRank().slice(0, limit);
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Find clusters
|
|
994
|
+
*/
|
|
995
|
+
findClusters() {
|
|
996
|
+
return this.processor.findClusters();
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Find path between events
|
|
1000
|
+
*/
|
|
1001
|
+
findPath(from, to) {
|
|
1002
|
+
return this.processor.findPath(from, to);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
exports.EventGraph = EventGraph;
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
export default require_dist();
|