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.
Files changed (211) hide show
  1. package/README.md +1 -0
  2. package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
  3. package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
  4. package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
  5. package/dashboard/dist/index.html +3 -3
  6. package/dist/bin/cli.js +7 -4
  7. package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
  8. package/dist/lib/agent/core/LoopContext.d.ts +1 -0
  9. package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
  10. package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
  11. package/dist/lib/agent/memory/ActiveContext.js +0 -2
  12. package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
  13. package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
  14. package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
  15. package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
  16. package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
  17. package/dist/lib/agent/memory/MemoryStore.js +196 -261
  18. package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
  19. package/dist/lib/agent/memory/PersistentMemory.js +4 -5
  20. package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
  21. package/dist/lib/agent/memory/SessionStore.js +0 -2
  22. package/dist/lib/agent/tools/ast-graph.js +21 -19
  23. package/dist/lib/agent/tools/infrastructure.js +3 -2
  24. package/dist/lib/agent/tools/project-access.d.ts +2 -2
  25. package/dist/lib/agent/tools/project-access.js +5 -4
  26. package/dist/lib/bootstrap.js +2 -1
  27. package/dist/lib/cli/AiScanService.js +4 -17
  28. package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
  29. package/dist/lib/cli/KnowledgeSyncService.js +23 -51
  30. package/dist/lib/core/ast/ProjectGraph.js +5 -27
  31. package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +0 -2
  32. package/dist/lib/core/discovery/CustomConfigDiscoverer.js +0 -2
  33. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
  34. package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
  35. package/dist/lib/domain/dimension/DimensionSop.js +44 -33
  36. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
  37. package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
  38. package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
  39. package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
  40. package/dist/lib/domain/knowledge/index.d.ts +2 -1
  41. package/dist/lib/domain/knowledge/index.js +1 -1
  42. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
  43. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
  44. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +33 -16
  45. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
  46. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
  47. package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -1
  48. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +7 -3
  49. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
  50. package/dist/lib/external/mcp/handlers/evolve-external.js +13 -16
  51. package/dist/lib/external/mcp/handlers/guard.js +15 -24
  52. package/dist/lib/external/mcp/handlers/panorama.js +9 -9
  53. package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
  54. package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
  55. package/dist/lib/external/mcp/handlers/search.js +3 -1
  56. package/dist/lib/external/mcp/handlers/skill.js +4 -4
  57. package/dist/lib/external/mcp/handlers/structure.js +8 -12
  58. package/dist/lib/external/mcp/handlers/system.js +10 -34
  59. package/dist/lib/http/routes/ai.js +11 -13
  60. package/dist/lib/http/routes/guardReport.js +3 -5
  61. package/dist/lib/http/routes/panorama.js +12 -12
  62. package/dist/lib/http/routes/recipes.js +59 -8
  63. package/dist/lib/http/routes/remote.js +3 -13
  64. package/dist/lib/http/routes/search.js +11 -8
  65. package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
  66. package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
  67. package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
  68. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
  69. package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
  70. package/dist/lib/injection/ServiceContainer.js +7 -4
  71. package/dist/lib/injection/ServiceMap.d.ts +20 -0
  72. package/dist/lib/injection/modules/AppModule.js +2 -1
  73. package/dist/lib/injection/modules/GuardModule.js +5 -5
  74. package/dist/lib/injection/modules/InfraModule.js +60 -0
  75. package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
  76. package/dist/lib/injection/modules/PanoramaModule.js +16 -10
  77. package/dist/lib/injection/modules/VectorModule.js +3 -0
  78. package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
  79. package/dist/lib/repository/audit/AuditRepository.js +272 -0
  80. package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
  81. package/dist/lib/repository/base/RepositoryBase.js +32 -0
  82. package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
  83. package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
  84. package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
  85. package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
  86. package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
  87. package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
  88. package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
  89. package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
  90. package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
  91. package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
  92. package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
  93. package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
  94. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
  95. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
  96. package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
  97. package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
  98. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
  99. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
  100. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
  101. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
  102. package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
  103. package/dist/lib/repository/memory/MemoryRepository.js +260 -0
  104. package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
  105. package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
  106. package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
  107. package/dist/lib/repository/session/SessionRepository.js +110 -0
  108. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
  109. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
  110. package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
  111. package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
  112. package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
  113. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
  114. package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
  115. package/dist/lib/service/cleanup/CleanupService.js +8 -4
  116. package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
  117. package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
  118. package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
  119. package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
  120. package/dist/lib/service/evolution/ContentPatcher.js +48 -19
  121. package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
  122. package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
  123. package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
  124. package/dist/lib/service/evolution/DecayDetector.js +63 -57
  125. package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
  126. package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
  127. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
  128. package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
  129. package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
  130. package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
  131. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
  132. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
  133. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
  134. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
  135. package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
  136. package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
  137. package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
  138. package/dist/lib/service/evolution/StagingManager.js +37 -95
  139. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
  140. package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
  141. package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
  142. package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
  143. package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
  144. package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
  145. package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
  146. package/dist/lib/service/guard/ReverseGuard.js +21 -31
  147. package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
  148. package/dist/lib/service/guard/ViolationsStore.js +75 -69
  149. package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +39 -63
  150. package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -512
  151. package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
  152. package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
  153. package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
  154. package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
  155. package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
  156. package/dist/lib/service/knowledge/KnowledgeService.js +76 -38
  157. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
  158. package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
  159. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
  160. package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
  161. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +5 -3
  162. package/dist/lib/service/panorama/CouplingAnalyzer.js +102 -39
  163. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
  164. package/dist/lib/service/panorama/DimensionAnalyzer.js +72 -25
  165. package/dist/lib/service/panorama/LayerInferrer.js +1 -1
  166. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +7 -6
  167. package/dist/lib/service/panorama/ModuleDiscoverer.js +174 -82
  168. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +10 -3
  169. package/dist/lib/service/panorama/PanoramaAggregator.js +67 -79
  170. package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
  171. package/dist/lib/service/panorama/PanoramaScanner.js +32 -31
  172. package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
  173. package/dist/lib/service/panorama/PanoramaService.js +41 -66
  174. package/dist/lib/service/panorama/PanoramaTypes.d.ts +3 -0
  175. package/dist/lib/service/panorama/RoleRefiner.d.ts +8 -5
  176. package/dist/lib/service/panorama/RoleRefiner.js +52 -283
  177. package/dist/lib/service/panorama/TechStackProfiler.js +7 -119
  178. package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
  179. package/dist/lib/service/quality/QualityScorer.js +157 -83
  180. package/dist/lib/service/search/SearchEngine.d.ts +1 -0
  181. package/dist/lib/service/search/SearchEngine.js +32 -37
  182. package/dist/lib/service/signal/HitRecorder.js +5 -5
  183. package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
  184. package/dist/lib/service/skills/SignalCollector.d.ts +5 -8
  185. package/dist/lib/service/skills/SignalCollector.js +28 -55
  186. package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
  187. package/dist/lib/service/skills/SkillAdvisor.js +30 -79
  188. package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
  189. package/dist/lib/service/vector/SyncCoordinator.js +25 -3
  190. package/dist/lib/service/vector/VectorService.d.ts +2 -0
  191. package/dist/lib/service/vector/VectorService.js +3 -0
  192. package/dist/lib/service/wiki/WikiGenerator.js +1 -1
  193. package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
  194. package/dist/lib/shared/LanguageProfiles.js +939 -0
  195. package/dist/lib/shared/LanguageService.d.ts +6 -0
  196. package/dist/lib/shared/LanguageService.js +16 -0
  197. package/dist/lib/shared/constants.d.ts +19 -19
  198. package/dist/lib/shared/constants.js +10 -10
  199. package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
  200. package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
  201. package/dist/lib/types/project-snapshot-builder.js +0 -1
  202. package/dist/lib/types/project-snapshot.d.ts +0 -1
  203. package/dist/lib/types/project-snapshot.js +0 -1
  204. package/dist/lib/types/snapshot-views.d.ts +0 -2
  205. package/dist/lib/types/snapshot-views.js +0 -1
  206. package/package.json +2 -1
  207. package/dashboard/dist/assets/icons-FHns2ypa.js +0 -1
  208. package/dashboard/dist/assets/index-BRJv5Y3r.js +0 -135
  209. package/dashboard/dist/assets/index-DzoB7kxK.css +0 -1
  210. package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
  211. 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
- #db;
19
+ #edgeRepo;
20
+ #entityRepo;
18
21
  #projectRoot;
19
- constructor(db, projectRoot) {
20
- this.#db = db;
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.#db
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.from_id;
97
- const toId = row.to_id;
98
- const fromType = row.from_type;
99
- const toType = row.to_type;
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 row = this.#db
120
- .prepare(`SELECT file_path FROM code_entities
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(row.file_path) ?? null;
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.#db
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.from_id;
193
- const toId = row.to_id;
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 { CeDbLike, HealthRadar, KnowledgeGap } from './PanoramaTypes.js';
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(db: CeDbLike, projectRoot: string);
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
- #db;
21
+ #bootstrapRepo;
22
+ #entityRepo;
23
+ #knowledgeRepo;
20
24
  #projectRoot;
21
- constructor(db, projectRoot) {
22
- this.#db = db;
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 row = this.#db
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
- const rows = this.#db
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 { CeDbLike } from './PanoramaTypes.js';
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(db: CeDbLike, projectRoot: string);
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
  }