autosnippet 3.3.7 → 3.3.8
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 +1 -0
- package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
- package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
- package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +7 -4
- package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
- package/dist/lib/agent/core/LoopContext.d.ts +1 -0
- package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
- package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
- package/dist/lib/agent/memory/ActiveContext.js +0 -2
- package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
- package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
- package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
- package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
- package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
- package/dist/lib/agent/memory/MemoryStore.js +196 -261
- package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
- package/dist/lib/agent/memory/PersistentMemory.js +4 -5
- package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
- package/dist/lib/agent/memory/SessionStore.js +0 -2
- package/dist/lib/agent/tools/ast-graph.js +21 -19
- package/dist/lib/agent/tools/infrastructure.js +3 -2
- package/dist/lib/agent/tools/project-access.d.ts +2 -2
- package/dist/lib/agent/tools/project-access.js +5 -4
- package/dist/lib/bootstrap.js +2 -1
- package/dist/lib/cli/AiScanService.js +4 -17
- package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
- package/dist/lib/cli/KnowledgeSyncService.js +23 -51
- package/dist/lib/core/ast/ProjectGraph.js +5 -27
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +0 -2
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
- package/dist/lib/domain/dimension/DimensionSop.js +44 -33
- package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
- package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
- package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
- package/dist/lib/domain/knowledge/index.d.ts +2 -1
- package/dist/lib/domain/knowledge/index.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +33 -16
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +7 -3
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +13 -16
- package/dist/lib/external/mcp/handlers/guard.js +15 -24
- package/dist/lib/external/mcp/handlers/panorama.js +9 -9
- package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
- package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
- package/dist/lib/external/mcp/handlers/search.js +3 -1
- package/dist/lib/external/mcp/handlers/skill.js +4 -4
- package/dist/lib/external/mcp/handlers/structure.js +8 -12
- package/dist/lib/external/mcp/handlers/system.js +10 -34
- package/dist/lib/http/routes/ai.js +11 -13
- package/dist/lib/http/routes/guardReport.js +3 -5
- package/dist/lib/http/routes/panorama.js +12 -12
- package/dist/lib/http/routes/recipes.js +59 -8
- package/dist/lib/http/routes/remote.js +3 -13
- package/dist/lib/http/routes/search.js +11 -8
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
- package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
- package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
- package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
- package/dist/lib/injection/ServiceContainer.js +7 -4
- package/dist/lib/injection/ServiceMap.d.ts +20 -0
- package/dist/lib/injection/modules/AppModule.js +2 -1
- package/dist/lib/injection/modules/GuardModule.js +5 -5
- package/dist/lib/injection/modules/InfraModule.js +60 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
- package/dist/lib/injection/modules/PanoramaModule.js +16 -10
- package/dist/lib/injection/modules/VectorModule.js +3 -0
- package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
- package/dist/lib/repository/audit/AuditRepository.js +272 -0
- package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
- package/dist/lib/repository/base/RepositoryBase.js +32 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
- package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
- package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
- package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
- package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
- package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
- package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
- package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
- package/dist/lib/repository/memory/MemoryRepository.js +260 -0
- package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
- package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
- package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
- package/dist/lib/repository/session/SessionRepository.js +110 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
- package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
- package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
- package/dist/lib/service/cleanup/CleanupService.js +8 -4
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
- package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
- package/dist/lib/service/evolution/ContentPatcher.js +48 -19
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
- package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
- package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
- package/dist/lib/service/evolution/DecayDetector.js +63 -57
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
- package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
- package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
- package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
- package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
- package/dist/lib/service/evolution/StagingManager.js +37 -95
- package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
- package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
- package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
- package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
- package/dist/lib/service/guard/ReverseGuard.js +21 -31
- package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
- package/dist/lib/service/guard/ViolationsStore.js +75 -69
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +39 -63
- package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -512
- package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
- package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
- package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
- package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
- package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
- package/dist/lib/service/knowledge/KnowledgeService.js +76 -38
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
- package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +5 -3
- package/dist/lib/service/panorama/CouplingAnalyzer.js +102 -39
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
- package/dist/lib/service/panorama/DimensionAnalyzer.js +72 -25
- package/dist/lib/service/panorama/LayerInferrer.js +1 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +7 -6
- package/dist/lib/service/panorama/ModuleDiscoverer.js +174 -82
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +10 -3
- package/dist/lib/service/panorama/PanoramaAggregator.js +67 -79
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
- package/dist/lib/service/panorama/PanoramaScanner.js +32 -31
- package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
- package/dist/lib/service/panorama/PanoramaService.js +41 -66
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +3 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +8 -5
- package/dist/lib/service/panorama/RoleRefiner.js +52 -283
- package/dist/lib/service/panorama/TechStackProfiler.js +7 -119
- package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
- package/dist/lib/service/quality/QualityScorer.js +157 -83
- package/dist/lib/service/search/SearchEngine.d.ts +1 -0
- package/dist/lib/service/search/SearchEngine.js +32 -37
- package/dist/lib/service/signal/HitRecorder.js +5 -5
- package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
- package/dist/lib/service/skills/SignalCollector.d.ts +5 -8
- package/dist/lib/service/skills/SignalCollector.js +28 -55
- package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
- package/dist/lib/service/skills/SkillAdvisor.js +30 -79
- package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
- package/dist/lib/service/vector/SyncCoordinator.js +25 -3
- package/dist/lib/service/vector/VectorService.d.ts +2 -0
- package/dist/lib/service/vector/VectorService.js +3 -0
- package/dist/lib/service/wiki/WikiGenerator.js +1 -1
- package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
- package/dist/lib/shared/LanguageProfiles.js +939 -0
- package/dist/lib/shared/LanguageService.d.ts +6 -0
- package/dist/lib/shared/LanguageService.js +16 -0
- package/dist/lib/shared/constants.d.ts +19 -19
- package/dist/lib/shared/constants.js +10 -10
- package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
- package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
- package/dist/lib/types/project-snapshot-builder.js +0 -1
- package/dist/lib/types/project-snapshot.d.ts +0 -1
- package/dist/lib/types/project-snapshot.js +0 -1
- package/dist/lib/types/snapshot-views.d.ts +0 -2
- package/dist/lib/types/snapshot-views.js +0 -1
- package/package.json +2 -1
- package/dashboard/dist/assets/icons-FHns2ypa.js +0 -1
- package/dashboard/dist/assets/index-BRJv5Y3r.js +0 -135
- package/dashboard/dist/assets/index-DzoB7kxK.css +0 -1
- package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
- package/dist/lib/repository/base/BaseRepository.js +0 -226
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* 此路由仅处理 Recipe 特有的批量 AI 操作。
|
|
7
7
|
*/
|
|
8
8
|
import express from 'express';
|
|
9
|
+
import { COUNTABLE_LIFECYCLES } from '../../domain/knowledge/Lifecycle.js';
|
|
9
10
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
10
11
|
import { getServiceContainer } from '../../injection/ServiceContainer.js';
|
|
11
12
|
const router = express.Router();
|
|
@@ -77,11 +78,10 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
77
78
|
data: { status: 'error', error: 'AI Provider 未配置,当前为 Mock 模式。请先配置 API Key。' },
|
|
78
79
|
});
|
|
79
80
|
}
|
|
80
|
-
// 快速检查:至少需要 2
|
|
81
|
+
// 快速检查:至少需要 2 条可消费 Recipe(active/staging/pending/evolving)
|
|
81
82
|
try {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const count = items.length || data.length;
|
|
83
|
+
const knowledgeRepo = container.get('knowledgeRepository');
|
|
84
|
+
const count = await knowledgeRepo.countByLifecycles(COUNTABLE_LIFECYCLES);
|
|
85
85
|
if (count < 2) {
|
|
86
86
|
return void res.json({
|
|
87
87
|
success: true,
|
|
@@ -93,7 +93,7 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
catch {
|
|
96
|
-
//
|
|
96
|
+
// 如果查询失败,继续尝试(让 runTask 给出具体错误)
|
|
97
97
|
}
|
|
98
98
|
// 重置并启动后台任务
|
|
99
99
|
resetTask();
|
|
@@ -103,11 +103,62 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
103
103
|
(async () => {
|
|
104
104
|
try {
|
|
105
105
|
const result = await agentFactory.discoverRelations();
|
|
106
|
+
const relations = result.relations || [];
|
|
107
|
+
const analyzed = result.analyzed || 0;
|
|
108
|
+
// 将 AI 发现的关系写入知识图谱
|
|
109
|
+
// AI 返回的 from/to 是 Recipe 标题,需要解析为实际 ID
|
|
110
|
+
let written = 0;
|
|
111
|
+
if (relations.length > 0) {
|
|
112
|
+
try {
|
|
113
|
+
const graphService = container.get('knowledgeGraphService');
|
|
114
|
+
const knowledgeRepo = container.get('knowledgeRepository');
|
|
115
|
+
// 缓存标题 → ID 映射,避免重复查询
|
|
116
|
+
const titleToId = new Map();
|
|
117
|
+
const resolveId = async (title) => {
|
|
118
|
+
if (titleToId.has(title)) {
|
|
119
|
+
return titleToId.get(title);
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const entry = await knowledgeRepo.findByTitle(title);
|
|
123
|
+
const id = entry?.id ?? null;
|
|
124
|
+
titleToId.set(title, id);
|
|
125
|
+
return id;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
titleToId.set(title, null);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
for (const rel of relations) {
|
|
133
|
+
if (!rel.from || !rel.to || !rel.type) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const fromId = await resolveId(rel.from);
|
|
137
|
+
const toId = await resolveId(rel.to);
|
|
138
|
+
if (!fromId || !toId) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const res = await graphService.addEdge(fromId, 'recipe', toId, 'recipe', rel.type, {
|
|
142
|
+
weight: 0.7,
|
|
143
|
+
source: 'ai-discovery',
|
|
144
|
+
evidence: rel.evidence || '',
|
|
145
|
+
});
|
|
146
|
+
if (res.success) {
|
|
147
|
+
written++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (graphErr) {
|
|
152
|
+
logger.warn('Failed to write some discovered edges', {
|
|
153
|
+
error: graphErr.message,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
106
157
|
discoverTask.status = 'done';
|
|
107
158
|
discoverTask.finishedAt = new Date().toISOString();
|
|
108
|
-
discoverTask.discovered =
|
|
109
|
-
discoverTask.totalPairs =
|
|
110
|
-
discoverTask.batchErrors =
|
|
159
|
+
discoverTask.discovered = written;
|
|
160
|
+
discoverTask.totalPairs = analyzed;
|
|
161
|
+
discoverTask.batchErrors = relations.length - written;
|
|
111
162
|
discoverTask.elapsed = Math.round((new Date(discoverTask.finishedAt).getTime() - new Date(discoverTask.startedAt).getTime()) /
|
|
112
163
|
1000);
|
|
113
164
|
logger.info('Discover relations completed', {
|
|
@@ -21,7 +21,6 @@ import express from 'express';
|
|
|
21
21
|
import { LarkTransport } from '../../external/lark/LarkTransport.js';
|
|
22
22
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
23
23
|
import { getServiceContainer } from '../../injection/ServiceContainer.js';
|
|
24
|
-
import { RemoteCommandRepository, } from '../../repository/remote/RemoteCommandRepository.js';
|
|
25
24
|
import { resolveProjectRoot } from '../../shared/resolveProjectRoot.js';
|
|
26
25
|
import { RemoteHistoryQuery, RemoteNotifyBody, RemoteResultBody, RemoteSendBody, } from '../../shared/schemas/http-requests.js';
|
|
27
26
|
import { validate, validateQuery } from '../middleware/validate.js';
|
|
@@ -32,19 +31,10 @@ const PENDING_TIMEOUT_SEC = 120; // pending 超过 2 分钟 → timeout
|
|
|
32
31
|
const RUNNING_TIMEOUT_SEC = 600; // running 超过 10 分钟 → timeout
|
|
33
32
|
const CLEANUP_INTERVAL_MS = 30_000; // 每 30 秒清理一次
|
|
34
33
|
// ─── 数据库辅助 ─────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
const container = getServiceContainer();
|
|
37
|
-
const database = container.get('database');
|
|
38
|
-
return typeof database?.getDb === 'function' ? database.getDb() : database;
|
|
39
|
-
}
|
|
40
|
-
let _repo = null;
|
|
41
|
-
/** 获取或创建 RemoteCommandRepository 单例 */
|
|
34
|
+
/** 从 DI 容器获取 RemoteCommandRepository */
|
|
42
35
|
function getRepo() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_repo = new RemoteCommandRepository(db);
|
|
46
|
-
}
|
|
47
|
-
return _repo;
|
|
36
|
+
const container = getServiceContainer();
|
|
37
|
+
return container.get('remoteCommandRepository');
|
|
48
38
|
}
|
|
49
39
|
function genId() {
|
|
50
40
|
return `rcmd_${Date.now().toString(36)}_${crypto.randomBytes(3).toString('hex')}`;
|
|
@@ -98,8 +98,8 @@ router.get('/graph', validateQuery(GraphQuery), async (req, res) => {
|
|
|
98
98
|
return void res.json({ success: true, data: { outgoing: [], incoming: [] } });
|
|
99
99
|
}
|
|
100
100
|
const edges = relation
|
|
101
|
-
? graphService.getRelated(nodeId, nodeType, relation)
|
|
102
|
-
: graphService.getEdges(nodeId, nodeType, direction);
|
|
101
|
+
? await graphService.getRelated(nodeId, nodeType, relation)
|
|
102
|
+
: await graphService.getEdges(nodeId, nodeType, direction);
|
|
103
103
|
res.json({ success: true, data: edges });
|
|
104
104
|
});
|
|
105
105
|
/**
|
|
@@ -114,7 +114,7 @@ router.get('/graph/impact', validateQuery(GraphImpactQuery), async (req, res) =>
|
|
|
114
114
|
if (!graphService) {
|
|
115
115
|
return void res.json({ success: true, data: [] });
|
|
116
116
|
}
|
|
117
|
-
const impact = graphService.getImpactAnalysis(nodeId, nodeType, maxDepth);
|
|
117
|
+
const impact = await graphService.getImpactAnalysis(nodeId, nodeType, maxDepth);
|
|
118
118
|
res.json({ success: true, data: impact });
|
|
119
119
|
});
|
|
120
120
|
/**
|
|
@@ -129,9 +129,11 @@ router.get('/graph/all', async (req, res) => {
|
|
|
129
129
|
if (!graphService) {
|
|
130
130
|
return void res.json({ success: true, data: { edges: [], nodeLabels: {} } });
|
|
131
131
|
}
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
const
|
|
132
|
+
// 默认不过滤 nodeType,返回所有知识相关边(recipe + knowledge)
|
|
133
|
+
// 仅当显式指定 nodeType 时才过滤(module 类由 /spm/dep-graph 提供)
|
|
134
|
+
const rawNodeType = req.query.nodeType;
|
|
135
|
+
const nodeType = rawNodeType === 'all' ? undefined : rawNodeType || undefined;
|
|
136
|
+
const edges = await graphService.getAllEdges(limit, nodeType);
|
|
135
137
|
// 收集节点 ID + 类型 → 按类型查标签
|
|
136
138
|
const nodeMap = new Map(); // id → Set<type>
|
|
137
139
|
for (const e of edges) {
|
|
@@ -183,8 +185,9 @@ router.get('/graph/stats', async (req, res) => {
|
|
|
183
185
|
data: { totalEdges: 0, byRelation: {}, nodeTypes: [] },
|
|
184
186
|
});
|
|
185
187
|
}
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
+
const rawStatsType = req.query.nodeType;
|
|
189
|
+
const statsNodeType = rawStatsType === 'all' ? undefined : rawStatsType || undefined;
|
|
190
|
+
const stats = await graphService.getStats(statsNodeType);
|
|
188
191
|
res.json({ success: true, data: stats });
|
|
189
192
|
});
|
|
190
193
|
/**
|
|
@@ -41,7 +41,18 @@ export declare class AuditLogger {
|
|
|
41
41
|
startDate?: number;
|
|
42
42
|
endDate?: number;
|
|
43
43
|
limit?: number;
|
|
44
|
-
}): Promise<
|
|
44
|
+
}): Promise<{
|
|
45
|
+
id: string;
|
|
46
|
+
timestamp: number;
|
|
47
|
+
actor: string;
|
|
48
|
+
actorContext: string | null;
|
|
49
|
+
action: string;
|
|
50
|
+
resource: string | null;
|
|
51
|
+
operationData: string | null;
|
|
52
|
+
result: string;
|
|
53
|
+
errorMessage: string | null;
|
|
54
|
+
duration: number | null;
|
|
55
|
+
}[]>;
|
|
45
56
|
/** 获取特定请求的日志 */
|
|
46
57
|
getByRequestId(requestId: string): Promise<{
|
|
47
58
|
id: string;
|
|
@@ -102,8 +113,14 @@ export declare class AuditLogger {
|
|
|
102
113
|
failure: number;
|
|
103
114
|
successRate: string;
|
|
104
115
|
avgDuration: string;
|
|
105
|
-
byActor:
|
|
106
|
-
|
|
116
|
+
byActor: {
|
|
117
|
+
actor: string;
|
|
118
|
+
count: number;
|
|
119
|
+
}[];
|
|
120
|
+
byAction: {
|
|
121
|
+
action: string;
|
|
122
|
+
count: number;
|
|
123
|
+
}[];
|
|
107
124
|
}>;
|
|
108
125
|
}
|
|
109
126
|
export default AuditLogger;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import type { DrizzleDB } from '../database/drizzle/index.js';
|
|
2
2
|
export declare class AuditStore {
|
|
3
3
|
#private;
|
|
4
|
-
db: import('better-sqlite3').Database;
|
|
5
4
|
constructor(db: {
|
|
6
5
|
getDb: () => import('better-sqlite3').Database;
|
|
7
6
|
}, drizzle?: DrizzleDB);
|
|
8
|
-
/**
|
|
9
|
-
* 保存审计日志
|
|
10
|
-
* ★ Drizzle 类型安全 INSERT
|
|
11
|
-
*/
|
|
7
|
+
/** 保存审计日志 */
|
|
12
8
|
save(entry: {
|
|
13
9
|
id: string;
|
|
14
10
|
timestamp: number;
|
|
@@ -21,7 +17,7 @@ export declare class AuditStore {
|
|
|
21
17
|
error_message: string | null;
|
|
22
18
|
duration: number | null;
|
|
23
19
|
}): Promise<void>;
|
|
24
|
-
/**
|
|
20
|
+
/** 查询审计日志(动态多条件,全 Drizzle) */
|
|
25
21
|
query(filters?: {
|
|
26
22
|
actor?: string;
|
|
27
23
|
action?: string;
|
|
@@ -29,11 +25,19 @@ export declare class AuditStore {
|
|
|
29
25
|
startDate?: number;
|
|
30
26
|
endDate?: number;
|
|
31
27
|
limit?: number;
|
|
32
|
-
}):
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
}): {
|
|
29
|
+
id: string;
|
|
30
|
+
timestamp: number;
|
|
31
|
+
actor: string;
|
|
32
|
+
actorContext: string | null;
|
|
33
|
+
action: string;
|
|
34
|
+
resource: string | null;
|
|
35
|
+
operationData: string | null;
|
|
36
|
+
result: string;
|
|
37
|
+
errorMessage: string | null;
|
|
38
|
+
duration: number | null;
|
|
39
|
+
}[];
|
|
40
|
+
/** 根据请求 ID 查询 */
|
|
37
41
|
findByRequestId(requestId: string): {
|
|
38
42
|
id: string;
|
|
39
43
|
timestamp: number;
|
|
@@ -46,10 +50,7 @@ export declare class AuditStore {
|
|
|
46
50
|
errorMessage: string | null;
|
|
47
51
|
duration: number | null;
|
|
48
52
|
} | undefined;
|
|
49
|
-
/**
|
|
50
|
-
* 根据角色查询
|
|
51
|
-
* ★ Drizzle 类型安全 SELECT
|
|
52
|
-
*/
|
|
53
|
+
/** 根据角色查询 */
|
|
53
54
|
findByActor(actor: string, limit?: number): {
|
|
54
55
|
id: string;
|
|
55
56
|
timestamp: number;
|
|
@@ -62,10 +63,7 @@ export declare class AuditStore {
|
|
|
62
63
|
errorMessage: string | null;
|
|
63
64
|
duration: number | null;
|
|
64
65
|
}[];
|
|
65
|
-
/**
|
|
66
|
-
* 根据操作查询
|
|
67
|
-
* ★ Drizzle 类型安全 SELECT
|
|
68
|
-
*/
|
|
66
|
+
/** 根据操作查询 */
|
|
69
67
|
findByAction(action: string, limit?: number): {
|
|
70
68
|
id: string;
|
|
71
69
|
timestamp: number;
|
|
@@ -78,10 +76,7 @@ export declare class AuditStore {
|
|
|
78
76
|
errorMessage: string | null;
|
|
79
77
|
duration: number | null;
|
|
80
78
|
}[];
|
|
81
|
-
/**
|
|
82
|
-
* 根据结果查询
|
|
83
|
-
* ★ Drizzle 类型安全 SELECT
|
|
84
|
-
*/
|
|
79
|
+
/** 根据结果查询 */
|
|
85
80
|
findByResult(result: string, limit?: number): {
|
|
86
81
|
id: string;
|
|
87
82
|
timestamp: number;
|
|
@@ -94,7 +89,7 @@ export declare class AuditStore {
|
|
|
94
89
|
errorMessage: string | null;
|
|
95
90
|
duration: number | null;
|
|
96
91
|
}[];
|
|
97
|
-
/**
|
|
92
|
+
/** 获取统计数据(全 Drizzle) */
|
|
98
93
|
getStats(timeRange?: string): {
|
|
99
94
|
timeRange: string;
|
|
100
95
|
total: number;
|
|
@@ -102,14 +97,18 @@ export declare class AuditStore {
|
|
|
102
97
|
failure: number;
|
|
103
98
|
successRate: string;
|
|
104
99
|
avgDuration: string;
|
|
105
|
-
byActor:
|
|
106
|
-
|
|
100
|
+
byActor: {
|
|
101
|
+
actor: string;
|
|
102
|
+
count: number;
|
|
103
|
+
}[];
|
|
104
|
+
byAction: {
|
|
105
|
+
action: string;
|
|
106
|
+
count: number;
|
|
107
|
+
}[];
|
|
107
108
|
};
|
|
108
109
|
/**
|
|
109
110
|
* 清理过期审计日志
|
|
110
|
-
*
|
|
111
|
-
* @param [opts.maxAgeDays=90] 保留天数,超过此天数的记录将被删除
|
|
112
|
-
* @returns }
|
|
111
|
+
* @param [opts.maxAgeDays=90] 保留天数
|
|
113
112
|
*/
|
|
114
113
|
cleanup({ maxAgeDays }?: {
|
|
115
114
|
maxAgeDays?: number | undefined;
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
/** AuditStore -
|
|
2
|
-
import { desc, eq, sql } from 'drizzle-orm';
|
|
1
|
+
/** AuditStore - 审计日志存储(全 Drizzle 类型安全) */
|
|
2
|
+
import { and, avg, count, desc, eq, gte, lte, sql } from 'drizzle-orm';
|
|
3
3
|
import { getDrizzle } from '../database/drizzle/index.js';
|
|
4
4
|
import { auditLogs } from '../database/drizzle/schema.js';
|
|
5
5
|
export class AuditStore {
|
|
6
|
-
db;
|
|
7
6
|
#drizzle;
|
|
8
7
|
constructor(db, drizzle) {
|
|
9
|
-
this.db = db.getDb();
|
|
10
8
|
this.#drizzle = drizzle ?? getDrizzle();
|
|
11
9
|
}
|
|
12
|
-
/**
|
|
13
|
-
* 保存审计日志
|
|
14
|
-
* ★ Drizzle 类型安全 INSERT
|
|
15
|
-
*/
|
|
10
|
+
/** 保存审计日志 */
|
|
16
11
|
async save(entry) {
|
|
17
12
|
this.#drizzle
|
|
18
13
|
.insert(auditLogs)
|
|
@@ -30,49 +25,40 @@ export class AuditStore {
|
|
|
30
25
|
})
|
|
31
26
|
.run();
|
|
32
27
|
}
|
|
33
|
-
/**
|
|
28
|
+
/** 查询审计日志(动态多条件,全 Drizzle) */
|
|
34
29
|
query(filters = {}) {
|
|
35
|
-
|
|
36
|
-
const params = [];
|
|
30
|
+
const conditions = [];
|
|
37
31
|
if (filters.actor) {
|
|
38
|
-
|
|
39
|
-
params.push(filters.actor);
|
|
32
|
+
conditions.push(eq(auditLogs.actor, filters.actor));
|
|
40
33
|
}
|
|
41
34
|
if (filters.action) {
|
|
42
|
-
|
|
43
|
-
params.push(filters.action);
|
|
35
|
+
conditions.push(eq(auditLogs.action, filters.action));
|
|
44
36
|
}
|
|
45
37
|
if (filters.result) {
|
|
46
|
-
|
|
47
|
-
params.push(filters.result);
|
|
38
|
+
conditions.push(eq(auditLogs.result, filters.result));
|
|
48
39
|
}
|
|
49
40
|
if (filters.startDate) {
|
|
50
|
-
|
|
51
|
-
params.push(filters.startDate);
|
|
41
|
+
conditions.push(gte(auditLogs.timestamp, filters.startDate));
|
|
52
42
|
}
|
|
53
43
|
if (filters.endDate) {
|
|
54
|
-
|
|
55
|
-
params.push(filters.endDate);
|
|
44
|
+
conditions.push(lte(auditLogs.timestamp, filters.endDate));
|
|
56
45
|
}
|
|
57
|
-
|
|
46
|
+
const condition = conditions.length > 0 ? and(...conditions) : undefined;
|
|
47
|
+
let query = this.#drizzle
|
|
48
|
+
.select()
|
|
49
|
+
.from(auditLogs)
|
|
50
|
+
.where(condition)
|
|
51
|
+
.orderBy(desc(auditLogs.timestamp));
|
|
58
52
|
if (filters.limit) {
|
|
59
|
-
|
|
60
|
-
params.push(filters.limit);
|
|
53
|
+
query = query.limit(filters.limit);
|
|
61
54
|
}
|
|
62
|
-
|
|
63
|
-
return stmt.all(...params);
|
|
55
|
+
return query.all();
|
|
64
56
|
}
|
|
65
|
-
/**
|
|
66
|
-
* 根据请求 ID 查询
|
|
67
|
-
* ★ Drizzle 类型安全 SELECT
|
|
68
|
-
*/
|
|
57
|
+
/** 根据请求 ID 查询 */
|
|
69
58
|
findByRequestId(requestId) {
|
|
70
59
|
return this.#drizzle.select().from(auditLogs).where(eq(auditLogs.id, requestId)).get();
|
|
71
60
|
}
|
|
72
|
-
/**
|
|
73
|
-
* 根据角色查询
|
|
74
|
-
* ★ Drizzle 类型安全 SELECT
|
|
75
|
-
*/
|
|
61
|
+
/** 根据角色查询 */
|
|
76
62
|
findByActor(actor, limit = 100) {
|
|
77
63
|
return this.#drizzle
|
|
78
64
|
.select()
|
|
@@ -82,10 +68,7 @@ export class AuditStore {
|
|
|
82
68
|
.limit(limit)
|
|
83
69
|
.all();
|
|
84
70
|
}
|
|
85
|
-
/**
|
|
86
|
-
* 根据操作查询
|
|
87
|
-
* ★ Drizzle 类型安全 SELECT
|
|
88
|
-
*/
|
|
71
|
+
/** 根据操作查询 */
|
|
89
72
|
findByAction(action, limit = 100) {
|
|
90
73
|
return this.#drizzle
|
|
91
74
|
.select()
|
|
@@ -95,10 +78,7 @@ export class AuditStore {
|
|
|
95
78
|
.limit(limit)
|
|
96
79
|
.all();
|
|
97
80
|
}
|
|
98
|
-
/**
|
|
99
|
-
* 根据结果查询
|
|
100
|
-
* ★ Drizzle 类型安全 SELECT
|
|
101
|
-
*/
|
|
81
|
+
/** 根据结果查询 */
|
|
102
82
|
findByResult(result, limit = 100) {
|
|
103
83
|
return this.#drizzle
|
|
104
84
|
.select()
|
|
@@ -108,66 +88,79 @@ export class AuditStore {
|
|
|
108
88
|
.limit(limit)
|
|
109
89
|
.all();
|
|
110
90
|
}
|
|
111
|
-
/**
|
|
91
|
+
/** 获取统计数据(全 Drizzle) */
|
|
112
92
|
getStats(timeRange = '24h') {
|
|
113
|
-
// 计算时间范围
|
|
114
93
|
const hours = timeRange === '24h' ? 24 : timeRange === '7d' ? 168 : 720; // 30d
|
|
115
94
|
const startTime = Date.now() - hours * 60 * 60 * 1000;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
.
|
|
95
|
+
const startCondition = gte(auditLogs.timestamp, startTime);
|
|
96
|
+
// 总数
|
|
97
|
+
const [totalRow] = this.#drizzle
|
|
98
|
+
.select({ count: count() })
|
|
99
|
+
.from(auditLogs)
|
|
100
|
+
.where(startCondition)
|
|
101
|
+
.all();
|
|
102
|
+
const total = totalRow?.count ?? 0;
|
|
103
|
+
// 成功数
|
|
104
|
+
const [successRow] = this.#drizzle
|
|
105
|
+
.select({ count: count() })
|
|
106
|
+
.from(auditLogs)
|
|
107
|
+
.where(and(startCondition, eq(auditLogs.result, 'success')))
|
|
108
|
+
.all();
|
|
109
|
+
const successCount = successRow?.count ?? 0;
|
|
110
|
+
// 失败数
|
|
111
|
+
const [failureRow] = this.#drizzle
|
|
112
|
+
.select({ count: count() })
|
|
113
|
+
.from(auditLogs)
|
|
114
|
+
.where(and(startCondition, eq(auditLogs.result, 'failure')))
|
|
115
|
+
.all();
|
|
116
|
+
const failureCount = failureRow?.count ?? 0;
|
|
127
117
|
// 按角色统计
|
|
128
|
-
const byActor = this
|
|
129
|
-
.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
.
|
|
118
|
+
const byActor = this.#drizzle
|
|
119
|
+
.select({
|
|
120
|
+
actor: auditLogs.actor,
|
|
121
|
+
count: count(),
|
|
122
|
+
})
|
|
123
|
+
.from(auditLogs)
|
|
124
|
+
.where(startCondition)
|
|
125
|
+
.groupBy(auditLogs.actor)
|
|
126
|
+
.orderBy(desc(count()))
|
|
127
|
+
.all();
|
|
137
128
|
// 按操作统计
|
|
138
|
-
const byAction = this
|
|
139
|
-
.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
.
|
|
129
|
+
const byAction = this.#drizzle
|
|
130
|
+
.select({
|
|
131
|
+
action: auditLogs.action,
|
|
132
|
+
count: count(),
|
|
133
|
+
})
|
|
134
|
+
.from(auditLogs)
|
|
135
|
+
.where(startCondition)
|
|
136
|
+
.groupBy(auditLogs.action)
|
|
137
|
+
.orderBy(desc(count()))
|
|
138
|
+
.all();
|
|
147
139
|
// 平均响应时间
|
|
148
|
-
const
|
|
149
|
-
.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
.
|
|
140
|
+
const [avgRow] = this.#drizzle
|
|
141
|
+
.select({
|
|
142
|
+
avg_duration: avg(auditLogs.duration),
|
|
143
|
+
})
|
|
144
|
+
.from(auditLogs)
|
|
145
|
+
.where(and(startCondition, sql `${auditLogs.duration} IS NOT NULL`))
|
|
146
|
+
.all();
|
|
147
|
+
const avgDuration = avgRow?.avg_duration
|
|
148
|
+
? `${Math.round(Number(avgRow.avg_duration))}ms`
|
|
149
|
+
: 'N/A';
|
|
155
150
|
return {
|
|
156
151
|
timeRange,
|
|
157
|
-
total
|
|
158
|
-
success: successCount
|
|
159
|
-
failure: failureCount
|
|
160
|
-
successRate: total
|
|
161
|
-
avgDuration
|
|
152
|
+
total,
|
|
153
|
+
success: successCount,
|
|
154
|
+
failure: failureCount,
|
|
155
|
+
successRate: total > 0 ? `${((successCount / total) * 100).toFixed(2)}%` : '0%',
|
|
156
|
+
avgDuration,
|
|
162
157
|
byActor,
|
|
163
158
|
byAction,
|
|
164
159
|
};
|
|
165
160
|
}
|
|
166
161
|
/**
|
|
167
162
|
* 清理过期审计日志
|
|
168
|
-
*
|
|
169
|
-
* @param [opts.maxAgeDays=90] 保留天数,超过此天数的记录将被删除
|
|
170
|
-
* @returns }
|
|
163
|
+
* @param [opts.maxAgeDays=90] 保留天数
|
|
171
164
|
*/
|
|
172
165
|
cleanup({ maxAgeDays = 90 } = {}) {
|
|
173
166
|
try {
|