autosnippet 3.3.0 → 3.3.3

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 (245) hide show
  1. package/dashboard/dist/assets/icons-BJ2mUBi8.js +1 -0
  2. package/dashboard/dist/assets/index-B659K9t5.js +128 -0
  3. package/dashboard/dist/assets/index-NCm40PMD.css +1 -0
  4. package/dashboard/dist/index.html +3 -3
  5. package/dist/bin/cli.d.ts +1 -0
  6. package/dist/bin/cli.js +284 -142
  7. package/dist/lib/agent/context/ExplorationTracker.d.ts +2 -0
  8. package/dist/lib/agent/context/ExplorationTracker.js +21 -3
  9. package/dist/lib/agent/core/ToolExecutionPipeline.d.ts +3 -1
  10. package/dist/lib/agent/core/ToolExecutionPipeline.js +8 -1
  11. package/dist/lib/agent/forge/DynamicComposer.d.ts +58 -0
  12. package/dist/lib/agent/forge/DynamicComposer.js +99 -0
  13. package/dist/lib/agent/forge/SandboxRunner.d.ts +60 -0
  14. package/dist/lib/agent/forge/SandboxRunner.js +251 -0
  15. package/dist/lib/agent/forge/TemporaryToolRegistry.d.ts +76 -0
  16. package/dist/lib/agent/forge/TemporaryToolRegistry.js +154 -0
  17. package/dist/lib/agent/forge/ToolForge.d.ts +92 -0
  18. package/dist/lib/agent/forge/ToolForge.js +239 -0
  19. package/dist/lib/agent/forge/ToolRequirementAnalyzer.d.ts +44 -0
  20. package/dist/lib/agent/forge/ToolRequirementAnalyzer.js +119 -0
  21. package/dist/lib/agent/tools/ToolRegistry.d.ts +2 -0
  22. package/dist/lib/agent/tools/ToolRegistry.js +4 -0
  23. package/dist/lib/agent/tools/composite.js +0 -1
  24. package/dist/lib/agent/tools/index.d.ts +2 -50
  25. package/dist/lib/agent/tools/index.js +2 -3
  26. package/dist/lib/agent/tools/lifecycle.d.ts +1 -58
  27. package/dist/lib/agent/tools/lifecycle.js +2 -75
  28. package/dist/lib/cli/KnowledgeSyncService.d.ts +26 -0
  29. package/dist/lib/cli/KnowledgeSyncService.js +33 -1
  30. package/dist/lib/cli/deploy/FileManifest.d.ts +0 -21
  31. package/dist/lib/cli/deploy/FileManifest.js +0 -11
  32. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +10 -0
  33. package/dist/lib/domain/knowledge/KnowledgeEntry.js +2 -0
  34. package/dist/lib/domain/knowledge/Lifecycle.d.ts +19 -2
  35. package/dist/lib/domain/knowledge/Lifecycle.js +32 -6
  36. package/dist/lib/domain/knowledge/UnifiedValidator.d.ts +1 -5
  37. package/dist/lib/domain/knowledge/UnifiedValidator.js +7 -44
  38. package/dist/lib/domain/knowledge/values/Stats.d.ts +29 -0
  39. package/dist/lib/domain/knowledge/values/Stats.js +41 -0
  40. package/dist/lib/external/mcp/McpServer.d.ts +19 -38
  41. package/dist/lib/external/mcp/McpServer.js +145 -117
  42. package/dist/lib/external/mcp/autoApproveInjector.js +0 -2
  43. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +26 -1
  44. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +41 -0
  45. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -0
  46. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +3 -0
  47. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +27 -0
  48. package/dist/lib/external/mcp/handlers/bootstrap/skills.js +1 -1
  49. package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -0
  50. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
  51. package/dist/lib/external/mcp/handlers/browse.d.ts +1 -0
  52. package/dist/lib/external/mcp/handlers/browse.js +2 -1
  53. package/dist/lib/external/mcp/handlers/consolidated.d.ts +117 -6
  54. package/dist/lib/external/mcp/handlers/consolidated.js +251 -71
  55. package/dist/lib/external/mcp/handlers/guard.d.ts +150 -0
  56. package/dist/lib/external/mcp/handlers/guard.js +239 -5
  57. package/dist/lib/external/mcp/handlers/knowledge.d.ts +0 -29
  58. package/dist/lib/external/mcp/handlers/knowledge.js +1 -76
  59. package/dist/lib/external/mcp/handlers/panorama.d.ts +36 -0
  60. package/dist/lib/external/mcp/handlers/panorama.js +156 -0
  61. package/dist/lib/external/mcp/handlers/system.d.ts +2 -54
  62. package/dist/lib/external/mcp/handlers/system.js +3 -113
  63. package/dist/lib/external/mcp/handlers/task.d.ts +13 -24
  64. package/dist/lib/external/mcp/handlers/task.js +218 -557
  65. package/dist/lib/external/mcp/handlers/types.d.ts +91 -8
  66. package/dist/lib/external/mcp/handlers/types.js +18 -1
  67. package/dist/lib/external/mcp/handlers/wiki-external.d.ts +18 -1
  68. package/dist/lib/external/mcp/handlers/wiki-external.js +16 -1
  69. package/dist/lib/external/mcp/tools.d.ts +18 -24
  70. package/dist/lib/external/mcp/tools.js +132 -159
  71. package/dist/lib/http/HttpServer.js +52 -0
  72. package/dist/lib/http/middleware/validate.js +7 -3
  73. package/dist/lib/http/routes/audit.d.ts +8 -0
  74. package/dist/lib/http/routes/audit.js +51 -0
  75. package/dist/lib/http/routes/guardReport.d.ts +10 -0
  76. package/dist/lib/http/routes/guardReport.js +143 -0
  77. package/dist/lib/http/routes/knowledge.js +32 -1
  78. package/dist/lib/http/routes/panorama.d.ts +11 -0
  79. package/dist/lib/http/routes/panorama.js +322 -0
  80. package/dist/lib/http/routes/signals.d.ts +10 -0
  81. package/dist/lib/http/routes/signals.js +104 -0
  82. package/dist/lib/http/routes/task.d.ts +2 -3
  83. package/dist/lib/http/routes/task.js +17 -347
  84. package/dist/lib/http/routes/violations.js +1 -1
  85. package/dist/lib/infrastructure/audit/AuditLogger.d.ts +6 -1
  86. package/dist/lib/infrastructure/audit/AuditLogger.js +14 -1
  87. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +202 -504
  88. package/dist/lib/infrastructure/database/drizzle/schema.js +38 -69
  89. package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.d.ts +8 -0
  90. package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.js +43 -0
  91. package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.d.ts +9 -0
  92. package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.js +24 -0
  93. package/dist/lib/infrastructure/logging/Logger.d.ts +2 -0
  94. package/dist/lib/infrastructure/logging/Logger.js +34 -7
  95. package/dist/lib/infrastructure/monitoring/ErrorTracker.js +3 -1
  96. package/dist/lib/infrastructure/monitoring/PerformanceMonitor.d.ts +2 -2
  97. package/dist/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -10
  98. package/dist/lib/infrastructure/notification/LarkNotifier.d.ts +24 -0
  99. package/dist/lib/infrastructure/notification/LarkNotifier.js +97 -0
  100. package/dist/lib/infrastructure/report/ReportStore.d.ts +45 -0
  101. package/dist/lib/infrastructure/report/ReportStore.js +133 -0
  102. package/dist/lib/infrastructure/signal/SignalAggregator.d.ts +18 -0
  103. package/dist/lib/infrastructure/signal/SignalAggregator.js +84 -0
  104. package/dist/lib/infrastructure/signal/SignalBridge.d.ts +13 -0
  105. package/dist/lib/infrastructure/signal/SignalBridge.js +20 -0
  106. package/dist/lib/infrastructure/signal/SignalBus.d.ts +63 -0
  107. package/dist/lib/infrastructure/signal/SignalBus.js +106 -0
  108. package/dist/lib/infrastructure/signal/SignalTraceWriter.d.ts +36 -0
  109. package/dist/lib/infrastructure/signal/SignalTraceWriter.js +130 -0
  110. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +18 -2
  111. package/dist/lib/injection/ServiceContainer.js +8 -0
  112. package/dist/lib/injection/ServiceMap.d.ts +16 -10
  113. package/dist/lib/injection/modules/AgentModule.d.ts +1 -1
  114. package/dist/lib/injection/modules/AgentModule.js +7 -1
  115. package/dist/lib/injection/modules/AppModule.d.ts +1 -1
  116. package/dist/lib/injection/modules/AppModule.js +4 -13
  117. package/dist/lib/injection/modules/GuardModule.js +27 -2
  118. package/dist/lib/injection/modules/InfraModule.d.ts +0 -1
  119. package/dist/lib/injection/modules/InfraModule.js +9 -7
  120. package/dist/lib/injection/modules/KnowledgeModule.d.ts +5 -0
  121. package/dist/lib/injection/modules/KnowledgeModule.js +131 -0
  122. package/dist/lib/injection/modules/PanoramaModule.d.ts +18 -0
  123. package/dist/lib/injection/modules/PanoramaModule.js +76 -0
  124. package/dist/lib/injection/modules/SignalModule.d.ts +10 -0
  125. package/dist/lib/injection/modules/SignalModule.js +84 -0
  126. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +1 -0
  127. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +6 -0
  128. package/dist/lib/service/bootstrap/BootstrapTaskManager.d.ts +3 -1
  129. package/dist/lib/service/bootstrap/BootstrapTaskManager.js +20 -1
  130. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +45 -0
  131. package/dist/lib/service/bootstrap/UiStartupTasks.js +101 -0
  132. package/dist/lib/service/delivery/AgentInstructionsGenerator.js +4 -5
  133. package/dist/lib/service/delivery/CursorDeliveryPipeline.d.ts +3 -1
  134. package/dist/lib/service/delivery/CursorDeliveryPipeline.js +13 -10
  135. package/dist/lib/service/delivery/RulesGenerator.js +3 -2
  136. package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +114 -0
  137. package/dist/lib/service/evolution/ConsolidationAdvisor.js +542 -0
  138. package/dist/lib/service/evolution/ContradictionDetector.d.ts +54 -0
  139. package/dist/lib/service/evolution/ContradictionDetector.js +253 -0
  140. package/dist/lib/service/evolution/DecayDetector.d.ts +71 -0
  141. package/dist/lib/service/evolution/DecayDetector.js +244 -0
  142. package/dist/lib/service/evolution/EnhancementSuggester.d.ts +38 -0
  143. package/dist/lib/service/evolution/EnhancementSuggester.js +220 -0
  144. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +82 -0
  145. package/dist/lib/service/evolution/KnowledgeMetabolism.js +167 -0
  146. package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +53 -0
  147. package/dist/lib/service/evolution/RedundancyAnalyzer.js +210 -0
  148. package/dist/lib/service/evolution/StagingManager.d.ts +57 -0
  149. package/dist/lib/service/evolution/StagingManager.js +201 -0
  150. package/dist/lib/service/guard/ComplianceReporter.d.ts +42 -2
  151. package/dist/lib/service/guard/ComplianceReporter.js +43 -5
  152. package/dist/lib/service/guard/CoverageAnalyzer.d.ts +54 -0
  153. package/dist/lib/service/guard/CoverageAnalyzer.js +149 -0
  154. package/dist/lib/service/guard/GuardCheckEngine.d.ts +42 -0
  155. package/dist/lib/service/guard/GuardCheckEngine.js +465 -14
  156. package/dist/lib/service/guard/GuardFeedbackLoop.d.ts +3 -0
  157. package/dist/lib/service/guard/GuardFeedbackLoop.js +9 -0
  158. package/dist/lib/service/guard/ReverseGuard.d.ts +73 -0
  159. package/dist/lib/service/guard/ReverseGuard.js +256 -0
  160. package/dist/lib/service/guard/RuleLearner.d.ts +12 -0
  161. package/dist/lib/service/guard/RuleLearner.js +38 -0
  162. package/dist/lib/service/guard/UncertaintyCollector.d.ts +83 -0
  163. package/dist/lib/service/guard/UncertaintyCollector.js +149 -0
  164. package/dist/lib/service/guard/ViolationsStore.d.ts +1 -0
  165. package/dist/lib/service/guard/ViolationsStore.js +33 -3
  166. package/dist/lib/service/knowledge/ConfidenceRouter.d.ts +13 -0
  167. package/dist/lib/service/knowledge/ConfidenceRouter.js +14 -0
  168. package/dist/lib/service/knowledge/KnowledgeService.js +22 -4
  169. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +68 -0
  170. package/dist/lib/service/knowledge/SourceRefReconciler.js +309 -0
  171. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +27 -0
  172. package/dist/lib/service/panorama/CouplingAnalyzer.js +192 -0
  173. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +28 -0
  174. package/dist/lib/service/panorama/DimensionAnalyzer.js +320 -0
  175. package/dist/lib/service/panorama/LayerInferrer.d.ts +19 -0
  176. package/dist/lib/service/panorama/LayerInferrer.js +182 -0
  177. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +24 -0
  178. package/dist/lib/service/panorama/ModuleDiscoverer.js +185 -0
  179. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +29 -0
  180. package/dist/lib/service/panorama/PanoramaAggregator.js +228 -0
  181. package/dist/lib/service/panorama/PanoramaScanner.d.ts +52 -0
  182. package/dist/lib/service/panorama/PanoramaScanner.js +188 -0
  183. package/dist/lib/service/panorama/PanoramaService.d.ts +125 -0
  184. package/dist/lib/service/panorama/PanoramaService.js +363 -0
  185. package/dist/lib/service/panorama/PanoramaTypes.d.ts +134 -0
  186. package/dist/lib/service/panorama/PanoramaTypes.js +6 -0
  187. package/dist/lib/service/panorama/RoleRefiner.d.ts +48 -0
  188. package/dist/lib/service/panorama/RoleRefiner.js +535 -0
  189. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  190. package/dist/lib/service/search/CoarseRanker.d.ts +7 -6
  191. package/dist/lib/service/search/CoarseRanker.js +11 -10
  192. package/dist/lib/service/search/FieldWeightedScorer.d.ts +81 -0
  193. package/dist/lib/service/search/FieldWeightedScorer.js +318 -0
  194. package/dist/lib/service/search/MultiSignalRanker.d.ts +3 -2
  195. package/dist/lib/service/search/MultiSignalRanker.js +17 -1
  196. package/dist/lib/service/search/SearchEngine.d.ts +9 -7
  197. package/dist/lib/service/search/SearchEngine.js +67 -10
  198. package/dist/lib/service/search/SearchTypes.d.ts +25 -3
  199. package/dist/lib/service/search/SearchTypes.js +6 -1
  200. package/dist/lib/service/signal/HitRecorder.d.ts +68 -0
  201. package/dist/lib/service/signal/HitRecorder.js +173 -0
  202. package/dist/lib/service/skills/SignalCollector.d.ts +3 -1
  203. package/dist/lib/service/skills/SignalCollector.js +31 -1
  204. package/dist/lib/service/task/IntentExtractor.d.ts +66 -0
  205. package/dist/lib/service/task/IntentExtractor.js +256 -0
  206. package/dist/lib/service/task/PrimeSearchPipeline.d.ts +54 -0
  207. package/dist/lib/service/task/PrimeSearchPipeline.js +113 -0
  208. package/dist/lib/service/vector/VectorService.d.ts +3 -0
  209. package/dist/lib/service/vector/VectorService.js +38 -4
  210. package/dist/lib/shared/schemas/mcp-tools.d.ts +41 -96
  211. package/dist/lib/shared/schemas/mcp-tools.js +59 -119
  212. package/dist/scripts/analyze-signals.d.ts +20 -0
  213. package/dist/scripts/analyze-signals.js +155 -0
  214. package/dist/scripts/diagnose-mcp.js +1 -1
  215. package/package.json +1 -1
  216. package/skills/autosnippet-create/SKILL.md +98 -89
  217. package/skills/autosnippet-devdocs/SKILL.md +55 -57
  218. package/templates/claude-code/hooks/autosnippet-session.sh +10 -15
  219. package/templates/cursor-hooks/hooks/session-start.sh +1 -1
  220. package/templates/guard-ci.yml +2 -2
  221. package/templates/instructions/agent-static.md +2 -1
  222. package/templates/instructions/conventions.md +5 -6
  223. package/templates/recipes-setup/README.md +1 -2
  224. package/templates/recipes-setup/_template.md +39 -39
  225. package/dashboard/dist/assets/icons-BofcEZ3f.js +0 -1
  226. package/dashboard/dist/assets/index-D0whuycy.css +0 -1
  227. package/dashboard/dist/assets/index-SiN1GChm.js +0 -128
  228. package/dist/lib/domain/task/Task.d.ts +0 -140
  229. package/dist/lib/domain/task/Task.js +0 -254
  230. package/dist/lib/domain/task/TaskDependency.d.ts +0 -23
  231. package/dist/lib/domain/task/TaskDependency.js +0 -34
  232. package/dist/lib/domain/task/TaskIdGenerator.d.ts +0 -40
  233. package/dist/lib/domain/task/TaskIdGenerator.js +0 -75
  234. package/dist/lib/domain/task/index.d.ts +0 -4
  235. package/dist/lib/domain/task/index.js +0 -4
  236. package/dist/lib/infrastructure/database/migrations/002_add_tasks.d.ts +0 -11
  237. package/dist/lib/infrastructure/database/migrations/002_add_tasks.js +0 -86
  238. package/dist/lib/repository/task/TaskRepository.impl.d.ts +0 -171
  239. package/dist/lib/repository/task/TaskRepository.impl.js +0 -347
  240. package/dist/lib/service/task/TaskGraphService.d.ts +0 -222
  241. package/dist/lib/service/task/TaskGraphService.js +0 -597
  242. package/dist/lib/service/task/TaskKnowledgeBridge.d.ts +0 -95
  243. package/dist/lib/service/task/TaskKnowledgeBridge.js +0 -298
  244. package/dist/lib/service/task/TaskReadyEngine.d.ts +0 -84
  245. package/dist/lib/service/task/TaskReadyEngine.js +0 -115
@@ -0,0 +1,182 @@
1
+ /**
2
+ * LayerInferrer — 拓扑排序层级推断
3
+ *
4
+ * 基于模块依赖图,通过去环 + 拓扑排序 + 最长路径法推断架构层级 (L0-Ln)。
5
+ * 底层 (L0) = Foundation/Core,顶层 = App/UI。
6
+ *
7
+ * @module LayerInferrer
8
+ */
9
+ /* ═══ Constants ═══════════════════════════════════════════ */
10
+ /** 层级命名启发式 — 按优先级排列,匹配模块名(边界安全) */
11
+ const LAYER_NAME_HINTS = [
12
+ { pattern: /^(foundation|core|base|shared|common)$/i, name: 'Foundation', bias: -2 },
13
+ { pattern: /foundation/i, name: 'Foundation', bias: -2 },
14
+ { pattern: /^(model|entity|dto)$/i, name: 'Model', bias: -1 },
15
+ { pattern: /service|repository|manager|provider|store/i, name: 'Service', bias: 0 },
16
+ { pattern: /network|api|http/i, name: 'Networking', bias: 0 },
17
+ { pattern: /(?:^ui$|^ui[A-Z]|view|screen|component|widget)/i, name: 'UI', bias: 1 },
18
+ { pattern: /router|coordinator|navigation/i, name: 'Routing', bias: 1 },
19
+ { pattern: /^(app|main|launch|entry)$/i, name: 'Application', bias: 2 },
20
+ { pattern: /test|spec|mock/i, name: 'Test', bias: 3 },
21
+ ];
22
+ /* ═══ LayerInferrer Class ═════════════════════════════════ */
23
+ export class LayerInferrer {
24
+ /**
25
+ * 从模块依赖边推断架构层级
26
+ * @param edges - 模块间依赖边 (from depends_on/calls/data_flow to)
27
+ * @param modules - 所有模块名
28
+ * @param cycles - 已检测到的循环依赖
29
+ */
30
+ infer(edges, modules, cycles) {
31
+ // 1. 建图 (邻接表: from → to[])
32
+ const adjacency = new Map();
33
+ const reverseAdj = new Map();
34
+ const allModules = new Set(modules);
35
+ for (const mod of allModules) {
36
+ adjacency.set(mod, new Set());
37
+ reverseAdj.set(mod, new Set());
38
+ }
39
+ // 收集环中的节点
40
+ const cycleEdges = new Set();
41
+ for (const c of cycles) {
42
+ for (let i = 0; i < c.cycle.length; i++) {
43
+ const from = c.cycle[i];
44
+ const to = c.cycle[(i + 1) % c.cycle.length];
45
+ cycleEdges.add(`${from}→${to}`);
46
+ }
47
+ }
48
+ // 2. 添加边 (跳过环边)
49
+ const violations = [];
50
+ for (const edge of edges) {
51
+ if (!allModules.has(edge.from) || !allModules.has(edge.to) || edge.from === edge.to) {
52
+ continue;
53
+ }
54
+ const edgeKey = `${edge.from}→${edge.to}`;
55
+ if (cycleEdges.has(edgeKey)) {
56
+ // 环边作为违规记录,不加入 DAG
57
+ continue;
58
+ }
59
+ adjacency.get(edge.from).add(edge.to);
60
+ reverseAdj.get(edge.to).add(edge.from);
61
+ }
62
+ // 3. 拓扑排序 (Kahn's algorithm)
63
+ const inDegree = new Map();
64
+ for (const mod of allModules) {
65
+ inDegree.set(mod, reverseAdj.get(mod)?.size ?? 0);
66
+ }
67
+ const queue = [];
68
+ for (const [mod, deg] of inDegree) {
69
+ if (deg === 0) {
70
+ queue.push(mod);
71
+ }
72
+ }
73
+ const order = [];
74
+ while (queue.length > 0) {
75
+ const node = queue.shift();
76
+ order.push(node);
77
+ for (const neighbor of adjacency.get(node) ?? []) {
78
+ const newDeg = (inDegree.get(neighbor) ?? 1) - 1;
79
+ inDegree.set(neighbor, newDeg);
80
+ if (newDeg === 0) {
81
+ queue.push(neighbor);
82
+ }
83
+ }
84
+ }
85
+ // 未排入的节点 (仍在环中) 追加到末尾
86
+ for (const mod of allModules) {
87
+ if (!order.includes(mod)) {
88
+ order.push(mod);
89
+ }
90
+ }
91
+ // 4. 分配层级: 最长路径法
92
+ // A 依赖 B → A 的 level ≥ B 的 level + 1
93
+ // reverseAdj: "B 被 A 依赖" → predecessors 是 reverseAdj(node) = {A}
94
+ // 但我们要的是 "A 依赖 B" → A 的 predecessors = adjacency(A) 出度目标的 level
95
+ // 换言之: level(A) = max(level(dep) for dep in adjacency(A)) + 1
96
+ // 底层 (无出度) = L0
97
+ const levels = new Map();
98
+ // 反向遍历: 从源头 (无出度) 开始
99
+ const reverseOrder = [...order].reverse();
100
+ for (const node of reverseOrder) {
101
+ const deps = adjacency.get(node) ?? new Set();
102
+ if (deps.size === 0) {
103
+ levels.set(node, 0);
104
+ }
105
+ else {
106
+ let maxDepLevel = 0;
107
+ for (const dep of deps) {
108
+ maxDepLevel = Math.max(maxDepLevel, levels.get(dep) ?? 0);
109
+ }
110
+ levels.set(node, maxDepLevel + 1);
111
+ }
112
+ }
113
+ // 5. 聚合: 同层模块分组
114
+ const layerGroups = new Map();
115
+ for (const [mod, level] of levels) {
116
+ if (!layerGroups.has(level)) {
117
+ layerGroups.set(level, []);
118
+ }
119
+ layerGroups.get(level).push(mod);
120
+ }
121
+ // 按 level 排序
122
+ const sortedLevels = [...layerGroups.entries()].sort((a, b) => a[0] - b[0]);
123
+ // 6. 推断层级名
124
+ const levelEntries = sortedLevels.map(([level, mods]) => ({
125
+ level,
126
+ name: this.#inferLayerName(mods, level, sortedLevels.length),
127
+ modules: mods.sort(),
128
+ }));
129
+ // 7. 检测层级违规 (高层 → 低层调用正常;低层 → 高层调用为违规)
130
+ for (const edge of edges) {
131
+ const fromLevel = levels.get(edge.from);
132
+ const toLevel = levels.get(edge.to);
133
+ if (fromLevel !== undefined && toLevel !== undefined && fromLevel < toLevel) {
134
+ violations.push({
135
+ from: edge.from,
136
+ to: edge.to,
137
+ fromLayer: fromLevel,
138
+ toLayer: toLevel,
139
+ relation: edge.relation,
140
+ });
141
+ }
142
+ }
143
+ return { levels: levelEntries, violations };
144
+ }
145
+ /* ─── Layer Naming ──────────────────────────────── */
146
+ #inferLayerName(modules, level, totalLevels) {
147
+ // 投票: 每个匹配的 hint 累加权重,取最高分的名称
148
+ const votes = new Map();
149
+ for (const mod of modules) {
150
+ for (const hint of LAYER_NAME_HINTS) {
151
+ if (hint.pattern.test(mod)) {
152
+ votes.set(hint.name, (votes.get(hint.name) ?? 0) + 1);
153
+ break; // 每个模块只投一票(匹配第一个 hint)
154
+ }
155
+ }
156
+ }
157
+ if (votes.size > 0) {
158
+ // 选最高票
159
+ let best = '';
160
+ let bestCount = 0;
161
+ for (const [name, count] of votes) {
162
+ if (count > bestCount) {
163
+ best = name;
164
+ bestCount = count;
165
+ }
166
+ }
167
+ return best;
168
+ }
169
+ // 基于层级位置推断
170
+ const position = totalLevels > 1 ? level / (totalLevels - 1) : 0.5;
171
+ if (position <= 0.2) {
172
+ return 'Foundation';
173
+ }
174
+ if (position <= 0.5) {
175
+ return 'Service';
176
+ }
177
+ if (position <= 0.8) {
178
+ return 'Feature';
179
+ }
180
+ return 'Application';
181
+ }
182
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * ModuleDiscoverer — 模块发现与文件归属
3
+ *
4
+ * 从 DB(code_entities / knowledge_edges)读取已扫描的模块数据。
5
+ * 前提:PanoramaScanner.ensureData() 保证 DB 中已有结构数据。
6
+ *
7
+ * 策略 1: code_entities entity_type='module' + is_part_of 边 → 完整数据
8
+ * 策略 1.5: module 实体存在但无 is_part_of 边 → 文件系统 + DB 路径补全
9
+ *
10
+ * 若 DB 中无 module 实体,返回空数组(由 PanoramaScanner 负责兜底扫描)。
11
+ *
12
+ * @module ModuleDiscoverer
13
+ */
14
+ import type { CeDbLike } from './PanoramaTypes.js';
15
+ import type { ModuleCandidate } from './RoleRefiner.js';
16
+ export declare class ModuleDiscoverer {
17
+ #private;
18
+ constructor(db: CeDbLike, projectRoot: string);
19
+ /**
20
+ * 从 DB 中读取已扫描的模块数据。
21
+ * 若无 module 实体,返回空数组(让调用侧决定是否重新扫描)。
22
+ */
23
+ discover(): ModuleCandidate[];
24
+ }
@@ -0,0 +1,185 @@
1
+ /**
2
+ * ModuleDiscoverer — 模块发现与文件归属
3
+ *
4
+ * 从 DB(code_entities / knowledge_edges)读取已扫描的模块数据。
5
+ * 前提:PanoramaScanner.ensureData() 保证 DB 中已有结构数据。
6
+ *
7
+ * 策略 1: code_entities entity_type='module' + is_part_of 边 → 完整数据
8
+ * 策略 1.5: module 实体存在但无 is_part_of 边 → 文件系统 + DB 路径补全
9
+ *
10
+ * 若 DB 中无 module 实体,返回空数组(由 PanoramaScanner 负责兜底扫描)。
11
+ *
12
+ * @module ModuleDiscoverer
13
+ */
14
+ import fs from 'node:fs';
15
+ import path from 'node:path';
16
+ import { inferTargetRole } from '../../external/mcp/handlers/TargetClassifier.js';
17
+ /* ═══ 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
+ ]);
48
+ /* ═══ ModuleDiscoverer Class ══════════════════════════════ */
49
+ export class ModuleDiscoverer {
50
+ #db;
51
+ #projectRoot;
52
+ constructor(db, projectRoot) {
53
+ this.#db = db;
54
+ this.#projectRoot = projectRoot;
55
+ }
56
+ /**
57
+ * 从 DB 中读取已扫描的模块数据。
58
+ * 若无 module 实体,返回空数组(让调用侧决定是否重新扫描)。
59
+ */
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) {
67
+ return [];
68
+ }
69
+ // 收集 is_part_of 边关联的文件
70
+ const moduleFiles = new Map();
71
+ for (const me of moduleEntities) {
72
+ const moduleName = me.entity_id;
73
+ 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);
78
+ 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);
85
+ }
86
+ }
87
+ }
88
+ // 策略 1.5: module 实体有但文件为空(SPM 只建了模块节点)
89
+ const totalFileCount = [...moduleFiles.values()].reduce((sum, s) => sum + s.size, 0);
90
+ if (totalFileCount === 0) {
91
+ this.#enrichModuleFiles(moduleFiles);
92
+ }
93
+ return [...moduleFiles.entries()].map(([name, files]) => ({
94
+ name,
95
+ inferredRole: inferTargetRole(name),
96
+ files: [...files],
97
+ }));
98
+ }
99
+ /* ─── 策略 1.5: 模块文件充填 ───────────────────── */
100
+ /**
101
+ * 为已知模块名填充文件路径:
102
+ * a. 文件系统扫描(递归 4 层找模块同名目录)
103
+ * b. DB code_entities.file_path 路径段匹配
104
+ */
105
+ #enrichModuleFiles(moduleFiles) {
106
+ const moduleNames = [...moduleFiles.keys()];
107
+ // a. 文件系统扫描
108
+ for (const modName of moduleNames) {
109
+ const dir = this.#findModuleDir(this.#projectRoot, modName, 4);
110
+ if (dir) {
111
+ for (const f of this.#collectSourceFiles(dir)) {
112
+ moduleFiles.get(modName).add(f);
113
+ }
114
+ }
115
+ }
116
+ // b. 如果 FS 扫描仍为空 → DB 路径匹配
117
+ const totalAfterFs = [...moduleFiles.values()].reduce((sum, s) => sum + s.size, 0);
118
+ if (totalAfterFs > 0) {
119
+ return;
120
+ }
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);
125
+ // 长名优先,避免短名误匹配
126
+ const sorted = [...moduleNames].sort((a, b) => b.length - a.length);
127
+ for (const row of allFiles) {
128
+ const filePath = row.file_path;
129
+ if (!filePath) {
130
+ continue;
131
+ }
132
+ for (const modName of sorted) {
133
+ if (filePath.includes(`/${modName}/`) || filePath.startsWith(`${modName}/`)) {
134
+ moduleFiles.get(modName).add(filePath);
135
+ break; // 一个文件只属于一个模块
136
+ }
137
+ }
138
+ }
139
+ }
140
+ /* ─── 文件系统辅助 ────────────────────────────── */
141
+ #findModuleDir(rootDir, targetName, maxDepth) {
142
+ if (maxDepth <= 0) {
143
+ return null;
144
+ }
145
+ try {
146
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
147
+ for (const entry of entries) {
148
+ if (!entry.isDirectory() || SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) {
149
+ continue;
150
+ }
151
+ const fullPath = path.join(rootDir, entry.name);
152
+ if (entry.name === targetName) {
153
+ return fullPath;
154
+ }
155
+ const found = this.#findModuleDir(fullPath, targetName, maxDepth - 1);
156
+ if (found) {
157
+ return found;
158
+ }
159
+ }
160
+ }
161
+ catch {
162
+ // 无法读取目录
163
+ }
164
+ return null;
165
+ }
166
+ #collectSourceFiles(dir) {
167
+ const files = [];
168
+ try {
169
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
170
+ for (const entry of entries) {
171
+ const fullPath = path.join(dir, entry.name);
172
+ if (entry.isDirectory() && !entry.name.startsWith('.') && !SKIP_DIRS.has(entry.name)) {
173
+ files.push(...this.#collectSourceFiles(fullPath));
174
+ }
175
+ else if (entry.isFile() && SOURCE_EXTS.has(path.extname(entry.name).toLowerCase())) {
176
+ files.push(fullPath);
177
+ }
178
+ }
179
+ }
180
+ catch {
181
+ // 无法读取
182
+ }
183
+ return files;
184
+ }
185
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * PanoramaAggregator — 全景数据汇总
3
+ *
4
+ * 编排 RoleRefiner → CouplingAnalyzer → LayerInferrer,
5
+ * 汇总为统一的 PanoramaResult,附加知识覆盖率和空白区检测。
6
+ *
7
+ * @module PanoramaAggregator
8
+ */
9
+ import type { CouplingAnalyzer } from './CouplingAnalyzer.js';
10
+ import { DimensionAnalyzer } from './DimensionAnalyzer.js';
11
+ import type { LayerInferrer } from './LayerInferrer.js';
12
+ import type { CeDbLike, PanoramaResult } from './PanoramaTypes.js';
13
+ import type { ModuleCandidate, RoleRefiner } from './RoleRefiner.js';
14
+ export interface PanoramaAggregatorOptions {
15
+ roleRefiner: RoleRefiner;
16
+ couplingAnalyzer: CouplingAnalyzer;
17
+ layerInferrer: LayerInferrer;
18
+ db: CeDbLike;
19
+ projectRoot: string;
20
+ dimensionAnalyzer?: DimensionAnalyzer;
21
+ }
22
+ export declare class PanoramaAggregator {
23
+ #private;
24
+ constructor(opts: PanoramaAggregatorOptions);
25
+ /**
26
+ * 计算完整全景数据
27
+ */
28
+ compute(moduleCandidates: ModuleCandidate[]): PanoramaResult;
29
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * PanoramaAggregator — 全景数据汇总
3
+ *
4
+ * 编排 RoleRefiner → CouplingAnalyzer → LayerInferrer,
5
+ * 汇总为统一的 PanoramaResult,附加知识覆盖率和空白区检测。
6
+ *
7
+ * @module PanoramaAggregator
8
+ */
9
+ var _a;
10
+ import { DimensionAnalyzer } from './DimensionAnalyzer.js';
11
+ /* ═══ PanoramaAggregator Class ════════════════════════════ */
12
+ export class PanoramaAggregator {
13
+ #roleRefiner;
14
+ #couplingAnalyzer;
15
+ #layerInferrer;
16
+ #db;
17
+ #projectRoot;
18
+ #dimensionAnalyzer;
19
+ constructor(opts) {
20
+ this.#roleRefiner = opts.roleRefiner;
21
+ this.#couplingAnalyzer = opts.couplingAnalyzer;
22
+ this.#layerInferrer = opts.layerInferrer;
23
+ this.#db = opts.db;
24
+ this.#projectRoot = opts.projectRoot;
25
+ this.#dimensionAnalyzer = opts.dimensionAnalyzer ?? new DimensionAnalyzer(opts.db);
26
+ }
27
+ /**
28
+ * 计算完整全景数据
29
+ */
30
+ compute(moduleCandidates) {
31
+ // 1. RoleRefiner: 精化角色
32
+ const refinedRoles = this.#roleRefiner.refineAll(moduleCandidates);
33
+ // 2. 构建模块-文件映射
34
+ const moduleFiles = new Map();
35
+ for (const mc of moduleCandidates) {
36
+ moduleFiles.set(mc.name, mc.files);
37
+ }
38
+ // 3. CouplingAnalyzer: 耦合分析
39
+ const coupling = this.#couplingAnalyzer.analyze(moduleFiles);
40
+ // 4. LayerInferrer: 层级推断
41
+ const modules = moduleCandidates.map((m) => m.name);
42
+ const layers = this.#layerInferrer.infer(coupling.edges, modules, coupling.cycles);
43
+ // 5. 构建层级映射 (模块名 → 层级号)
44
+ const moduleLayerMap = new Map();
45
+ for (const level of layers.levels) {
46
+ for (const mod of level.modules) {
47
+ moduleLayerMap.set(mod, level.level);
48
+ }
49
+ }
50
+ // 6. 项目级 recipe 总数(recipe scope 通常为 universal,不做模块强关联)
51
+ const projectRecipeCount = this.#getProjectRecipeCount();
52
+ // 7. 计算总文件数
53
+ let totalFiles = 0;
54
+ for (const mc of moduleCandidates) {
55
+ totalFiles += mc.files.length;
56
+ }
57
+ // 8. 汇总 PanoramaModule
58
+ // 模块 recipeCount 按文件数等比分配项目级 recipe(反映覆盖贡献度)
59
+ const panoramaModules = new Map();
60
+ for (const mc of moduleCandidates) {
61
+ const refined = refinedRoles.get(mc.name);
62
+ const metrics = coupling.metrics.get(mc.name);
63
+ const recipeCount = totalFiles > 0 ? Math.round((projectRecipeCount * mc.files.length) / totalFiles) : 0;
64
+ panoramaModules.set(mc.name, {
65
+ name: mc.name,
66
+ inferredRole: mc.inferredRole,
67
+ refinedRole: refined?.refinedRole ?? mc.inferredRole,
68
+ roleConfidence: refined?.confidence ?? 0,
69
+ layer: moduleLayerMap.get(mc.name) ?? 0,
70
+ fanIn: metrics?.fanIn ?? 0,
71
+ fanOut: metrics?.fanOut ?? 0,
72
+ files: mc.files,
73
+ fileCount: mc.files.length,
74
+ recipeCount,
75
+ coverageRatio: mc.files.length > 0 ? recipeCount / mc.files.length : 0,
76
+ });
77
+ }
78
+ // 8.5 基于模块角色重命名层级(比模块名 pattern 更准确)
79
+ this.#renameLayersByRole(layers, panoramaModules);
80
+ // 9. 多维度知识健康分析 (替代旧的基于模块文件数的覆盖率模型)
81
+ const moduleRoles = moduleCandidates.map((m) => {
82
+ const pm = panoramaModules.get(m.name);
83
+ return pm?.refinedRole ?? m.inferredRole;
84
+ });
85
+ const { radar, gaps } = this.#dimensionAnalyzer.analyze(moduleRoles);
86
+ // 10. 调用流概要
87
+ const callFlowSummary = this.#computeCallFlowSummary();
88
+ return {
89
+ modules: panoramaModules,
90
+ layers,
91
+ cycles: coupling.cycles,
92
+ gaps,
93
+ healthRadar: radar,
94
+ callFlowSummary,
95
+ projectRecipeCount,
96
+ computedAt: Date.now(),
97
+ };
98
+ }
99
+ /* ─── Project Recipe Count ──────────────────────── */
100
+ #getProjectRecipeCount() {
101
+ 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);
106
+ }
107
+ catch {
108
+ return 0;
109
+ }
110
+ }
111
+ /* ─── Layer Naming (role-based) ─────────────────── */
112
+ /** 角色 → 层级名映射 */
113
+ static #ROLE_TO_LAYER = {
114
+ core: 'Foundation',
115
+ foundation: 'Foundation',
116
+ model: 'Model',
117
+ service: 'Service',
118
+ networking: 'Infrastructure',
119
+ storage: 'Infrastructure',
120
+ ui: 'UI',
121
+ feature: 'Feature',
122
+ config: 'Configuration',
123
+ test: 'Test',
124
+ app: 'Application',
125
+ };
126
+ /**
127
+ * 基于模块 refinedRole 投票重命名层级
128
+ * 比模块名 pattern 匹配更准确(避免 BDUIKit 被误匹配为 Foundation 等问题)
129
+ */
130
+ #renameLayersByRole(layers, panoramaModules) {
131
+ const usedNames = new Set();
132
+ const maxLevel = Math.max(...layers.levels.map((l) => l.level), 0);
133
+ for (const level of layers.levels) {
134
+ // 只统计有文件的模块(排除 0 文件的第三方依赖干扰)
135
+ const roleVotes = new Map();
136
+ for (const modName of level.modules) {
137
+ const mod = panoramaModules.get(modName);
138
+ if (mod && mod.fileCount > 0) {
139
+ const role = mod.refinedRole || mod.inferredRole;
140
+ roleVotes.set(role, (roleVotes.get(role) ?? 0) + 1);
141
+ }
142
+ }
143
+ let layerName;
144
+ if (roleVotes.size === 0) {
145
+ // 全部是 0 文件模块 → 用位置推断
146
+ layerName =
147
+ level.level === 0 ? 'Foundation' : level.level === maxLevel ? 'Application' : 'Feature';
148
+ }
149
+ else {
150
+ // 选最高票角色
151
+ let bestRole = '';
152
+ let bestCount = 0;
153
+ for (const [role, count] of roleVotes) {
154
+ if (count > bestCount) {
155
+ bestRole = role;
156
+ bestCount = count;
157
+ }
158
+ }
159
+ layerName = _a.#ROLE_TO_LAYER[bestRole] ?? 'Feature';
160
+ // 位置修正:最底层优先 Foundation,最顶层优先 Application
161
+ if (level.level === 0 && roleVotes.has('core')) {
162
+ layerName = 'Foundation';
163
+ }
164
+ else if (level.level === maxLevel && layers.levels.length > 1) {
165
+ layerName = 'Application';
166
+ }
167
+ }
168
+ // 去重:已使用的名称追加 level 号
169
+ if (usedNames.has(layerName)) {
170
+ layerName = `${layerName} ${level.level}`;
171
+ }
172
+ usedNames.add(layerName);
173
+ level.name = layerName;
174
+ }
175
+ }
176
+ /* ─── Call Flow Summary ─────────────────────────── */
177
+ #computeCallFlowSummary() {
178
+ // 最频繁被调用的方法
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();
187
+ // 入口点: 只有出度没有入度的方法
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();
197
+ // 数据生产者: 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();
207
+ // 数据消费者: 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();
217
+ return {
218
+ topCalledMethods: topCalled.map((r) => ({
219
+ id: r.to_id,
220
+ callCount: Number(r.call_count),
221
+ })),
222
+ entryPoints: entryPoints.map((r) => r.from_id),
223
+ dataProducers: dataProducers.map((r) => r.from_id),
224
+ dataConsumers: dataConsumers.map((r) => r.to_id),
225
+ };
226
+ }
227
+ }
228
+ _a = PanoramaAggregator;