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.
Files changed (275) 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 +8 -4
  7. package/dist/lib/agent/AgentRuntime.d.ts +2 -2
  8. package/dist/lib/agent/AgentRuntime.js +26 -18
  9. package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
  10. package/dist/lib/agent/core/LoopContext.d.ts +1 -0
  11. package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
  12. package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
  13. package/dist/lib/agent/forced-summary.js +7 -2
  14. package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
  15. package/dist/lib/agent/memory/ActiveContext.js +0 -2
  16. package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
  17. package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
  18. package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
  19. package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
  20. package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
  21. package/dist/lib/agent/memory/MemoryStore.js +196 -261
  22. package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
  23. package/dist/lib/agent/memory/PersistentMemory.js +4 -5
  24. package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
  25. package/dist/lib/agent/memory/SessionStore.js +0 -2
  26. package/dist/lib/agent/tools/ast-graph.js +21 -19
  27. package/dist/lib/agent/tools/infrastructure.js +3 -2
  28. package/dist/lib/agent/tools/project-access.d.ts +2 -2
  29. package/dist/lib/agent/tools/project-access.js +5 -4
  30. package/dist/lib/bootstrap.js +2 -1
  31. package/dist/lib/cli/AiScanService.js +8 -21
  32. package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
  33. package/dist/lib/cli/KnowledgeSyncService.js +23 -51
  34. package/dist/lib/core/ast/ProjectGraph.js +5 -27
  35. package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
  36. package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
  37. package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +28 -0
  38. package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1303 -0
  39. package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
  40. package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
  41. package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
  42. package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
  43. package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
  44. package/dist/lib/core/discovery/index.d.ts +2 -0
  45. package/dist/lib/core/discovery/index.js +4 -0
  46. package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
  47. package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
  48. package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
  49. package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
  50. package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
  51. package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
  52. package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
  53. package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
  54. package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
  55. package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
  56. package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
  57. package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
  58. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
  59. package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
  60. package/dist/lib/domain/dimension/DimensionSop.js +44 -33
  61. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
  62. package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
  63. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
  64. package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
  65. package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
  66. package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
  67. package/dist/lib/domain/knowledge/index.d.ts +2 -1
  68. package/dist/lib/domain/knowledge/index.js +1 -1
  69. package/dist/lib/external/ai/AiProvider.d.ts +12 -0
  70. package/dist/lib/external/ai/AiProvider.js +24 -0
  71. package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
  72. package/dist/lib/external/ai/AiProviderManager.js +193 -0
  73. package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
  74. package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
  75. package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
  76. package/dist/lib/external/ai/providers/MockProvider.js +290 -14
  77. package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
  78. package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
  79. package/dist/lib/external/lark/LarkTransport.js +10 -2
  80. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
  81. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
  82. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
  83. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
  84. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -24
  85. package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
  86. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
  87. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
  88. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
  89. package/dist/lib/external/mcp/handlers/bootstrap-external.js +3 -1
  90. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
  91. package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
  92. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +9 -4
  93. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
  94. package/dist/lib/external/mcp/handlers/evolve-external.js +18 -18
  95. package/dist/lib/external/mcp/handlers/guard.js +15 -24
  96. package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
  97. package/dist/lib/external/mcp/handlers/panorama.js +9 -9
  98. package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
  99. package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
  100. package/dist/lib/external/mcp/handlers/search.js +3 -1
  101. package/dist/lib/external/mcp/handlers/skill.js +4 -4
  102. package/dist/lib/external/mcp/handlers/structure.js +8 -12
  103. package/dist/lib/external/mcp/handlers/system.js +10 -34
  104. package/dist/lib/http/routes/ai.js +109 -30
  105. package/dist/lib/http/routes/candidates.js +11 -4
  106. package/dist/lib/http/routes/commands.js +10 -1
  107. package/dist/lib/http/routes/guardReport.js +3 -5
  108. package/dist/lib/http/routes/health.js +11 -0
  109. package/dist/lib/http/routes/modules.js +27 -0
  110. package/dist/lib/http/routes/panorama.js +12 -12
  111. package/dist/lib/http/routes/recipes.js +66 -8
  112. package/dist/lib/http/routes/remote.js +3 -13
  113. package/dist/lib/http/routes/search.js +11 -8
  114. package/dist/lib/http/utils/routeHelpers.js +2 -1
  115. package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
  116. package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
  117. package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
  118. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
  119. package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
  120. package/dist/lib/injection/ServiceContainer.d.ts +6 -5
  121. package/dist/lib/injection/ServiceContainer.js +18 -31
  122. package/dist/lib/injection/ServiceMap.d.ts +22 -0
  123. package/dist/lib/injection/modules/AiModule.d.ts +6 -9
  124. package/dist/lib/injection/modules/AiModule.js +82 -39
  125. package/dist/lib/injection/modules/AppModule.js +2 -1
  126. package/dist/lib/injection/modules/GuardModule.js +5 -5
  127. package/dist/lib/injection/modules/InfraModule.js +60 -0
  128. package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
  129. package/dist/lib/injection/modules/PanoramaModule.js +16 -10
  130. package/dist/lib/injection/modules/VectorModule.js +3 -0
  131. package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
  132. package/dist/lib/repository/audit/AuditRepository.js +272 -0
  133. package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
  134. package/dist/lib/repository/base/RepositoryBase.js +32 -0
  135. package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
  136. package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
  137. package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
  138. package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
  139. package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
  140. package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
  141. package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
  142. package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
  143. package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
  144. package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
  145. package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
  146. package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
  147. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
  148. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
  149. package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
  150. package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
  151. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
  152. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
  153. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
  154. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
  155. package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
  156. package/dist/lib/repository/memory/MemoryRepository.js +260 -0
  157. package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
  158. package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
  159. package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
  160. package/dist/lib/repository/session/SessionRepository.js +110 -0
  161. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
  162. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
  163. package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
  164. package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
  165. package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
  166. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
  167. package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
  168. package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
  169. package/dist/lib/service/cleanup/CleanupService.js +291 -40
  170. package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
  171. package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
  172. package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
  173. package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
  174. package/dist/lib/service/evolution/ContentPatcher.js +48 -19
  175. package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
  176. package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
  177. package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
  178. package/dist/lib/service/evolution/DecayDetector.js +63 -57
  179. package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
  180. package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
  181. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
  182. package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
  183. package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
  184. package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
  185. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
  186. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
  187. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
  188. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
  189. package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
  190. package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
  191. package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
  192. package/dist/lib/service/evolution/StagingManager.js +37 -95
  193. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
  194. package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
  195. package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
  196. package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
  197. package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
  198. package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
  199. package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
  200. package/dist/lib/service/guard/ReverseGuard.js +21 -31
  201. package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
  202. package/dist/lib/service/guard/ViolationsStore.js +75 -69
  203. package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +45 -63
  204. package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -496
  205. package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
  206. package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
  207. package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
  208. package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
  209. package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
  210. package/dist/lib/service/knowledge/KnowledgeService.js +97 -46
  211. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
  212. package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
  213. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
  214. package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
  215. package/dist/lib/service/module/ModuleService.js +10 -19
  216. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +14 -3
  217. package/dist/lib/service/panorama/CouplingAnalyzer.js +137 -32
  218. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
  219. package/dist/lib/service/panorama/DimensionAnalyzer.js +94 -33
  220. package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
  221. package/dist/lib/service/panorama/LayerInferrer.js +118 -1
  222. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +14 -4
  223. package/dist/lib/service/panorama/ModuleDiscoverer.js +209 -61
  224. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +15 -4
  225. package/dist/lib/service/panorama/PanoramaAggregator.js +128 -62
  226. package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
  227. package/dist/lib/service/panorama/PanoramaScanner.js +60 -31
  228. package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
  229. package/dist/lib/service/panorama/PanoramaService.js +49 -69
  230. package/dist/lib/service/panorama/PanoramaTypes.d.ts +41 -0
  231. package/dist/lib/service/panorama/RoleRefiner.d.ts +10 -5
  232. package/dist/lib/service/panorama/RoleRefiner.js +92 -282
  233. package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
  234. package/dist/lib/service/panorama/TechStackProfiler.js +79 -0
  235. package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
  236. package/dist/lib/service/quality/QualityScorer.js +157 -83
  237. package/dist/lib/service/search/SearchEngine.d.ts +1 -0
  238. package/dist/lib/service/search/SearchEngine.js +32 -37
  239. package/dist/lib/service/signal/HitRecorder.js +5 -5
  240. package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
  241. package/dist/lib/service/skills/SignalCollector.d.ts +6 -8
  242. package/dist/lib/service/skills/SignalCollector.js +34 -60
  243. package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
  244. package/dist/lib/service/skills/SkillAdvisor.js +30 -79
  245. package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
  246. package/dist/lib/service/vector/ContextualEnricher.js +4 -0
  247. package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
  248. package/dist/lib/service/vector/SyncCoordinator.js +25 -3
  249. package/dist/lib/service/vector/VectorService.d.ts +2 -0
  250. package/dist/lib/service/vector/VectorService.js +3 -0
  251. package/dist/lib/service/wiki/WikiGenerator.js +1 -1
  252. package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
  253. package/dist/lib/shared/LanguageProfiles.js +939 -0
  254. package/dist/lib/shared/LanguageService.d.ts +6 -0
  255. package/dist/lib/shared/LanguageService.js +19 -0
  256. package/dist/lib/shared/constants.d.ts +19 -19
  257. package/dist/lib/shared/constants.js +10 -10
  258. package/dist/lib/shared/developer-identity.d.ts +18 -0
  259. package/dist/lib/shared/developer-identity.js +62 -0
  260. package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
  261. package/dist/lib/shared/schemas/http-requests.js +9 -6
  262. package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
  263. package/dist/lib/types/knowledge-wire.d.ts +1 -0
  264. package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
  265. package/dist/lib/types/project-snapshot-builder.js +0 -1
  266. package/dist/lib/types/project-snapshot.d.ts +0 -1
  267. package/dist/lib/types/project-snapshot.js +0 -1
  268. package/dist/lib/types/snapshot-views.d.ts +0 -2
  269. package/dist/lib/types/snapshot-views.js +0 -1
  270. package/package.json +2 -1
  271. package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
  272. package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
  273. package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
  274. package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
  275. package/dist/lib/repository/base/BaseRepository.js +0 -226
@@ -13,96 +13,141 @@
13
13
  */
14
14
  import fs from 'node:fs';
15
15
  import path from 'node:path';
16
+ import { LanguageProfiles } from '#shared/LanguageProfiles.js';
16
17
  import { inferTargetRole } from '../../external/mcp/handlers/TargetClassifier.js';
17
18
  /* ═══ Constants ═══════════════════════════════════════════ */
18
- const SOURCE_EXTS = new Set([
19
- '.swift',
20
- '.ts',
21
- '.tsx',
22
- '.js',
23
- '.jsx',
24
- '.m',
25
- '.mm',
26
- '.h',
27
- '.c',
28
- '.cpp',
29
- '.kt',
30
- '.java',
31
- '.py',
32
- '.rb',
33
- '.go',
34
- '.rs',
35
- ]);
36
- const SKIP_DIRS = new Set([
37
- '.git',
38
- '.build',
39
- '.autosnippet',
40
- 'node_modules',
41
- 'build',
42
- 'Pods',
43
- 'DerivedData',
44
- '.swiftpm',
45
- '__pycache__',
46
- 'dist',
47
- ]);
19
+ // All language-specific constants are now in LanguageProfiles.
20
+ // These aliases delegate to the unified registry for backward compat:
21
+ const SOURCE_EXTS = LanguageProfiles.sourceExts;
22
+ const SKIP_DIRS = LanguageProfiles.skipDirs;
23
+ const HOST_SKIP_SUFFIXES = LanguageProfiles.artifactSuffixes;
24
+ const HOST_VENDOR_DIRS = LanguageProfiles.vendorDirs;
48
25
  /* ═══ ModuleDiscoverer Class ══════════════════════════════ */
49
26
  export class ModuleDiscoverer {
50
- #db;
27
+ #entityRepo;
28
+ #edgeRepo;
51
29
  #projectRoot;
52
- constructor(db, projectRoot) {
53
- this.#db = db;
30
+ constructor(entityRepo, edgeRepo, projectRoot) {
31
+ this.#entityRepo = entityRepo;
32
+ this.#edgeRepo = edgeRepo;
54
33
  this.#projectRoot = projectRoot;
55
34
  }
56
35
  /**
57
36
  * 从 DB 中读取已扫描的模块数据。
58
- * 若无 module 实体,返回空数组(让调用侧决定是否重新扫描)。
37
+ * 若无 module 实体(含 host),返回空数组(让调用侧决定是否重新扫描)。
59
38
  */
60
- discover() {
61
- // 从 code_entities 查 entity_type = 'module'
62
- const moduleEntities = this.#db
63
- .prepare(`SELECT DISTINCT entity_id, name FROM code_entities
64
- WHERE entity_type = 'module' AND project_root = ?`)
65
- .all(this.#projectRoot);
66
- if (moduleEntities.length === 0) {
39
+ async discover() {
40
+ // 从 code_entities 查 entity_type = 'module'(排除 external/host 节点)
41
+ const moduleEntities = await this.#entityRepo.findLocalModules(this.#projectRoot);
42
+ // 检查是否存在 host 模块(用于后续分解)
43
+ const hasHostModules = await this.#hasHostModules();
44
+ if (moduleEntities.length === 0 && !hasHostModules) {
67
45
  return [];
68
46
  }
69
47
  // 收集 is_part_of 边关联的文件
70
48
  const moduleFiles = new Map();
71
49
  for (const me of moduleEntities) {
72
- const moduleName = me.entity_id;
50
+ const moduleName = me.entityId;
73
51
  moduleFiles.set(moduleName, new Set());
74
- const parts = this.#db
75
- .prepare(`SELECT ke.from_id FROM knowledge_edges ke
76
- WHERE ke.to_id = ? AND ke.to_type = 'module' AND ke.relation = 'is_part_of'`)
77
- .all(moduleName);
52
+ const parts = await this.#edgeRepo.findIncomingByRelation(moduleName, 'is_part_of');
78
53
  for (const part of parts) {
79
- const entity = this.#db
80
- .prepare(`SELECT file_path FROM code_entities
81
- WHERE entity_id = ? AND project_root = ? LIMIT 1`)
82
- .get(part.from_id, this.#projectRoot);
83
- if (entity?.file_path) {
84
- moduleFiles.get(moduleName).add(entity.file_path);
54
+ const entity = await this.#entityRepo.findByEntityIdOnly(part.fromId, this.#projectRoot);
55
+ if (entity?.filePath) {
56
+ moduleFiles.get(moduleName).add(entity.filePath);
85
57
  }
86
58
  }
87
59
  }
88
60
  // 策略 1.5: module 实体有但文件为空(SPM 只建了模块节点)
89
61
  const totalFileCount = [...moduleFiles.values()].reduce((sum, s) => sum + s.size, 0);
90
62
  if (totalFileCount === 0) {
91
- this.#enrichModuleFiles(moduleFiles);
63
+ await this.#enrichModuleFiles(moduleFiles);
92
64
  }
93
- return [...moduleFiles.entries()].map(([name, files]) => ({
65
+ // 读取模块 metadata 中的 configLayer 信息
66
+ const moduleLayerMap = await this.#readModuleLayerMetadata(moduleEntities);
67
+ const regularModules = [...moduleFiles.entries()].map(([name, files]) => ({
94
68
  name,
95
69
  inferredRole: inferTargetRole(name),
96
70
  files: [...files],
71
+ configLayer: moduleLayerMap.get(name),
97
72
  }));
73
+ // 策略 2: 分解 host 模块(主工程目录)为子模块
74
+ const hostSubModules = await this.#decomposeHostModules(moduleFiles);
75
+ return [...regularModules, ...hostSubModules];
76
+ }
77
+ /**
78
+ * 读取 config layers 元数据(如果存在)
79
+ * @returns 从 `__config_layers__` 实体中恢复的层级定义
80
+ */
81
+ async readConfigLayers() {
82
+ try {
83
+ const entity = await this.#entityRepo.findByEntityIdOnly('__config_layers__', this.#projectRoot);
84
+ if (!entity?.metadata) {
85
+ return null;
86
+ }
87
+ const meta = entity.metadata;
88
+ if (Array.isArray(meta.layers) && meta.layers.length > 0) {
89
+ const layers = meta.layers;
90
+ // 当存在 host 模块时,注入 Application 层(位于所有配置层之上)
91
+ if (await this.#hasHostModules()) {
92
+ const minOrder = Math.min(...layers.map((l) => l.order));
93
+ const hasAppLayer = layers.some((l) => l.name.toLowerCase() === 'application' || l.name.toLowerCase() === 'app');
94
+ if (!hasAppLayer) {
95
+ layers.unshift({
96
+ name: 'Application',
97
+ order: minOrder - 1,
98
+ accessibleLayers: layers.map((l) => l.name),
99
+ });
100
+ }
101
+ }
102
+ return layers;
103
+ }
104
+ }
105
+ catch {
106
+ /* skip parse error */
107
+ }
108
+ return null;
98
109
  }
99
110
  /* ─── 策略 1.5: 模块文件充填 ───────────────────── */
111
+ /**
112
+ * 从 code_entities metadata 中读取每个模块的 layer 信息
113
+ */
114
+ async #readModuleLayerMetadata(moduleEntities) {
115
+ const result = new Map();
116
+ for (const me of moduleEntities) {
117
+ const moduleName = me.entityId;
118
+ try {
119
+ const entity = await this.#entityRepo.findByEntityIdOnly(moduleName, this.#projectRoot);
120
+ if (entity?.metadata) {
121
+ const meta = entity.metadata;
122
+ if (meta.layer && typeof meta.layer === 'string') {
123
+ result.set(moduleName, meta.layer);
124
+ }
125
+ }
126
+ }
127
+ catch {
128
+ /* skip parse error */
129
+ }
130
+ }
131
+ return result;
132
+ }
133
+ /**
134
+ * 检查 DB 中是否存在 nodeType='host' 的模块实体
135
+ */
136
+ async #hasHostModules() {
137
+ try {
138
+ const cnt = await this.#entityRepo.countModulesByNodeType(this.#projectRoot, 'host');
139
+ return cnt > 0;
140
+ }
141
+ catch {
142
+ return false;
143
+ }
144
+ }
100
145
  /**
101
146
  * 为已知模块名填充文件路径:
102
147
  * a. 文件系统扫描(递归 4 层找模块同名目录)
103
148
  * b. DB code_entities.file_path 路径段匹配
104
149
  */
105
- #enrichModuleFiles(moduleFiles) {
150
+ async #enrichModuleFiles(moduleFiles) {
106
151
  const moduleNames = [...moduleFiles.keys()];
107
152
  // a. 文件系统扫描
108
153
  for (const modName of moduleNames) {
@@ -118,14 +163,10 @@ export class ModuleDiscoverer {
118
163
  if (totalAfterFs > 0) {
119
164
  return;
120
165
  }
121
- const allFiles = this.#db
122
- .prepare(`SELECT DISTINCT file_path FROM code_entities
123
- WHERE project_root = ? AND file_path IS NOT NULL AND entity_type != 'module'`)
124
- .all(this.#projectRoot);
166
+ const allFiles = await this.#entityRepo.findDistinctFilePaths(this.#projectRoot);
125
167
  // 长名优先,避免短名误匹配
126
168
  const sorted = [...moduleNames].sort((a, b) => b.length - a.length);
127
- for (const row of allFiles) {
128
- const filePath = row.file_path;
169
+ for (const filePath of allFiles) {
129
170
  if (!filePath) {
130
171
  continue;
131
172
  }
@@ -182,4 +223,111 @@ export class ModuleDiscoverer {
182
223
  }
183
224
  return files;
184
225
  }
226
+ /* ─── 策略 2: Host 模块分解 ────────────────────── */
227
+ /**
228
+ * 分解 host 类型模块(主工程目录)为子模块。
229
+ *
230
+ * 适用场景:混合项目(如 Boxfile/EasyBox + 主工程未模块化代码)中,
231
+ * host 模块包含大量按文件夹组织但未声明为独立模块的业务代码。
232
+ *
233
+ * 策略:
234
+ * 1. 从 DB 查询 nodeType='host' 的模块实体
235
+ * 2. 扫描 host 目录的子文件夹,每个含 ≥2 个源文件的文件夹视为隐式子模块
236
+ * 3. 排除已被现有模块覆盖的文件(避免重复计数)
237
+ * 4. 跳过资源目录(.xcassets, .bundle, .lproj 等)和第三方代码目录
238
+ * 5. 当项目有 configLayers 时,为子模块分配 Application 层(host 在所有声明层之上)
239
+ */
240
+ async #decomposeHostModules(existingModuleFiles) {
241
+ const hostEntities = await this.#entityRepo.findModulesByNodeTypes(this.#projectRoot, ['host']);
242
+ if (hostEntities.length === 0) {
243
+ return [];
244
+ }
245
+ // 检查是否有 configLayers — 决定是否分配 Application 层
246
+ const hasConfigLayers = (await this.readConfigLayers()) !== null;
247
+ // 已有模块名 + 所有已归属文件(用于去重)
248
+ const existingNames = new Set(existingModuleFiles.keys());
249
+ const allExistingFiles = new Set();
250
+ for (const files of existingModuleFiles.values()) {
251
+ for (const f of files) {
252
+ allExistingFiles.add(f);
253
+ }
254
+ }
255
+ const result = [];
256
+ for (const host of hostEntities) {
257
+ let meta = {};
258
+ try {
259
+ meta = host.metadata ?? {};
260
+ }
261
+ catch {
262
+ /* skip parse error */
263
+ }
264
+ const hostName = host.name;
265
+ const hostDir = meta.fullPath || path.join(this.#projectRoot, hostName);
266
+ if (!this.#isDirectory(hostDir)) {
267
+ continue;
268
+ }
269
+ let entries;
270
+ try {
271
+ entries = fs.readdirSync(hostDir, { withFileTypes: true });
272
+ }
273
+ catch {
274
+ continue;
275
+ }
276
+ const rootFiles = [];
277
+ for (const entry of entries) {
278
+ if (entry.isDirectory()) {
279
+ // 跳过隐藏目录、构建产物、资源目录
280
+ if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) {
281
+ continue;
282
+ }
283
+ if (HOST_SKIP_SUFFIXES.some((suffix) => entry.name.endsWith(suffix))) {
284
+ continue;
285
+ }
286
+ // 跳过第三方/供应商代码目录
287
+ if (HOST_VENDOR_DIRS.has(entry.name.toLowerCase())) {
288
+ continue;
289
+ }
290
+ const dirPath = path.join(hostDir, entry.name);
291
+ const files = this.#collectSourceFiles(dirPath).filter((f) => !allExistingFiles.has(f));
292
+ if (files.length < 2) {
293
+ continue;
294
+ }
295
+ // 名称冲突时加 host 前缀
296
+ const moduleName = existingNames.has(entry.name)
297
+ ? `${hostName}/${entry.name}`
298
+ : entry.name;
299
+ result.push({
300
+ name: moduleName,
301
+ inferredRole: inferTargetRole(entry.name),
302
+ files,
303
+ configLayer: hasConfigLayers ? 'Application' : undefined,
304
+ });
305
+ }
306
+ else if (entry.isFile() && SOURCE_EXTS.has(path.extname(entry.name).toLowerCase())) {
307
+ const fullPath = path.join(hostDir, entry.name);
308
+ if (!allExistingFiles.has(fullPath)) {
309
+ rootFiles.push(fullPath);
310
+ }
311
+ }
312
+ }
313
+ // 主工程根级文件归入宿主模块本身
314
+ if (rootFiles.length > 0) {
315
+ result.push({
316
+ name: hostName,
317
+ inferredRole: 'app',
318
+ files: rootFiles,
319
+ configLayer: hasConfigLayers ? 'Application' : undefined,
320
+ });
321
+ }
322
+ }
323
+ return result;
324
+ }
325
+ #isDirectory(dirPath) {
326
+ try {
327
+ return fs.statSync(dirPath).isDirectory();
328
+ }
329
+ catch {
330
+ return false;
331
+ }
332
+ }
185
333
  }
@@ -6,16 +6,23 @@
6
6
  *
7
7
  * @module PanoramaAggregator
8
8
  */
9
+ import type { BootstrapRepositoryImpl } from '../../repository/bootstrap/BootstrapRepository.js';
10
+ import type { CodeEntityRepositoryImpl } from '../../repository/code/CodeEntityRepository.js';
11
+ import type { KnowledgeEdgeRepositoryImpl } from '../../repository/knowledge/KnowledgeEdgeRepository.js';
12
+ import type { KnowledgeRepositoryImpl } from '../../repository/knowledge/KnowledgeRepository.impl.js';
9
13
  import type { CouplingAnalyzer } from './CouplingAnalyzer.js';
10
14
  import { DimensionAnalyzer } from './DimensionAnalyzer.js';
11
- import type { LayerInferrer } from './LayerInferrer.js';
12
- import type { CeDbLike, PanoramaResult } from './PanoramaTypes.js';
15
+ import type { ConfigLayer, LayerInferrer } from './LayerInferrer.js';
16
+ import type { PanoramaResult } from './PanoramaTypes.js';
13
17
  import type { ModuleCandidate, RoleRefiner } from './RoleRefiner.js';
14
18
  export interface PanoramaAggregatorOptions {
15
19
  roleRefiner: RoleRefiner;
16
20
  couplingAnalyzer: CouplingAnalyzer;
17
21
  layerInferrer: LayerInferrer;
18
- db: CeDbLike;
22
+ bootstrapRepo: BootstrapRepositoryImpl;
23
+ entityRepo: CodeEntityRepositoryImpl;
24
+ edgeRepo: KnowledgeEdgeRepositoryImpl;
25
+ knowledgeRepo: KnowledgeRepositoryImpl;
19
26
  projectRoot: string;
20
27
  dimensionAnalyzer?: DimensionAnalyzer;
21
28
  }
@@ -24,6 +31,10 @@ export declare class PanoramaAggregator {
24
31
  constructor(opts: PanoramaAggregatorOptions);
25
32
  /**
26
33
  * 计算完整全景数据
34
+ * @param moduleCandidates 模块候选列表
35
+ * @param options.configLayers 来自配置文件的层级声明(如 Boxfile layer 定义)
27
36
  */
28
- compute(moduleCandidates: ModuleCandidate[]): PanoramaResult;
37
+ compute(moduleCandidates: ModuleCandidate[], options?: {
38
+ configLayers?: ConfigLayer[] | null;
39
+ }): Promise<PanoramaResult>;
29
40
  }
@@ -8,38 +8,57 @@
8
8
  */
9
9
  var _a;
10
10
  import { DimensionAnalyzer } from './DimensionAnalyzer.js';
11
+ import { profileTechStack } from './TechStackProfiler.js';
11
12
  /* ═══ PanoramaAggregator Class ════════════════════════════ */
12
13
  export class PanoramaAggregator {
13
14
  #roleRefiner;
14
15
  #couplingAnalyzer;
15
16
  #layerInferrer;
16
- #db;
17
+ #entityRepo;
18
+ #edgeRepo;
19
+ #knowledgeRepo;
17
20
  #projectRoot;
18
21
  #dimensionAnalyzer;
19
22
  constructor(opts) {
20
23
  this.#roleRefiner = opts.roleRefiner;
21
24
  this.#couplingAnalyzer = opts.couplingAnalyzer;
22
25
  this.#layerInferrer = opts.layerInferrer;
23
- this.#db = opts.db;
26
+ this.#entityRepo = opts.entityRepo;
27
+ this.#edgeRepo = opts.edgeRepo;
28
+ this.#knowledgeRepo = opts.knowledgeRepo;
24
29
  this.#projectRoot = opts.projectRoot;
25
- this.#dimensionAnalyzer = opts.dimensionAnalyzer ?? new DimensionAnalyzer(opts.db);
30
+ this.#dimensionAnalyzer =
31
+ opts.dimensionAnalyzer ??
32
+ new DimensionAnalyzer(opts.bootstrapRepo, opts.entityRepo, opts.knowledgeRepo, opts.projectRoot);
26
33
  }
27
34
  /**
28
35
  * 计算完整全景数据
36
+ * @param moduleCandidates 模块候选列表
37
+ * @param options.configLayers 来自配置文件的层级声明(如 Boxfile layer 定义)
29
38
  */
30
- compute(moduleCandidates) {
39
+ async compute(moduleCandidates, options) {
31
40
  // 1. RoleRefiner: 精化角色
32
- const refinedRoles = this.#roleRefiner.refineAll(moduleCandidates);
41
+ const refinedRoles = await this.#roleRefiner.refineAll(moduleCandidates);
33
42
  // 2. 构建模块-文件映射
34
43
  const moduleFiles = new Map();
35
44
  for (const mc of moduleCandidates) {
36
45
  moduleFiles.set(mc.name, mc.files);
37
46
  }
38
- // 3. CouplingAnalyzer: 耦合分析
39
- const coupling = this.#couplingAnalyzer.analyze(moduleFiles);
40
- // 4. LayerInferrer: 层级推断
47
+ // 3. CouplingAnalyzer: 耦合分析(含外部依赖 fan-in)
48
+ const externalModules = await this.#collectExternalModules();
49
+ const coupling = await this.#couplingAnalyzer.analyze(moduleFiles, externalModules);
50
+ // 4. LayerInferrer: 层级推断(优先使用配置层级)
41
51
  const modules = moduleCandidates.map((m) => m.name);
42
- const layers = this.#layerInferrer.infer(coupling.edges, modules, coupling.cycles);
52
+ const configModuleLayerMap = new Map();
53
+ for (const mc of moduleCandidates) {
54
+ if (mc.configLayer) {
55
+ configModuleLayerMap.set(mc.name, mc.configLayer);
56
+ }
57
+ }
58
+ const layers = this.#layerInferrer.infer(coupling.edges, modules, coupling.cycles, {
59
+ configLayers: options?.configLayers,
60
+ moduleLayerMap: configModuleLayerMap.size > 0 ? configModuleLayerMap : undefined,
61
+ });
43
62
  // 5. 构建层级映射 (模块名 → 层级号)
44
63
  const moduleLayerMap = new Map();
45
64
  for (const level of layers.levels) {
@@ -48,7 +67,7 @@ export class PanoramaAggregator {
48
67
  }
49
68
  }
50
69
  // 6. 项目级 recipe 总数(recipe scope 通常为 universal,不做模块强关联)
51
- const projectRecipeCount = this.#getProjectRecipeCount();
70
+ const projectRecipeCount = await this.#getProjectRecipeCount();
52
71
  // 7. 计算总文件数
53
72
  let totalFiles = 0;
54
73
  for (const mc of moduleCandidates) {
@@ -75,16 +94,21 @@ export class PanoramaAggregator {
75
94
  coverageRatio: mc.files.length > 0 ? recipeCount / mc.files.length : 0,
76
95
  });
77
96
  }
78
- // 8.5 基于模块角色重命名层级(比模块名 pattern 更准确)
79
- this.#renameLayersByRole(layers, panoramaModules);
97
+ // 8.5 基于模块角色重命名层级(仅在拓扑推断模式下;配置层级保留原名)
98
+ if (!layers.configBased) {
99
+ this.#renameLayersByRole(layers, panoramaModules);
100
+ }
80
101
  // 9. 多维度知识健康分析 (替代旧的基于模块文件数的覆盖率模型)
81
102
  const moduleRoles = moduleCandidates.map((m) => {
82
103
  const pm = panoramaModules.get(m.name);
83
104
  return pm?.refinedRole ?? m.inferredRole;
84
105
  });
85
- const { radar, gaps } = this.#dimensionAnalyzer.analyze(moduleRoles);
106
+ const { radar, gaps } = await this.#dimensionAnalyzer.analyze(moduleRoles);
86
107
  // 10. 调用流概要
87
- const callFlowSummary = this.#computeCallFlowSummary();
108
+ const callFlowSummary = await this.#computeCallFlowSummary();
109
+ // 11. 外部依赖概况 + 技术栈画像
110
+ const externalDeps = await this.#buildExternalDepProfiles(coupling.externalDeps);
111
+ const techStack = externalDeps.length > 0 ? profileTechStack(externalDeps) : null;
88
112
  return {
89
113
  modules: panoramaModules,
90
114
  layers,
@@ -93,21 +117,72 @@ export class PanoramaAggregator {
93
117
  healthRadar: radar,
94
118
  callFlowSummary,
95
119
  projectRecipeCount,
120
+ externalDeps,
121
+ techStack,
96
122
  computedAt: Date.now(),
97
123
  };
98
124
  }
99
125
  /* ─── Project Recipe Count ──────────────────────── */
100
- #getProjectRecipeCount() {
126
+ async #getProjectRecipeCount() {
101
127
  try {
102
- const row = this.#db
103
- .prepare(`SELECT COUNT(*) as cnt FROM knowledge_entries WHERE lifecycle IN ('active', 'pending')`)
104
- .get();
105
- return Number(row?.cnt ?? 0);
128
+ return await this.#knowledgeRepo.countByCountableLifecycles();
106
129
  }
107
130
  catch {
108
131
  return 0;
109
132
  }
110
133
  }
134
+ /* ─── External Dependencies ─────────────────────── */
135
+ /**
136
+ * 从 code_entities 收集标记为 external 的模块名
137
+ */
138
+ async #collectExternalModules() {
139
+ try {
140
+ const rows = await this.#entityRepo.findModulesByNodeTypes(this.#projectRoot, [
141
+ 'external',
142
+ 'host',
143
+ ]);
144
+ return new Set(rows.map((r) => r.entityId));
145
+ }
146
+ catch {
147
+ return new Set();
148
+ }
149
+ }
150
+ /**
151
+ * 将 CouplingAnalyzer 的外部依赖统计转为 ExternalDepProfile
152
+ * 并从 code_entities 补充 layer/version 元数据
153
+ */
154
+ async #buildExternalDepProfiles(rawExternalDeps) {
155
+ if (rawExternalDeps.length === 0) {
156
+ return [];
157
+ }
158
+ // 查询外部依赖的元数据
159
+ const metadataMap = new Map();
160
+ try {
161
+ for (const dep of rawExternalDeps) {
162
+ const entity = await this.#entityRepo.findByEntityIdOnly(dep.name, this.#projectRoot);
163
+ if (entity?.metadata) {
164
+ const meta = entity.metadata;
165
+ metadataMap.set(dep.name, {
166
+ layer: meta.layer,
167
+ version: meta.version,
168
+ });
169
+ }
170
+ }
171
+ }
172
+ catch {
173
+ /* skip metadata enrichment errors */
174
+ }
175
+ return rawExternalDeps.map((dep) => {
176
+ const meta = metadataMap.get(dep.name);
177
+ return {
178
+ name: dep.name,
179
+ fanIn: dep.fanIn,
180
+ dependedBy: dep.dependedBy,
181
+ layer: meta?.layer,
182
+ version: meta?.version,
183
+ };
184
+ });
185
+ }
111
186
  /* ─── Layer Naming (role-based) ─────────────────── */
112
187
  /** 角色 → 层级名映射 */
113
188
  static #ROLE_TO_LAYER = {
@@ -165,63 +240,54 @@ export class PanoramaAggregator {
165
240
  layerName = 'Application';
166
241
  }
167
242
  }
168
- // 去重:已使用的名称追加 level 号
243
+ // 去重:优先尝试次高票角色名,仍冲突则追加位置描述
169
244
  if (usedNames.has(layerName)) {
170
- layerName = `${layerName} ${level.level}`;
245
+ // 尝试次高票角色
246
+ let resolved = false;
247
+ if (roleVotes.size > 1) {
248
+ const sortedRoles = [...roleVotes.entries()].sort((a, b) => b[1] - a[1]);
249
+ for (let i = 1; i < sortedRoles.length; i++) {
250
+ const altName = _a.#ROLE_TO_LAYER[sortedRoles[i][0]] ?? sortedRoles[i][0];
251
+ if (!usedNames.has(altName)) {
252
+ layerName = altName;
253
+ resolved = true;
254
+ break;
255
+ }
256
+ }
257
+ }
258
+ // 仍冲突:使用位置描述而非数字后缀
259
+ if (!resolved && usedNames.has(layerName)) {
260
+ const pos = level.level <= maxLevel * 0.33
261
+ ? 'Core'
262
+ : level.level >= maxLevel * 0.67
263
+ ? 'App'
264
+ : 'Mid';
265
+ const qualifiedName = `${pos} ${layerName}`;
266
+ layerName = usedNames.has(qualifiedName) ? `${layerName} L${level.level}` : qualifiedName;
267
+ }
171
268
  }
172
269
  usedNames.add(layerName);
173
270
  level.name = layerName;
174
271
  }
175
272
  }
176
273
  /* ─── Call Flow Summary ─────────────────────────── */
177
- #computeCallFlowSummary() {
274
+ async #computeCallFlowSummary() {
178
275
  // 最频繁被调用的方法
179
- const topCalled = this.#db
180
- .prepare(`SELECT to_id, COUNT(*) as call_count
181
- FROM knowledge_edges
182
- WHERE relation = 'calls'
183
- GROUP BY to_id
184
- ORDER BY call_count DESC
185
- LIMIT 10`)
186
- .all();
276
+ const topCalled = await this.#edgeRepo.findTopCalledNodes(10);
187
277
  // 入口点: 只有出度没有入度的方法
188
- const entryPoints = this.#db
189
- .prepare(`SELECT DISTINCT ke.from_id
190
- FROM knowledge_edges ke
191
- WHERE ke.relation = 'calls'
192
- AND ke.from_id NOT IN (
193
- SELECT to_id FROM knowledge_edges WHERE relation = 'calls'
194
- )
195
- LIMIT 20`)
196
- .all();
278
+ const entryPoints = await this.#edgeRepo.findEntryPoints(20);
197
279
  // 数据生产者: data_flow outFlow >> inFlow
198
- const dataProducers = this.#db
199
- .prepare(`SELECT from_id, COUNT(*) as out_cnt
200
- FROM knowledge_edges
201
- WHERE relation = 'data_flow'
202
- GROUP BY from_id
203
- HAVING out_cnt > 3
204
- ORDER BY out_cnt DESC
205
- LIMIT 10`)
206
- .all();
280
+ const dataProducers = await this.#edgeRepo.findTopDataFlowSources(10, 3);
207
281
  // 数据消费者: data_flow inFlow >> outFlow
208
- const dataConsumers = this.#db
209
- .prepare(`SELECT to_id, COUNT(*) as in_cnt
210
- FROM knowledge_edges
211
- WHERE relation = 'data_flow'
212
- GROUP BY to_id
213
- HAVING in_cnt > 3
214
- ORDER BY in_cnt DESC
215
- LIMIT 10`)
216
- .all();
282
+ const dataConsumers = await this.#edgeRepo.findTopDataFlowSinks(10, 3);
217
283
  return {
218
284
  topCalledMethods: topCalled.map((r) => ({
219
- id: r.to_id,
220
- callCount: Number(r.call_count),
285
+ id: r.toId,
286
+ callCount: r.callCount,
221
287
  })),
222
- entryPoints: entryPoints.map((r) => r.from_id),
223
- dataProducers: dataProducers.map((r) => r.from_id),
224
- dataConsumers: dataConsumers.map((r) => r.to_id),
288
+ entryPoints,
289
+ dataProducers,
290
+ dataConsumers,
225
291
  };
226
292
  }
227
293
  }
@@ -11,9 +11,13 @@
11
11
  *
12
12
  * @module PanoramaScanner
13
13
  */
14
+ import type { CodeEntityRepositoryImpl } from '../../repository/code/CodeEntityRepository.js';
15
+ import type { KnowledgeEdgeRepositoryImpl } from '../../repository/knowledge/KnowledgeEdgeRepository.js';
14
16
  export interface PanoramaScannerOptions {
15
17
  projectRoot: string;
16
18
  container: ScannerContainer;
19
+ entityRepo: CodeEntityRepositoryImpl;
20
+ edgeRepo: KnowledgeEdgeRepositoryImpl;
17
21
  logger?: ScannerLogger;
18
22
  }
19
23
  export interface ScannerContainer {
@@ -35,7 +39,7 @@ export declare class PanoramaScanner {
35
39
  /**
36
40
  * 检测 DB 中是否已有该项目的 code_entities 数据
37
41
  */
38
- hasData(): boolean;
42
+ hasData(): Promise<boolean>;
39
43
  /**
40
44
  * 确保全景数据存在。无数据时自动执行扫描。
41
45
  * 幂等:扫描过一次后不再重复(重启进程或手动 reset 可重新触发)。