autosnippet 3.3.6 → 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 +8 -4
- package/dist/lib/agent/AgentRuntime.d.ts +2 -2
- package/dist/lib/agent/AgentRuntime.js +26 -18
- 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/domain/ChatAgentTasks.js +4 -0
- package/dist/lib/agent/forced-summary.js +7 -2
- 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 +8 -21
- 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/ConfigWatcher.d.ts +64 -0
- package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +28 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1303 -0
- package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
- package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
- package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
- package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
- package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
- package/dist/lib/core/discovery/index.d.ts +2 -0
- package/dist/lib/core/discovery/index.js +4 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
- 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/KnowledgeEntry.d.ts +7 -1
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
- 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/ai/AiProvider.d.ts +12 -0
- package/dist/lib/external/ai/AiProvider.js +24 -0
- package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
- package/dist/lib/external/ai/AiProviderManager.js +193 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
- package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
- package/dist/lib/external/ai/providers/MockProvider.js +290 -14
- package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
- package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
- package/dist/lib/external/lark/LarkTransport.js +10 -2
- 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/mock-pipeline.d.ts +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -24
- package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
- 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.d.ts +9 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +3 -1
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +9 -4
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +18 -18
- package/dist/lib/external/mcp/handlers/guard.js +15 -24
- package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
- 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 +109 -30
- package/dist/lib/http/routes/candidates.js +11 -4
- package/dist/lib/http/routes/commands.js +10 -1
- package/dist/lib/http/routes/guardReport.js +3 -5
- package/dist/lib/http/routes/health.js +11 -0
- package/dist/lib/http/routes/modules.js +27 -0
- package/dist/lib/http/routes/panorama.js +12 -12
- package/dist/lib/http/routes/recipes.js +66 -8
- package/dist/lib/http/routes/remote.js +3 -13
- package/dist/lib/http/routes/search.js +11 -8
- package/dist/lib/http/utils/routeHelpers.js +2 -1
- 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.d.ts +6 -5
- package/dist/lib/injection/ServiceContainer.js +18 -31
- package/dist/lib/injection/ServiceMap.d.ts +22 -0
- package/dist/lib/injection/modules/AiModule.d.ts +6 -9
- package/dist/lib/injection/modules/AiModule.js +82 -39
- 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.d.ts +54 -7
- package/dist/lib/service/cleanup/CleanupService.js +291 -40
- 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 +45 -63
- package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -496
- 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 +97 -46
- 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/module/ModuleService.js +10 -19
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +14 -3
- package/dist/lib/service/panorama/CouplingAnalyzer.js +137 -32
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
- package/dist/lib/service/panorama/DimensionAnalyzer.js +94 -33
- package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
- package/dist/lib/service/panorama/LayerInferrer.js +118 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +14 -4
- package/dist/lib/service/panorama/ModuleDiscoverer.js +209 -61
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +15 -4
- package/dist/lib/service/panorama/PanoramaAggregator.js +128 -62
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
- package/dist/lib/service/panorama/PanoramaScanner.js +60 -31
- package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
- package/dist/lib/service/panorama/PanoramaService.js +49 -69
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +41 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +10 -5
- package/dist/lib/service/panorama/RoleRefiner.js +92 -282
- package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
- package/dist/lib/service/panorama/TechStackProfiler.js +79 -0
- 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 +6 -8
- package/dist/lib/service/skills/SignalCollector.js +34 -60
- package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
- package/dist/lib/service/skills/SkillAdvisor.js +30 -79
- package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
- package/dist/lib/service/vector/ContextualEnricher.js +4 -0
- 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 +19 -0
- package/dist/lib/shared/constants.d.ts +19 -19
- package/dist/lib/shared/constants.js +10 -10
- package/dist/lib/shared/developer-identity.d.ts +18 -0
- package/dist/lib/shared/developer-identity.js +62 -0
- package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
- package/dist/lib/shared/schemas/http-requests.js +9 -6
- package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
- package/dist/lib/types/knowledge-wire.d.ts +1 -0
- 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-D1aVZYFW.js +0 -1
- package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
- package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
- 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();
|
|
@@ -70,11 +71,17 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
70
71
|
data: { status: 'error', error: 'AgentFactory 不可用,请检查 AI Provider 配置' },
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
|
-
//
|
|
74
|
+
// Mock 模式下跳过 AI 关系发现
|
|
75
|
+
if (agentFactory.getAiProviderInfo?.()?.name === 'mock') {
|
|
76
|
+
return void res.json({
|
|
77
|
+
success: true,
|
|
78
|
+
data: { status: 'error', error: 'AI Provider 未配置,当前为 Mock 模式。请先配置 API Key。' },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// 快速检查:至少需要 2 条可消费 Recipe(active/staging/pending/evolving)
|
|
74
82
|
try {
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const count = items.length || data.length;
|
|
83
|
+
const knowledgeRepo = container.get('knowledgeRepository');
|
|
84
|
+
const count = await knowledgeRepo.countByLifecycles(COUNTABLE_LIFECYCLES);
|
|
78
85
|
if (count < 2) {
|
|
79
86
|
return void res.json({
|
|
80
87
|
success: true,
|
|
@@ -86,7 +93,7 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
catch {
|
|
89
|
-
//
|
|
96
|
+
// 如果查询失败,继续尝试(让 runTask 给出具体错误)
|
|
90
97
|
}
|
|
91
98
|
// 重置并启动后台任务
|
|
92
99
|
resetTask();
|
|
@@ -96,11 +103,62 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
96
103
|
(async () => {
|
|
97
104
|
try {
|
|
98
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
|
+
}
|
|
99
157
|
discoverTask.status = 'done';
|
|
100
158
|
discoverTask.finishedAt = new Date().toISOString();
|
|
101
|
-
discoverTask.discovered =
|
|
102
|
-
discoverTask.totalPairs =
|
|
103
|
-
discoverTask.batchErrors =
|
|
159
|
+
discoverTask.discovered = written;
|
|
160
|
+
discoverTask.totalPairs = analyzed;
|
|
161
|
+
discoverTask.batchErrors = relations.length - written;
|
|
104
162
|
discoverTask.elapsed = Math.round((new Date(discoverTask.finishedAt).getTime() - new Date(discoverTask.startedAt).getTime()) /
|
|
105
163
|
1000);
|
|
106
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
|
/**
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
* 提取自各路由文件中的重复实现
|
|
4
4
|
*/
|
|
5
5
|
import { KnowledgeEntry } from '../../domain/knowledge/KnowledgeEntry.js';
|
|
6
|
+
import { getDeveloperIdentity } from '../../shared/developer-identity.js';
|
|
6
7
|
/**
|
|
7
8
|
* 从请求中提取操作上下文(用户身份、IP、UA)
|
|
8
9
|
* @returns }
|
|
9
10
|
*/
|
|
10
11
|
export function getContext(req) {
|
|
11
12
|
return {
|
|
12
|
-
userId: String(req.headers['x-user-id'] ||
|
|
13
|
+
userId: String(req.headers['x-user-id'] || getDeveloperIdentity()),
|
|
13
14
|
ip: req.ip || '',
|
|
14
15
|
userAgent: req.headers['user-agent'] || '',
|
|
15
16
|
};
|
|
@@ -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 {
|