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,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module CouplingAnalyzer
|
|
8
8
|
*/
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { LanguageProfiles } from '#shared/LanguageProfiles.js';
|
|
9
11
|
/* ═══ Edge Weights ════════════════════════════════════════ */
|
|
10
12
|
const EDGE_WEIGHTS = {
|
|
11
13
|
depends_on: 0.5,
|
|
@@ -14,10 +16,12 @@ const EDGE_WEIGHTS = {
|
|
|
14
16
|
};
|
|
15
17
|
/* ═══ CouplingAnalyzer Class ══════════════════════════════ */
|
|
16
18
|
export class CouplingAnalyzer {
|
|
17
|
-
#
|
|
19
|
+
#edgeRepo;
|
|
20
|
+
#entityRepo;
|
|
18
21
|
#projectRoot;
|
|
19
|
-
constructor(
|
|
20
|
-
this.#
|
|
22
|
+
constructor(edgeRepo, entityRepo, projectRoot) {
|
|
23
|
+
this.#edgeRepo = edgeRepo;
|
|
24
|
+
this.#entityRepo = entityRepo;
|
|
21
25
|
this.#projectRoot = projectRoot;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
@@ -25,7 +29,7 @@ export class CouplingAnalyzer {
|
|
|
25
29
|
* @param moduleFiles - Map<moduleName, filePaths[]>
|
|
26
30
|
* @param externalModules - 外部模块名集合(无源码但参与依赖图)
|
|
27
31
|
*/
|
|
28
|
-
analyze(moduleFiles, externalModules) {
|
|
32
|
+
async analyze(moduleFiles, externalModules) {
|
|
29
33
|
// 1. 构建 file → module 反向索引
|
|
30
34
|
const fileToModule = new Map();
|
|
31
35
|
for (const [mod, files] of moduleFiles) {
|
|
@@ -34,7 +38,7 @@ export class CouplingAnalyzer {
|
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
// 2. 从 knowledge_edges 聚合模块间边
|
|
37
|
-
const edges = this.#buildModuleEdges(moduleFiles, fileToModule);
|
|
41
|
+
const edges = await this.#buildModuleEdges(moduleFiles, fileToModule);
|
|
38
42
|
// 3. 建图
|
|
39
43
|
const adjacency = new Map();
|
|
40
44
|
const allModules = new Set(moduleFiles.keys());
|
|
@@ -68,62 +72,55 @@ export class CouplingAnalyzer {
|
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
// 5.5 外部依赖 fan-in 统计
|
|
71
|
-
const externalDeps = this.#computeExternalFanIn(moduleFiles, externalModules);
|
|
75
|
+
const externalDeps = await this.#computeExternalFanIn(moduleFiles, externalModules);
|
|
72
76
|
// 去重边 (同 from→to 聚合)
|
|
73
77
|
const dedupEdges = this.#deduplicateEdges(edges);
|
|
74
78
|
return { cycles, metrics, edges: dedupEdges, externalDeps };
|
|
75
79
|
}
|
|
76
80
|
/* ─── Internal helpers ──────────────────────────── */
|
|
77
|
-
#buildModuleEdges(moduleFiles, fileToModule) {
|
|
81
|
+
async #buildModuleEdges(moduleFiles, fileToModule) {
|
|
78
82
|
const edges = [];
|
|
79
83
|
const relations = ['depends_on', 'calls', 'data_flow'];
|
|
84
|
+
// 跟踪哪些模块有 DB 边(用于判断是否需要 import 推断)
|
|
85
|
+
const modulesWithDbEdges = new Set();
|
|
80
86
|
for (const relation of relations) {
|
|
81
87
|
const weight = EDGE_WEIGHTS[relation] ?? 0.5;
|
|
82
88
|
// 查询该类型的边(仅限当前项目:至少 from 侧实体属于本项目)
|
|
83
|
-
const rows = this.#
|
|
84
|
-
.prepare(`SELECT ke.from_id, ke.from_type, ke.to_id, ke.to_type
|
|
85
|
-
FROM knowledge_edges ke
|
|
86
|
-
WHERE ke.relation = ?
|
|
87
|
-
AND (
|
|
88
|
-
ke.from_type = 'module'
|
|
89
|
-
OR EXISTS (
|
|
90
|
-
SELECT 1 FROM code_entities ce
|
|
91
|
-
WHERE ce.entity_id = ke.from_id AND ce.project_root = ?
|
|
92
|
-
)
|
|
93
|
-
)`)
|
|
94
|
-
.all(relation, this.#projectRoot);
|
|
89
|
+
const rows = await this.#edgeRepo.findEdgesFilteredByEntityExistence(relation, this.#projectRoot);
|
|
95
90
|
for (const row of rows) {
|
|
96
|
-
const fromId = row.
|
|
97
|
-
const toId = row.
|
|
98
|
-
const fromType = row.
|
|
99
|
-
const toType = row.
|
|
91
|
+
const fromId = row.fromId;
|
|
92
|
+
const toId = row.toId;
|
|
93
|
+
const fromType = row.fromType;
|
|
94
|
+
const toType = row.toType;
|
|
100
95
|
// module-to-module 直接边 (depends_on)
|
|
101
96
|
if (fromType === 'module' && toType === 'module') {
|
|
102
97
|
if (fromId !== toId && moduleFiles.has(fromId) && moduleFiles.has(toId)) {
|
|
103
98
|
edges.push({ from: fromId, to: toId, weight, relation });
|
|
99
|
+
modulesWithDbEdges.add(fromId);
|
|
104
100
|
}
|
|
105
101
|
continue;
|
|
106
102
|
}
|
|
107
103
|
// entity-to-entity 边 → 解析 file → module
|
|
108
|
-
const fromModule = this.#resolveEntityModule(fromId, fromType, fileToModule);
|
|
109
|
-
const toModule = this.#resolveEntityModule(toId, toType, fileToModule);
|
|
104
|
+
const fromModule = await this.#resolveEntityModule(fromId, fromType, fileToModule);
|
|
105
|
+
const toModule = await this.#resolveEntityModule(toId, toType, fileToModule);
|
|
110
106
|
if (fromModule && toModule && fromModule !== toModule) {
|
|
111
107
|
edges.push({ from: fromModule, to: toModule, weight, relation });
|
|
108
|
+
modulesWithDbEdges.add(fromModule);
|
|
112
109
|
}
|
|
113
110
|
}
|
|
114
111
|
}
|
|
112
|
+
// 对没有 DB 边的模块,通过 import 扫描推断依赖
|
|
113
|
+
const importEdges = this.#inferEdgesFromImports(moduleFiles, modulesWithDbEdges);
|
|
114
|
+
edges.push(...importEdges);
|
|
115
115
|
return edges;
|
|
116
116
|
}
|
|
117
|
-
#resolveEntityModule(entityId, _entityType, fileToModule) {
|
|
117
|
+
async #resolveEntityModule(entityId, _entityType, fileToModule) {
|
|
118
118
|
// 先查实体所在文件
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
WHERE entity_id = ? AND project_root = ? LIMIT 1`)
|
|
122
|
-
.get(entityId, this.#projectRoot);
|
|
123
|
-
if (!row?.file_path) {
|
|
119
|
+
const entity = await this.#entityRepo.findByEntityIdOnly(entityId, this.#projectRoot);
|
|
120
|
+
if (!entity?.filePath) {
|
|
124
121
|
return null;
|
|
125
122
|
}
|
|
126
|
-
return fileToModule.get(
|
|
123
|
+
return fileToModule.get(entity.filePath) ?? null;
|
|
127
124
|
}
|
|
128
125
|
/**
|
|
129
126
|
* Tarjan 强连通分量算法
|
|
@@ -181,16 +178,13 @@ export class CouplingAnalyzer {
|
|
|
181
178
|
* 统计外部依赖的 fan-in(被多少本地模块依赖)
|
|
182
179
|
* 数据来源:knowledge_edges 中 from_type='module' AND to_type='module' 且 to 不在 moduleFiles 中
|
|
183
180
|
*/
|
|
184
|
-
#computeExternalFanIn(moduleFiles, externalModules) {
|
|
181
|
+
async #computeExternalFanIn(moduleFiles, externalModules) {
|
|
185
182
|
const fanInMap = new Map();
|
|
186
183
|
// 从 DB 查询 module-to-module depends_on 边
|
|
187
|
-
const rows = this.#
|
|
188
|
-
.prepare(`SELECT from_id, to_id FROM knowledge_edges
|
|
189
|
-
WHERE relation = 'depends_on' AND from_type = 'module' AND to_type = 'module'`)
|
|
190
|
-
.all();
|
|
184
|
+
const rows = await this.#edgeRepo.findModuleDependencyPairs();
|
|
191
185
|
for (const row of rows) {
|
|
192
|
-
const fromId = row.
|
|
193
|
-
const toId = row.
|
|
186
|
+
const fromId = row.fromId;
|
|
187
|
+
const toId = row.toId;
|
|
194
188
|
// from 必须是本地模块, to 必须是外部模块
|
|
195
189
|
if (!moduleFiles.has(fromId)) {
|
|
196
190
|
continue;
|
|
@@ -216,6 +210,75 @@ export class CouplingAnalyzer {
|
|
|
216
210
|
}))
|
|
217
211
|
.sort((a, b) => b.fanIn - a.fanIn);
|
|
218
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* 对无 DB 边的模块,扫描源文件 import 语句推断依赖。
|
|
215
|
+
* 典型场景:iOS 宿主应用中未声明在 Boxfile 的子模块。
|
|
216
|
+
*/
|
|
217
|
+
#inferEdgesFromImports(moduleFiles, modulesWithDbEdges) {
|
|
218
|
+
const sourceExts = LanguageProfiles.sourceExts;
|
|
219
|
+
const importPatterns = LanguageProfiles.importPatterns;
|
|
220
|
+
const MAX_READ_BYTES = 8192; // 只读文件前 8KB(import 几乎总在文件头部)
|
|
221
|
+
const edges = [];
|
|
222
|
+
// 建立已知模块名集合(用于快速匹配 import 目标)
|
|
223
|
+
const knownModules = new Set(moduleFiles.keys());
|
|
224
|
+
for (const [modName, files] of moduleFiles) {
|
|
225
|
+
// 跳过已有 DB 边的模块——它们的依赖已由 Boxfile/配置声明
|
|
226
|
+
if (modulesWithDbEdges.has(modName)) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const importedModules = new Set();
|
|
230
|
+
for (const filePath of files) {
|
|
231
|
+
// 只扫描源码文件
|
|
232
|
+
const dotIdx = filePath.lastIndexOf('.');
|
|
233
|
+
if (dotIdx < 0) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const ext = filePath.slice(dotIdx).toLowerCase();
|
|
237
|
+
if (!sourceExts.has(ext)) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
let content;
|
|
241
|
+
try {
|
|
242
|
+
const fd = readFileSync(filePath, { flag: 'r' });
|
|
243
|
+
content =
|
|
244
|
+
fd.length > MAX_READ_BYTES
|
|
245
|
+
? fd.subarray(0, MAX_READ_BYTES).toString('utf8')
|
|
246
|
+
: fd.toString('utf8');
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
continue; // 文件不可读则跳过
|
|
250
|
+
}
|
|
251
|
+
// 逐行匹配 import 模式
|
|
252
|
+
const lines = content.split('\n');
|
|
253
|
+
for (const line of lines) {
|
|
254
|
+
const trimmed = line.trim();
|
|
255
|
+
for (const pattern of importPatterns) {
|
|
256
|
+
const m = pattern.regex.exec(trimmed);
|
|
257
|
+
if (m) {
|
|
258
|
+
const candidates = pattern.extract(m);
|
|
259
|
+
for (const c of candidates) {
|
|
260
|
+
if (c) {
|
|
261
|
+
importedModules.add(c);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// 生成边:仅在目标是已知模块且非自身时
|
|
269
|
+
for (const imported of importedModules) {
|
|
270
|
+
if (imported !== modName && knownModules.has(imported)) {
|
|
271
|
+
edges.push({
|
|
272
|
+
from: modName,
|
|
273
|
+
to: imported,
|
|
274
|
+
weight: EDGE_WEIGHTS.depends_on,
|
|
275
|
+
relation: 'depends_on',
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return edges;
|
|
281
|
+
}
|
|
219
282
|
#deduplicateEdges(edges) {
|
|
220
283
|
const key = (e) => `${e.from}→${e.to}`;
|
|
221
284
|
const map = new Map();
|
|
@@ -13,17 +13,20 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @module DimensionAnalyzer
|
|
15
15
|
*/
|
|
16
|
-
import type {
|
|
16
|
+
import type { BootstrapRepositoryImpl } from '../../repository/bootstrap/BootstrapRepository.js';
|
|
17
|
+
import type { CodeEntityRepositoryImpl } from '../../repository/code/CodeEntityRepository.js';
|
|
18
|
+
import type { KnowledgeRepositoryImpl } from '../../repository/knowledge/KnowledgeRepository.impl.js';
|
|
19
|
+
import type { HealthRadar, KnowledgeGap } from './PanoramaTypes.js';
|
|
17
20
|
export declare class DimensionAnalyzer {
|
|
18
21
|
#private;
|
|
19
|
-
constructor(
|
|
22
|
+
constructor(bootstrapRepo: BootstrapRepositoryImpl, entityRepo: CodeEntityRepositoryImpl, knowledgeRepo: KnowledgeRepositoryImpl, projectRoot: string);
|
|
20
23
|
/**
|
|
21
24
|
* 分析项目知识健康雷达
|
|
22
25
|
*
|
|
23
26
|
* @param moduleRoles — 项目中存在的模块角色 (用于 gap 优先级推断)
|
|
24
27
|
*/
|
|
25
|
-
analyze(moduleRoles: string[]): {
|
|
28
|
+
analyze(moduleRoles: string[]): Promise<{
|
|
26
29
|
radar: HealthRadar;
|
|
27
30
|
gaps: KnowledgeGap[];
|
|
28
|
-
}
|
|
31
|
+
}>;
|
|
29
32
|
}
|
|
@@ -14,12 +14,18 @@
|
|
|
14
14
|
* @module DimensionAnalyzer
|
|
15
15
|
*/
|
|
16
16
|
import { classifyRecipeToDimension, DIMENSION_REGISTRY, resolveActiveDimensions, } from '#domain/dimension/index.js';
|
|
17
|
+
import { LanguageService } from '#shared/LanguageService.js';
|
|
18
|
+
import { COUNTABLE_LIFECYCLES } from '../../domain/knowledge/Lifecycle.js';
|
|
17
19
|
/* ═══ DimensionAnalyzer Class ═════════════════════════════ */
|
|
18
20
|
export class DimensionAnalyzer {
|
|
19
|
-
#
|
|
21
|
+
#bootstrapRepo;
|
|
22
|
+
#entityRepo;
|
|
23
|
+
#knowledgeRepo;
|
|
20
24
|
#projectRoot;
|
|
21
|
-
constructor(
|
|
22
|
-
this.#
|
|
25
|
+
constructor(bootstrapRepo, entityRepo, knowledgeRepo, projectRoot) {
|
|
26
|
+
this.#bootstrapRepo = bootstrapRepo;
|
|
27
|
+
this.#entityRepo = entityRepo;
|
|
28
|
+
this.#knowledgeRepo = knowledgeRepo;
|
|
23
29
|
this.#projectRoot = projectRoot;
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
@@ -27,11 +33,11 @@ export class DimensionAnalyzer {
|
|
|
27
33
|
*
|
|
28
34
|
* @param moduleRoles — 项目中存在的模块角色 (用于 gap 优先级推断)
|
|
29
35
|
*/
|
|
30
|
-
analyze(moduleRoles) {
|
|
36
|
+
async analyze(moduleRoles) {
|
|
31
37
|
// 0. 按项目语言过滤活跃维度(排除无关语言/框架维度)
|
|
32
|
-
const activeDims = this.#resolveActiveDims();
|
|
38
|
+
const activeDims = await this.#resolveActiveDims();
|
|
33
39
|
// 1. 从 DB 获取所有活跃 recipe 的维度分类信息
|
|
34
|
-
const recipes = this.#fetchRecipeMetadata();
|
|
40
|
+
const recipes = await this.#fetchRecipeMetadata();
|
|
35
41
|
// 2. 将每条 recipe 映射到维度
|
|
36
42
|
const dimensionCounts = new Map();
|
|
37
43
|
for (const def of activeDims) {
|
|
@@ -79,36 +85,77 @@ export class DimensionAnalyzer {
|
|
|
79
85
|
return { radar, gaps };
|
|
80
86
|
}
|
|
81
87
|
/* ─── 按项目语言解析活跃维度 ───────────────────── */
|
|
82
|
-
#resolveActiveDims() {
|
|
88
|
+
async #resolveActiveDims() {
|
|
89
|
+
// 1. 优先从 bootstrap_snapshots 获取 primary_lang
|
|
83
90
|
try {
|
|
84
|
-
const
|
|
85
|
-
.prepare(`SELECT primary_lang FROM bootstrap_snapshots
|
|
86
|
-
WHERE project_root = ? ORDER BY created_at DESC LIMIT 1`)
|
|
87
|
-
.get(this.#projectRoot);
|
|
88
|
-
const primaryLang = row?.primary_lang;
|
|
91
|
+
const primaryLang = await this.#bootstrapRepo.getLatestPrimaryLang(this.#projectRoot);
|
|
89
92
|
if (primaryLang) {
|
|
90
93
|
return resolveActiveDimensions(primaryLang);
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
catch {
|
|
94
|
-
// 无 bootstrap 数据 →
|
|
97
|
+
// 无 bootstrap 数据 → 继续尝试从 code_entities 推断
|
|
98
|
+
}
|
|
99
|
+
// 2. 从 code_entities 文件扩展名推断主语言
|
|
100
|
+
const inferredLang = await this.#inferLanguageFromEntities();
|
|
101
|
+
if (inferredLang) {
|
|
102
|
+
return resolveActiveDimensions(inferredLang);
|
|
95
103
|
}
|
|
96
104
|
return DIMENSION_REGISTRY;
|
|
97
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* 从 code_entities 文件扩展名统计推断项目主语言
|
|
108
|
+
*
|
|
109
|
+
* 当无 bootstrap_snapshots 时使用(如仅执行了 scan 但未 bootstrap 的项目)
|
|
110
|
+
*/
|
|
111
|
+
async #inferLanguageFromEntities() {
|
|
112
|
+
try {
|
|
113
|
+
const filePaths = await this.#entityRepo.findDistinctFilePaths(this.#projectRoot, 2000);
|
|
114
|
+
if (filePaths.length === 0) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const langCounts = new Map();
|
|
118
|
+
for (const fp of filePaths) {
|
|
119
|
+
if (!fp) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const dotIdx = fp.lastIndexOf('.');
|
|
123
|
+
if (dotIdx < 0) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const ext = fp.slice(dotIdx).toLowerCase();
|
|
127
|
+
const lang = LanguageService.langFromExt(ext);
|
|
128
|
+
if (lang !== 'unknown') {
|
|
129
|
+
langCounts.set(lang, (langCounts.get(lang) ?? 0) + 1);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// .h 文件可能属于 Swift/ObjC 项目 — 如果同时存在 .swift 文件则优先 swift
|
|
133
|
+
if (langCounts.has('swift') && langCounts.has('objectivec')) {
|
|
134
|
+
const swiftCount = langCounts.get('swift');
|
|
135
|
+
const objcCount = langCounts.get('objectivec');
|
|
136
|
+
if (swiftCount >= objcCount * 0.2) {
|
|
137
|
+
return 'swift';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// 选最多的语言
|
|
141
|
+
let bestLang = '';
|
|
142
|
+
let bestCount = 0;
|
|
143
|
+
for (const [lang, _count] of langCounts) {
|
|
144
|
+
if (_count > bestCount) {
|
|
145
|
+
bestLang = lang;
|
|
146
|
+
bestCount = _count;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return bestLang || null;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
98
155
|
/* ─── 从 DB 获取 recipe 元数据 ─────────────────── */
|
|
99
|
-
#fetchRecipeMetadata() {
|
|
156
|
+
async #fetchRecipeMetadata() {
|
|
100
157
|
try {
|
|
101
|
-
|
|
102
|
-
.prepare(`SELECT title, category, topicHint, kind
|
|
103
|
-
FROM knowledge_entries
|
|
104
|
-
WHERE lifecycle IN ('active', 'pending')`)
|
|
105
|
-
.all();
|
|
106
|
-
return rows.map((r) => ({
|
|
107
|
-
title: String(r.title ?? ''),
|
|
108
|
-
category: String(r.category ?? ''),
|
|
109
|
-
topicHint: String(r.topicHint ?? ''),
|
|
110
|
-
kind: String(r.kind ?? ''),
|
|
111
|
-
}));
|
|
158
|
+
return await this.#knowledgeRepo.findRecipeMetadata(COUNTABLE_LIFECYCLES);
|
|
112
159
|
}
|
|
113
160
|
catch {
|
|
114
161
|
return [];
|
|
@@ -129,7 +129,7 @@ export class LayerInferrer {
|
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
return { levels: levelEntries, violations };
|
|
132
|
+
return { levels: levelEntries, violations, configBased: true };
|
|
133
133
|
}
|
|
134
134
|
#computeConfigCoverage(modules, moduleLayerMap) {
|
|
135
135
|
if (modules.length === 0) {
|
|
@@ -11,23 +11,24 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module ModuleDiscoverer
|
|
13
13
|
*/
|
|
14
|
-
import type {
|
|
14
|
+
import type { CodeEntityRepositoryImpl } from '../../repository/code/CodeEntityRepository.js';
|
|
15
|
+
import type { KnowledgeEdgeRepositoryImpl } from '../../repository/knowledge/KnowledgeEdgeRepository.js';
|
|
15
16
|
import type { ModuleCandidate } from './RoleRefiner.js';
|
|
16
17
|
export declare class ModuleDiscoverer {
|
|
17
18
|
#private;
|
|
18
|
-
constructor(
|
|
19
|
+
constructor(entityRepo: CodeEntityRepositoryImpl, edgeRepo: KnowledgeEdgeRepositoryImpl, projectRoot: string);
|
|
19
20
|
/**
|
|
20
21
|
* 从 DB 中读取已扫描的模块数据。
|
|
21
|
-
* 若无 module
|
|
22
|
+
* 若无 module 实体(含 host),返回空数组(让调用侧决定是否重新扫描)。
|
|
22
23
|
*/
|
|
23
|
-
discover(): ModuleCandidate[]
|
|
24
|
+
discover(): Promise<ModuleCandidate[]>;
|
|
24
25
|
/**
|
|
25
26
|
* 读取 config layers 元数据(如果存在)
|
|
26
27
|
* @returns 从 `__config_layers__` 实体中恢复的层级定义
|
|
27
28
|
*/
|
|
28
|
-
readConfigLayers(): Array<{
|
|
29
|
+
readConfigLayers(): Promise<Array<{
|
|
29
30
|
name: string;
|
|
30
31
|
order: number;
|
|
31
32
|
accessibleLayers: string[];
|
|
32
|
-
}> | null
|
|
33
|
+
}> | null>;
|
|
33
34
|
}
|