openclaw-rollback 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.
@@ -0,0 +1,586 @@
1
+ /**
2
+ * 配置影响图谱模块 (Config Impact Graph)
3
+ *
4
+ * 核心能力:
5
+ * 1. 构建配置项之间的依赖/影响关系图
6
+ * 2. 变更影响传播分析(改了A,会影响哪些B/C/D)
7
+ * 3. 故障根因定位(Gateway挂了,是哪个配置导致的)
8
+ * 4. 可视化数据输出(供WebUI渲染)
9
+ */
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ // ==================== 故障-配置映射知识库 ====================
13
+ /**
14
+ * 故障模式 → 可能相关的配置项
15
+ * 这是基于OpenClaw架构的领域知识
16
+ */
17
+ const FAULT_CONFIG_MAP = {
18
+ 'port_unreachable': {
19
+ nodePatterns: ['gateway.port', 'gateway.host', 'network.*', 'firewall.*'],
20
+ keywords: ['port', 'connect', 'refused', 'unreachable', 'timeout', 'ECONNREFUSED'],
21
+ description: '端口不可达,通常是端口配置或网络问题'
22
+ },
23
+ 'auth_401': {
24
+ nodePatterns: ['auth.token', 'auth.*', 'gateway.auth', 'authentication'],
25
+ keywords: ['401', 'unauthorized', 'token', 'auth', '认证'],
26
+ description: '认证失败,Token过期或被篡改'
27
+ },
28
+ 'auth_403': {
29
+ nodePatterns: ['auth.permissions', 'auth.*', 'gateway.access'],
30
+ keywords: ['403', 'forbidden', 'permission', '权限'],
31
+ description: '权限不足,访问控制配置问题'
32
+ },
33
+ 'process_crash': {
34
+ nodePatterns: ['gateway.workers', 'memory.*', 'plugins.*', 'agents.*'],
35
+ keywords: ['crash', 'panic', 'segfault', 'killed', 'OOM', 'memory'],
36
+ description: '进程崩溃,可能是资源限制或插件冲突'
37
+ },
38
+ 'config_parse_error': {
39
+ nodePatterns: ['*'], // 所有配置都可能
40
+ keywords: ['parse', 'syntax', 'invalid', 'JSON', 'YAML', 'unexpected'],
41
+ description: '配置文件语法错误'
42
+ },
43
+ 'plugin_load_fail': {
44
+ nodePatterns: ['plugins.*', 'extensions.*', 'node_modules'],
45
+ keywords: ['plugin', 'module', 'require', 'import', 'load'],
46
+ description: '插件加载失败'
47
+ },
48
+ 'agent_connect_fail': {
49
+ nodePatterns: ['agents.*', 'gateway.agents', 'network.*'],
50
+ keywords: ['agent', 'connect', 'worker', 'spawn'],
51
+ description: 'Agent连接失败'
52
+ },
53
+ 'skill_execution_error': {
54
+ nodePatterns: ['skills.*', 'agents.*.skills'],
55
+ keywords: ['skill', 'execute', 'tool', 'function'],
56
+ description: 'Skill执行错误'
57
+ }
58
+ };
59
+ // ==================== 配置项影响关系知识库 ====================
60
+ /**
61
+ * 预定义的配置影响关系
62
+ * 基于OpenClaw的架构理解
63
+ */
64
+ const PREDEFINED_EDGES = [
65
+ // Gateway 核心配置影响
66
+ { source: 'gateway.port', target: 'network.listen', type: 'influences', strength: 1.0, description: '端口决定服务监听地址' },
67
+ { source: 'gateway.port', target: 'network.proxy', type: 'influences', strength: 0.8, description: '代理需要知道实际端口' },
68
+ { source: 'gateway.host', target: 'network.bind', type: 'influences', strength: 1.0, description: '绑定地址影响网络可达性' },
69
+ { source: 'gateway.workers', target: 'memory.limit', type: 'influences', strength: 0.7, description: '工作进程数影响内存使用' },
70
+ { source: 'gateway.timeout', target: 'agents.timeout', type: 'influences', strength: 0.6, description: 'Gateway超时影响Agent超时' },
71
+ // 认证配置影响
72
+ { source: 'auth.token', target: 'gateway.auth', type: 'depends_on', strength: 1.0, description: '认证依赖Token配置' },
73
+ { source: 'auth.provider', target: 'auth.token', type: 'influences', strength: 0.9, description: '认证方式影响Token格式' },
74
+ { source: 'auth.expiry', target: 'auth.token', type: 'influences', strength: 0.8, description: '过期时间影响Token有效性' },
75
+ // Agent 配置影响
76
+ { source: 'agents.*.model', target: 'gateway.agents', type: 'influences', strength: 0.7, description: 'Agent模型配置影响Gateway调度' },
77
+ { source: 'agents.*.skills', target: 'skills.*', type: 'references', strength: 0.9, description: 'Agent引用Skill配置' },
78
+ { source: 'agents.*.enabled', target: 'gateway.agents', type: 'influences', strength: 0.8, description: 'Agent开关影响Gateway加载' },
79
+ // Skill 配置影响
80
+ { source: 'skills.*.enabled', target: 'agents.*.skills', type: 'influences', strength: 0.7, description: 'Skill开关影响Agent可用功能' },
81
+ { source: 'skills.*.api_key', target: 'network.external', type: 'depends_on', strength: 0.8, description: '外部API依赖密钥配置' },
82
+ // 插件配置影响
83
+ { source: 'plugins.*', target: 'gateway.plugins', type: 'depends_on', strength: 0.9, description: '插件配置影响Gateway插件加载' },
84
+ { source: 'plugins.*', target: 'memory.limit', type: 'influences', strength: 0.6, description: '插件数量影响内存使用' },
85
+ { source: 'plugins.*.version', target: 'node_modules.*', type: 'depends_on', strength: 0.8, description: '插件版本依赖npm包' },
86
+ // 存储配置影响
87
+ { source: 'storage.path', target: 'backup.location', type: 'influences', strength: 0.9, description: '存储路径影响备份位置' },
88
+ { source: 'storage.maxSize', target: 'memory.cache', type: 'influences', strength: 0.5, description: '存储限制影响缓存策略' },
89
+ ];
90
+ // ==================== 配置解析器 ====================
91
+ /**
92
+ * 解析配置文件,提取所有配置节点
93
+ */
94
+ export function parseConfigFile(filePath) {
95
+ const nodes = [];
96
+ if (!fs.existsSync(filePath))
97
+ return nodes;
98
+ try {
99
+ const content = fs.readFileSync(filePath, 'utf8');
100
+ const ext = path.extname(filePath).toLowerCase();
101
+ let data;
102
+ if (ext === '.json') {
103
+ data = JSON.parse(content);
104
+ }
105
+ else if (ext === '.yaml' || ext === '.yml') {
106
+ // 简化处理,实际项目中可以用 js-yaml
107
+ return nodes;
108
+ }
109
+ else {
110
+ return nodes;
111
+ }
112
+ const fileName = path.basename(filePath);
113
+ extractNodes(data, '', fileName, nodes);
114
+ }
115
+ catch {
116
+ // 解析失败返回空
117
+ }
118
+ return nodes;
119
+ }
120
+ /**
121
+ * 递归提取配置节点
122
+ */
123
+ function extractNodes(obj, prefix, file, nodes) {
124
+ if (typeof obj !== 'object' || obj === null)
125
+ return;
126
+ for (const [key, value] of Object.entries(obj)) {
127
+ const fullPath = prefix ? `${prefix}.${key}` : key;
128
+ const nodeId = fullPath;
129
+ // 确定节点类型
130
+ const type = inferNodeType(key, fullPath);
131
+ nodes.push({
132
+ id: nodeId,
133
+ name: key,
134
+ type,
135
+ file,
136
+ path: fullPath,
137
+ currentValue: typeof value !== 'object' ? value : undefined,
138
+ description: generateDescription(key, fullPath, value)
139
+ });
140
+ // 递归处理子对象
141
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
142
+ extractNodes(value, fullPath, file, nodes);
143
+ }
144
+ }
145
+ }
146
+ /**
147
+ * 推断节点类型
148
+ */
149
+ function inferNodeType(key, fullPath) {
150
+ const lower = fullPath.toLowerCase();
151
+ if (lower.includes('gateway'))
152
+ return 'gateway';
153
+ if (lower.includes('auth') || lower.includes('token') || lower.includes('credential'))
154
+ return 'auth';
155
+ if (lower.includes('agent'))
156
+ return 'agent';
157
+ if (lower.includes('skill'))
158
+ return 'skill';
159
+ if (lower.includes('plugin') || lower.includes('extension'))
160
+ return 'plugin';
161
+ if (lower.includes('port') || lower.includes('host') || lower.includes('network') || lower.includes('proxy'))
162
+ return 'network';
163
+ if (lower.includes('storage') || lower.includes('path') || lower.includes('cache'))
164
+ return 'storage';
165
+ return 'other';
166
+ }
167
+ /**
168
+ * 生成节点描述
169
+ */
170
+ function generateDescription(key, fullPath, value) {
171
+ const descMap = {
172
+ 'gateway.port': 'Gateway服务监听的端口号',
173
+ 'gateway.host': 'Gateway绑定的主机地址',
174
+ 'gateway.workers': 'Gateway工作进程数量',
175
+ 'gateway.timeout': '请求超时时间(秒)',
176
+ 'auth.token': 'API认证令牌',
177
+ 'auth.provider': '认证提供方',
178
+ 'auth.expiry': '令牌过期时间',
179
+ };
180
+ return descMap[fullPath] || `${key}配置项`;
181
+ }
182
+ // ==================== 图谱构建 ====================
183
+ /**
184
+ * 构建完整配置影响图谱
185
+ */
186
+ export function buildConfigGraph(configDir) {
187
+ const nodes = [];
188
+ const edges = [];
189
+ // 1. 扫描所有配置文件
190
+ const configFiles = scanConfigFiles(configDir);
191
+ for (const file of configFiles) {
192
+ const fileNodes = parseConfigFile(file);
193
+ nodes.push(...fileNodes);
194
+ }
195
+ // 2. 添加预定义关系
196
+ for (const preEdge of PREDEFINED_EDGES) {
197
+ // 展开通配符
198
+ const sourceNodes = expandWildcard(preEdge.source, nodes);
199
+ const targetNodes = expandWildcard(preEdge.target, nodes);
200
+ for (const s of sourceNodes) {
201
+ for (const t of targetNodes) {
202
+ if (s !== t) {
203
+ edges.push({
204
+ source: s,
205
+ target: t,
206
+ type: preEdge.type,
207
+ strength: preEdge.strength,
208
+ description: preEdge.description
209
+ });
210
+ }
211
+ }
212
+ }
213
+ }
214
+ // 3. 从配置内容推断关系(引用关系)
215
+ const inferredEdges = inferEdgesFromContent(nodes);
216
+ edges.push(...inferredEdges);
217
+ return {
218
+ nodes,
219
+ edges,
220
+ version: '1.0.0',
221
+ generatedAt: new Date().toISOString()
222
+ };
223
+ }
224
+ /**
225
+ * 扫描配置文件
226
+ */
227
+ function scanConfigFiles(dir) {
228
+ const files = [];
229
+ if (!fs.existsSync(dir))
230
+ return files;
231
+ try {
232
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
233
+ for (const entry of entries) {
234
+ const fullPath = path.join(dir, entry.name);
235
+ if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
236
+ files.push(...scanConfigFiles(fullPath));
237
+ }
238
+ else if (entry.isFile() && (entry.name.endsWith('.json') || entry.name.endsWith('.yaml') || entry.name.endsWith('.yml'))) {
239
+ files.push(fullPath);
240
+ }
241
+ }
242
+ }
243
+ catch {
244
+ // 忽略错误
245
+ }
246
+ return files;
247
+ }
248
+ /**
249
+ * 展开通配符模式
250
+ */
251
+ function expandWildcard(pattern, nodes) {
252
+ if (!pattern.includes('*'))
253
+ return [pattern];
254
+ const regex = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$');
255
+ return nodes.map(n => n.id).filter(id => regex.test(id));
256
+ }
257
+ /**
258
+ * 从配置内容推断关系
259
+ */
260
+ function inferEdgesFromContent(nodes) {
261
+ const edges = [];
262
+ for (const node of nodes) {
263
+ const value = node.currentValue;
264
+ if (typeof value !== 'string')
265
+ continue;
266
+ // 检测引用关系:值中包含其他配置项的ID
267
+ for (const other of nodes) {
268
+ if (other.id === node.id)
269
+ continue;
270
+ if (value.includes(other.id) || value.includes(other.name)) {
271
+ edges.push({
272
+ source: node.id,
273
+ target: other.id,
274
+ type: 'references',
275
+ strength: 0.7,
276
+ description: `${node.id} 引用 ${other.id}`
277
+ });
278
+ }
279
+ }
280
+ }
281
+ return edges;
282
+ }
283
+ // ==================== 影响传播分析 ====================
284
+ /**
285
+ * 分析某个配置变更的影响范围
286
+ */
287
+ export function analyzeImpact(graph, changedNodeId) {
288
+ const visited = new Set();
289
+ const queue = [{ nodeId: changedNodeId, depth: 0 }];
290
+ const directImpacts = [];
291
+ const indirectImpacts = [];
292
+ const affectedFiles = new Set();
293
+ while (queue.length > 0) {
294
+ const { nodeId, depth } = queue.shift();
295
+ if (visited.has(nodeId))
296
+ continue;
297
+ visited.add(nodeId);
298
+ // 找到所有出边(这个节点影响谁)
299
+ const outgoing = graph.edges.filter(e => e.source === nodeId);
300
+ for (const edge of outgoing) {
301
+ if (!visited.has(edge.target)) {
302
+ if (depth === 0) {
303
+ directImpacts.push(edge.target);
304
+ }
305
+ else {
306
+ indirectImpacts.push(edge.target);
307
+ }
308
+ // 找到目标节点所属文件
309
+ const targetNode = graph.nodes.find(n => n.id === edge.target);
310
+ if (targetNode) {
311
+ affectedFiles.add(targetNode.file);
312
+ }
313
+ queue.push({ nodeId: edge.target, depth: depth + 1 });
314
+ }
315
+ }
316
+ }
317
+ // 计算风险评分
318
+ const riskScore = calculateRiskScore(graph, changedNodeId, directImpacts, indirectImpacts);
319
+ // 生成警告
320
+ const warnings = generateWarnings(graph, changedNodeId, directImpacts);
321
+ return {
322
+ changedNode: changedNodeId,
323
+ directImpacts: [...new Set(directImpacts)],
324
+ indirectImpacts: [...new Set(indirectImpacts)],
325
+ riskScore,
326
+ warnings,
327
+ affectedFiles: [...affectedFiles]
328
+ };
329
+ }
330
+ /**
331
+ * 计算风险评分
332
+ */
333
+ function calculateRiskScore(graph, changedNode, direct, indirect) {
334
+ let score = 0;
335
+ // 基础分:影响范围越大风险越高
336
+ score += Math.min(direct.length * 10, 30);
337
+ score += Math.min(indirect.length * 5, 20);
338
+ // 关键配置项变更风险更高
339
+ const criticalNodes = ['gateway.port', 'auth.token', 'gateway.host'];
340
+ if (criticalNodes.includes(changedNode)) {
341
+ score += 30;
342
+ }
343
+ // 涉及认证/网络的变更风险高
344
+ const changed = graph.nodes.find(n => n.id === changedNode);
345
+ if (changed?.type === 'auth' || changed?.type === 'network') {
346
+ score += 15;
347
+ }
348
+ return Math.min(score, 100);
349
+ }
350
+ /**
351
+ * 生成警告信息
352
+ */
353
+ function generateWarnings(graph, changedNode, direct) {
354
+ const warnings = [];
355
+ const changed = graph.nodes.find(n => n.id === changedNode);
356
+ if (changed?.id === 'gateway.port') {
357
+ warnings.push('⚠️ 修改端口号可能导致服务无法访问,请确保新端口未被占用且防火墙已放行');
358
+ }
359
+ if (changed?.id === 'auth.token') {
360
+ warnings.push('⚠️ 修改认证令牌后,所有客户端需要更新Token才能连接');
361
+ }
362
+ if (direct.some(id => id.includes('auth'))) {
363
+ warnings.push('⚠️ 此变更可能影响认证系统,请验证登录功能');
364
+ }
365
+ if (direct.some(id => id.includes('network'))) {
366
+ warnings.push('⚠️ 此变更可能影响网络连接,请测试服务可达性');
367
+ }
368
+ return warnings;
369
+ }
370
+ // ==================== 根因定位引擎 ====================
371
+ /**
372
+ * 故障根因定位主入口
373
+ */
374
+ export function locateRootCause(faultType, faultDetail, recentChanges, graph) {
375
+ // 1. 识别故障模式
376
+ const faultPattern = identifyFaultPattern(faultType, faultDetail);
377
+ // 2. 筛选相关变更
378
+ const relatedChanges = findRelatedChanges(faultPattern, recentChanges, graph);
379
+ // 3. 计算每个候选根因的置信度
380
+ const candidates = calculateCandidateConfidence(faultPattern, relatedChanges, graph);
381
+ // 4. 选择最佳根因
382
+ const bestCandidate = candidates.length > 0 ? candidates[0] : null;
383
+ // 5. 生成修复建议
384
+ const recommendation = generateRecommendation(faultPattern, bestCandidate);
385
+ return {
386
+ faultType,
387
+ faultDetail,
388
+ rootCause: bestCandidate?.node || null,
389
+ confidence: bestCandidate?.confidence || 0,
390
+ relatedChanges: relatedChanges.map(c => ({
391
+ ...c,
392
+ timeBeforeFault: c.timeBeforeFault || 0
393
+ })),
394
+ evidence: generateEvidence(bestCandidate, faultPattern, relatedChanges),
395
+ recommendation
396
+ };
397
+ }
398
+ /**
399
+ * 识别故障模式
400
+ */
401
+ function identifyFaultPattern(faultType, faultDetail) {
402
+ const detail = faultDetail.toLowerCase();
403
+ for (const [pattern, info] of Object.entries(FAULT_CONFIG_MAP)) {
404
+ if (info.keywords.some(k => detail.includes(k) || faultType.includes(k))) {
405
+ return pattern;
406
+ }
407
+ }
408
+ return 'unknown';
409
+ }
410
+ /**
411
+ * 查找相关变更
412
+ */
413
+ function findRelatedChanges(faultPattern, changes, graph) {
414
+ if (faultPattern === 'unknown')
415
+ return changes;
416
+ const pattern = FAULT_CONFIG_MAP[faultPattern];
417
+ if (!pattern)
418
+ return changes;
419
+ return changes.filter(change => {
420
+ // 检查节点ID是否匹配模式
421
+ const matchesPattern = pattern.nodePatterns.some(p => {
422
+ const regex = new RegExp('^' + p.replace(/\*/g, '.*') + '$');
423
+ return regex.test(change.nodeId);
424
+ });
425
+ return matchesPattern;
426
+ });
427
+ }
428
+ /**
429
+ * 计算候选根因置信度
430
+ */
431
+ function calculateCandidateConfidence(faultPattern, relatedChanges, graph) {
432
+ const candidates = [];
433
+ // 按节点分组
434
+ const grouped = new Map();
435
+ for (const change of relatedChanges) {
436
+ if (!grouped.has(change.nodeId)) {
437
+ grouped.set(change.nodeId, []);
438
+ }
439
+ grouped.get(change.nodeId).push(change);
440
+ }
441
+ for (const [nodeId, changes] of grouped) {
442
+ const node = graph.nodes.find(n => n.id === nodeId);
443
+ if (!node)
444
+ continue;
445
+ let confidence = 0;
446
+ const reasons = [];
447
+ // 因素1:时间接近度(越近越可疑)
448
+ const minTimeBefore = Math.min(...changes.map(c => c.timeBeforeFault || Infinity));
449
+ if (minTimeBefore < 300) { // 5分钟内
450
+ confidence += 0.4;
451
+ reasons.push(`该配置在故障前${Math.round(minTimeBefore)}秒被修改,时间非常接近`);
452
+ }
453
+ else if (minTimeBefore < 3600) { // 1小时内
454
+ confidence += 0.25;
455
+ reasons.push(`该配置在故障前${Math.round(minTimeBefore / 60)}分钟被修改`);
456
+ }
457
+ // 因素2:变更次数(修改次数越多越可疑)
458
+ if (changes.length > 1) {
459
+ confidence += 0.15;
460
+ reasons.push(`该配置在短时间内被修改了${changes.length}次`);
461
+ }
462
+ // 因素3:节点类型匹配度
463
+ const pattern = FAULT_CONFIG_MAP[faultPattern];
464
+ if (pattern && pattern.nodePatterns.some(p => {
465
+ const regex = new RegExp('^' + p.replace(/\*/g, '.*') + '$');
466
+ return regex.test(nodeId);
467
+ })) {
468
+ confidence += 0.3;
469
+ reasons.push(`该配置项(${node.type})与故障模式(${pattern.description})高度相关`);
470
+ }
471
+ // 因素4:节点关键度
472
+ if (['gateway.port', 'auth.token', 'gateway.host'].includes(nodeId)) {
473
+ confidence += 0.1;
474
+ reasons.push('该配置属于系统关键配置');
475
+ }
476
+ candidates.push({ node, confidence: Math.min(confidence, 1.0), reasons });
477
+ }
478
+ // 按置信度排序
479
+ return candidates.sort((a, b) => b.confidence - a.confidence);
480
+ }
481
+ /**
482
+ * 生成证据链
483
+ */
484
+ function generateEvidence(bestCandidate, faultPattern, changes) {
485
+ const evidence = [];
486
+ const pattern = FAULT_CONFIG_MAP[faultPattern];
487
+ if (pattern) {
488
+ evidence.push(`故障模式识别: ${pattern.description}`);
489
+ }
490
+ if (bestCandidate) {
491
+ evidence.push(...bestCandidate.reasons);
492
+ }
493
+ // 时间线证据
494
+ const sortedChanges = [...changes].sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
495
+ for (const change of sortedChanges.slice(0, 3)) {
496
+ evidence.push(`[${new Date(change.timestamp).toLocaleString()}] ${change.file} 中 ${change.nodeId} ` +
497
+ `从 "${JSON.stringify(change.oldValue)}" 改为 "${JSON.stringify(change.newValue)}"`);
498
+ }
499
+ return evidence;
500
+ }
501
+ /**
502
+ * 生成修复建议
503
+ */
504
+ function generateRecommendation(faultPattern, candidate) {
505
+ if (!candidate) {
506
+ return '无法定位具体根因,建议查看完整配置变更历史,或执行全量回滚到上一个已知正常版本。';
507
+ }
508
+ const recommendations = {
509
+ 'port_unreachable': `检查 ${candidate.node.id} 的值是否正确,确认端口未被占用且防火墙已放行。可尝试改回之前的值。`,
510
+ 'auth_401': `检查 ${candidate.node.id} 是否过期或被篡改。尝试刷新Token或恢复之前的认证配置。`,
511
+ 'auth_403': `检查 ${candidate.node.id} 的权限配置,确认当前用户有访问权限。`,
512
+ 'process_crash': `检查 ${candidate.node.id} 的值是否合理,可能是资源限制过低或插件冲突导致。`,
513
+ 'config_parse_error': `检查 ${candidate.node.id} 的语法是否正确,特别注意JSON/YAML格式。`,
514
+ 'plugin_load_fail': `检查 ${candidate.node.id} 是否正确安装,版本是否兼容。`,
515
+ };
516
+ return recommendations[faultPattern] || `建议检查 ${candidate.node.id} 的配置,或回滚到上一个已知正常版本。`;
517
+ }
518
+ // ==================== 变更历史追踪 ====================
519
+ const CHANGE_LOG_FILE = path.join(process.env.HOME || process.env.USERPROFILE || '', '.openclaw', 'extensions', 'openclaw-rollback', 'change-log.json');
520
+ /**
521
+ * 记录配置变更
522
+ */
523
+ export function recordChange(change) {
524
+ try {
525
+ const dir = path.dirname(CHANGE_LOG_FILE);
526
+ if (!fs.existsSync(dir)) {
527
+ fs.mkdirSync(dir, { recursive: true });
528
+ }
529
+ let changes = [];
530
+ if (fs.existsSync(CHANGE_LOG_FILE)) {
531
+ changes = JSON.parse(fs.readFileSync(CHANGE_LOG_FILE, 'utf8'));
532
+ }
533
+ changes.push(change);
534
+ // 只保留最近100条
535
+ if (changes.length > 100) {
536
+ changes = changes.slice(-100);
537
+ }
538
+ fs.writeFileSync(CHANGE_LOG_FILE, JSON.stringify(changes, null, 2));
539
+ }
540
+ catch {
541
+ // 忽略记录错误
542
+ }
543
+ }
544
+ /**
545
+ * 读取变更历史
546
+ */
547
+ export function readChangeHistory(limit = 50) {
548
+ try {
549
+ if (!fs.existsSync(CHANGE_LOG_FILE))
550
+ return [];
551
+ const changes = JSON.parse(fs.readFileSync(CHANGE_LOG_FILE, 'utf8'));
552
+ return changes.slice(-limit);
553
+ }
554
+ catch {
555
+ return [];
556
+ }
557
+ }
558
+ // ==================== 导出便捷函数 ====================
559
+ /**
560
+ * 获取完整的根因分析报告(供WebUI使用)
561
+ */
562
+ export function getRootCauseReport(faultType, faultDetail, configDir) {
563
+ const graph = buildConfigGraph(configDir);
564
+ const changes = readChangeHistory();
565
+ // 计算距离故障的时间
566
+ const now = Date.now();
567
+ const changesWithTime = changes.map(c => ({
568
+ ...c,
569
+ timeBeforeFault: (now - new Date(c.timestamp).getTime()) / 1000
570
+ }));
571
+ return locateRootCause(faultType, faultDetail, changesWithTime, graph);
572
+ }
573
+ /**
574
+ * 获取影响分析(供WebUI使用)
575
+ */
576
+ export function getImpactReport(configDir, changedNodeId) {
577
+ const graph = buildConfigGraph(configDir);
578
+ return analyzeImpact(graph, changedNodeId);
579
+ }
580
+ /**
581
+ * 获取完整图谱(供WebUI可视化使用)
582
+ */
583
+ export function getFullGraph(configDir) {
584
+ return buildConfigGraph(configDir);
585
+ }
586
+ //# sourceMappingURL=config-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-graph.js","sourceRoot":"","sources":["../src/config-graph.ts"],"names":[],"mappings":"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"}