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
@@ -1,16 +1,38 @@
1
1
  /**
2
- * QualityScorer — Recipe 质量评分器
3
- * 5 个维度: completeness(0.35) + format(0.25) + codeQuality(0.25) + metadata(0.15) + engagement(0)
4
- * 每个维度评分 0-1,加权求和
2
+ * QualityScorer v2 — Recipe 质量评分器
3
+ *
4
+ * 面向知识管理场景重新设计,采用渐进式评分(非二元判断),
5
+ * 充分利用 KnowledgeEntry 所有可用字段。
6
+ *
7
+ * 5 维度加权:
8
+ * - completeness (0.25): 结构完整性 — 核心字段齐全度
9
+ * - contentDepth (0.30): 内容深度 — markdown 丰富度、推理、溯源
10
+ * - deliveryReady (0.20): 交付就绪 — trigger/language/tags/category
11
+ * - actionability (0.15): 可操作性 — coreCode、do/dont/when 质量
12
+ * - provenance (0.10): 溯源可信 — confidence、sources、authority
13
+ *
14
+ * 设计参考:
15
+ * - RAG Triad (TruLens): Relevance + Groundedness + Answer Relevance
16
+ * - RAGAS: Context Precision + Faithfulness + Factual Correctness
17
+ * - SonarQube: 多维度渐进评级,非二元判断
5
18
  */
6
- interface RecipeInput {
19
+ export interface RecipeInput {
7
20
  title?: string;
8
21
  trigger?: string;
9
- code?: string;
22
+ description?: string;
10
23
  language?: string;
11
24
  category?: string;
12
- summary?: string;
25
+ doClause?: string;
26
+ dontClause?: string;
27
+ whenClause?: string;
28
+ coreCode?: string;
13
29
  usageGuide?: string;
30
+ contentMarkdown?: string;
31
+ contentRationale?: string;
32
+ reasoningWhyStandard?: string;
33
+ reasoningSources?: string[];
34
+ reasoningConfidence?: number;
35
+ source?: string;
14
36
  headers?: string[];
15
37
  tags?: string[];
16
38
  views?: number;
@@ -18,25 +40,23 @@ interface RecipeInput {
18
40
  rating?: number;
19
41
  [key: string]: unknown;
20
42
  }
21
- interface QualityScorerOptions {
22
- weights?: Record<string, number>;
23
- }
24
43
  export declare class QualityScorer {
25
44
  #private;
26
- constructor(options?: QualityScorerOptions);
45
+ constructor(options?: {
46
+ weights?: Record<string, number>;
47
+ });
27
48
  /**
28
49
  * 计算综合质量分
29
- * @param recipe Recipe 对象 (title, trigger, code, language, category, summary, usageGuide, headers, tags, views, clicks, rating)
30
- * @returns }
50
+ * @returns { score: 0-1, dimensions: Record<string,number>, grade: A-F }
31
51
  */
32
52
  score(recipe: RecipeInput): {
33
53
  score: number;
34
54
  dimensions: {
35
55
  completeness: number;
36
- format: number;
37
- codeQuality: number;
38
- metadata: number;
39
- engagement: number;
56
+ contentDepth: number;
57
+ deliveryReady: number;
58
+ actionability: number;
59
+ provenance: number;
40
60
  };
41
61
  grade: string;
42
62
  };
@@ -45,21 +65,20 @@ export declare class QualityScorer {
45
65
  score: number;
46
66
  dimensions: {
47
67
  completeness: number;
48
- format: number;
49
- codeQuality: number;
50
- metadata: number;
51
- engagement: number;
68
+ contentDepth: number;
69
+ deliveryReady: number;
70
+ actionability: number;
71
+ provenance: number;
52
72
  };
53
73
  grade: string;
54
74
  recipe: RecipeInput;
55
75
  }[];
56
76
  /** 获取维度权重 */
57
77
  getWeights(): {
58
- completeness: 0.3;
59
- format: 0.25;
60
- codeQuality: 0.25;
61
- metadata: 0.1;
62
- engagement: 0.1;
78
+ completeness: 0.25;
79
+ contentDepth: 0.3;
80
+ deliveryReady: 0.2;
81
+ actionability: 0.15;
82
+ provenance: 0.1;
63
83
  };
64
84
  }
65
- export {};
@@ -1,10 +1,43 @@
1
1
  /**
2
- * QualityScorer — Recipe 质量评分器
3
- * 5 个维度: completeness(0.35) + format(0.25) + codeQuality(0.25) + metadata(0.15) + engagement(0)
4
- * 每个维度评分 0-1,加权求和
2
+ * QualityScorer v2 — Recipe 质量评分器
3
+ *
4
+ * 面向知识管理场景重新设计,采用渐进式评分(非二元判断),
5
+ * 充分利用 KnowledgeEntry 所有可用字段。
6
+ *
7
+ * 5 维度加权:
8
+ * - completeness (0.25): 结构完整性 — 核心字段齐全度
9
+ * - contentDepth (0.30): 内容深度 — markdown 丰富度、推理、溯源
10
+ * - deliveryReady (0.20): 交付就绪 — trigger/language/tags/category
11
+ * - actionability (0.15): 可操作性 — coreCode、do/dont/when 质量
12
+ * - provenance (0.10): 溯源可信 — confidence、sources、authority
13
+ *
14
+ * 设计参考:
15
+ * - RAG Triad (TruLens): Relevance + Groundedness + Answer Relevance
16
+ * - RAGAS: Context Precision + Faithfulness + Factual Correctness
17
+ * - SonarQube: 多维度渐进评级,非二元判断
5
18
  */
6
- import { CODE_LENGTH, QUALITY_GRADES, QUALITY_WEIGHTS } from '../../shared/constants.js';
19
+ import { QUALITY_GRADES, QUALITY_WEIGHTS } from '../../shared/constants.js';
20
+ import { LanguageProfiles } from '../../shared/LanguageProfiles.js';
7
21
  const DEFAULT_WEIGHTS = QUALITY_WEIGHTS;
22
+ // ─── 渐进式评分辅助函数 ─────────────────────────────────
23
+ /** 文本长度渐进评分: 低于 minLen 给 20% 基础分,minLen→optimalLen 线性增长到满分 */
24
+ function textScore(text, minLen, optimalLen, weight) {
25
+ if (!text?.trim()) {
26
+ return 0;
27
+ }
28
+ const len = text.trim().length;
29
+ if (len < minLen) {
30
+ return weight * 0.2;
31
+ }
32
+ if (len <= optimalLen) {
33
+ return weight * (0.5 + 0.5 * (len / optimalLen));
34
+ }
35
+ return weight;
36
+ }
37
+ /** 存在性检查: 有值给满分 */
38
+ function presenceScore(value, weight) {
39
+ return value?.trim() ? weight : 0;
40
+ }
8
41
  export class QualityScorer {
9
42
  #weights;
10
43
  constructor(options = {}) {
@@ -12,16 +45,15 @@ export class QualityScorer {
12
45
  }
13
46
  /**
14
47
  * 计算综合质量分
15
- * @param recipe Recipe 对象 (title, trigger, code, language, category, summary, usageGuide, headers, tags, views, clicks, rating)
16
- * @returns }
48
+ * @returns { score: 0-1, dimensions: Record<string,number>, grade: A-F }
17
49
  */
18
50
  score(recipe) {
19
51
  const dimensions = {
20
52
  completeness: this.#scoreCompleteness(recipe),
21
- format: this.#scoreFormat(recipe),
22
- codeQuality: this.#scoreCodeQuality(recipe),
23
- metadata: this.#scoreMetadata(recipe),
24
- engagement: this.#scoreEngagement(recipe),
53
+ contentDepth: this.#scoreContentDepth(recipe),
54
+ deliveryReady: this.#scoreDeliveryReady(recipe),
55
+ actionability: this.#scoreActionability(recipe),
56
+ provenance: this.#scoreProvenance(recipe),
25
57
  };
26
58
  let totalScore = 0;
27
59
  for (const [dim, weight] of Object.entries(this.#weights)) {
@@ -44,108 +76,150 @@ export class QualityScorer {
44
76
  return { ...this.#weights };
45
77
  }
46
78
  // ─── 维度评分 ─────────────────────────────────────────
47
- /** 完整性: title(0.25) + trigger(0.25) + code(0.3) + usageGuide(0.2) */
79
+ /**
80
+ * 结构完整性 (0-1)
81
+ * 渐进式检查核心字段齐全度
82
+ */
48
83
  #scoreCompleteness(r) {
49
84
  let s = 0;
50
- if (r.title?.trim()) {
51
- s += 0.25;
52
- }
53
- if (r.trigger?.trim()) {
54
- s += 0.25;
85
+ s += textScore(r.title, 3, 40, 0.15);
86
+ s += presenceScore(r.trigger, 0.15);
87
+ s += textScore(r.description, 10, 60, 0.15);
88
+ s += textScore(r.doClause, 10, 50, 0.15);
89
+ s += textScore(r.whenClause, 10, 50, 0.15);
90
+ s += textScore(r.coreCode, 10, 200, 0.15);
91
+ s += presenceScore(r.dontClause, 0.1);
92
+ return Math.min(1, s);
93
+ }
94
+ /**
95
+ * 内容深度 (0-1)
96
+ * markdown 丰富度 + 结构化标记 + 设计原理 + 来源引用
97
+ */
98
+ #scoreContentDepth(r) {
99
+ let s = 0;
100
+ const md = r.contentMarkdown || r.usageGuide || '';
101
+ // markdown 内容长度 (最优 200-800 字符)
102
+ s += textScore(md || undefined, 50, 800, 0.3);
103
+ // 结构化标记: 标题 / 代码块 / 列表
104
+ if (md) {
105
+ if (/^#{1,4}\s/m.test(md)) {
106
+ s += 0.08;
107
+ }
108
+ if (/```[\s\S]*?```|`[^`]+`/.test(md)) {
109
+ s += 0.08;
110
+ }
111
+ if (/^[\s]*[-*+]\s/m.test(md)) {
112
+ s += 0.04;
113
+ }
55
114
  }
56
- if (r.code && r.code.trim().length > 5) {
57
- s += 0.3;
115
+ // rationale: 设计原理
116
+ s += textScore(r.contentRationale, 10, 100, 0.15);
117
+ // reasoning.whyStandard
118
+ s += textScore(r.reasoningWhyStandard, 10, 100, 0.15);
119
+ // reasoning.sources 来源文件
120
+ if (r.reasoningSources && r.reasoningSources.length > 0) {
121
+ s += Math.min(0.1, r.reasoningSources.length * 0.03);
58
122
  }
59
- if (r.usageGuide?.trim()) {
60
- s += 0.2;
123
+ // usageGuide(如果与 markdown 不同则额外加分)
124
+ if (r.usageGuide && r.usageGuide !== md) {
125
+ s += textScore(r.usageGuide, 20, 200, 0.1);
61
126
  }
62
- return s;
127
+ return Math.min(1, s);
63
128
  }
64
- /** 格式: trigger 格式(0.5) + language 合法性(0.5) */
65
- #scoreFormat(r) {
129
+ /**
130
+ * 交付就绪度 (0-1)
131
+ * trigger 格式 + language 合法性 + 分类 + 标签
132
+ */
133
+ #scoreDeliveryReady(r) {
66
134
  let s = 0;
135
+ // trigger 格式
67
136
  if (r.trigger) {
68
- if (/^[a-zA-Z0-9_\-:.]+$/.test(r.trigger) &&
69
- r.trigger.length >= 2 &&
70
- r.trigger.length <= 64) {
71
- s += 0.5;
72
- }
73
- else if (r.trigger.length >= 2) {
74
- s += 0.25;
75
- }
137
+ const valid = /^[a-zA-Z0-9_\-:.@]+$/.test(r.trigger) && r.trigger.length >= 2 && r.trigger.length <= 80;
138
+ s += valid ? 0.25 : r.trigger.length >= 2 ? 0.15 : 0;
76
139
  }
140
+ // language 合法性
77
141
  if (r.language) {
78
- const valid = new Set([
79
- 'swift',
80
- 'objective-c',
81
- 'objc',
82
- 'javascript',
83
- 'typescript',
84
- 'python',
85
- 'c',
86
- 'cpp',
87
- 'shell',
88
- 'markdown',
89
- ]);
90
- s += valid.has(r.language.toLowerCase()) ? 0.5 : 0.25;
91
- }
92
- return s;
93
- }
94
- /** 代码质量: 长度适中(0.3) + 无 TODO(0.2) + 有注释(0.3) + 有错误处理(0.2) */
95
- #scoreCodeQuality(r) {
96
- if (!r.code) {
97
- return 0;
142
+ s += LanguageProfiles.validCodeLanguages.has(r.language.toLowerCase()) ? 0.25 : 0.1;
143
+ }
144
+ // category
145
+ s += presenceScore(r.category, 0.2);
146
+ // tags 丰富度
147
+ if (r.tags && r.tags.length > 0) {
148
+ s += Math.min(0.15, r.tags.length * 0.04);
98
149
  }
150
+ // headers (语言相关导入声明)
151
+ if (r.headers && r.headers.length > 0) {
152
+ s += Math.min(0.15, r.headers.length * 0.05);
153
+ }
154
+ return Math.min(1, s);
155
+ }
156
+ /**
157
+ * 可操作性 (0-1)
158
+ * AI agent 能否基于此知识有效行动
159
+ */
160
+ #scoreActionability(r) {
99
161
  let s = 0;
100
- const code = r.code;
101
- // 长度适中
102
- if (code.length >= CODE_LENGTH.MIN && code.length <= CODE_LENGTH.MAX) {
162
+ const code = r.coreCode || '';
163
+ const md = r.contentMarkdown || r.usageGuide || '';
164
+ // 具体代码示例
165
+ const codeLen = code.trim().length;
166
+ if (codeLen >= 30 && codeLen <= 500) {
103
167
  s += 0.3;
104
168
  }
105
- else if (code.length > CODE_LENGTH.MAX) {
106
- s += 0.15;
169
+ else if (codeLen >= 10) {
170
+ s += 0.2;
107
171
  }
108
- // TODO/FIXME/HACK
109
- if (!/\b(TODO|FIXME|HACK|XXX)\b/.test(code)) {
172
+ else if (/```[\s\S]{10,}?```/.test(md)) {
110
173
  s += 0.2;
111
174
  }
112
- // 有注释
113
- if (/\/\/|\/\*|#\s/.test(code)) {
114
- s += 0.3;
175
+ // doClause 具体度
176
+ if (r.doClause) {
177
+ const len = r.doClause.trim().length;
178
+ s += len >= 15 && len <= 200 ? 0.25 : len >= 5 ? 0.1 : 0;
115
179
  }
116
- // 有错误处理
117
- if (/try|catch|throw|guard|if\s+let|do\s*\{|\.catch/.test(code)) {
180
+ // 正反约束(do + don't → 引导更精确)
181
+ if (r.doClause?.trim() && r.dontClause?.trim()) {
118
182
  s += 0.2;
119
183
  }
120
- return s;
184
+ else if (r.doClause?.trim()) {
185
+ s += 0.1;
186
+ }
187
+ // whenClause 具体度
188
+ if (r.whenClause) {
189
+ const len = r.whenClause.trim().length;
190
+ s += len >= 15 ? 0.25 : len >= 5 ? 0.1 : 0;
191
+ }
192
+ return Math.min(1, s);
121
193
  }
122
- /** 元数据: category(0.35) + tags/headers(0.35) + summary(0.3) */
123
- #scoreMetadata(r) {
194
+ /**
195
+ * 溯源可信度 (0-1)
196
+ * 知识的可追溯性和可信度
197
+ */
198
+ #scoreProvenance(r) {
124
199
  let s = 0;
125
- if (r.category?.trim()) {
126
- s += 0.35;
200
+ // AI confidence (0-1 → 0-0.30)
201
+ if (r.reasoningConfidence != null && r.reasoningConfidence > 0) {
202
+ s += r.reasoningConfidence * 0.3;
127
203
  }
128
- if ((r.tags && r.tags.length > 0) || (r.headers && r.headers.length > 0)) {
129
- s += 0.35;
204
+ // 来源文件引用
205
+ if (r.reasoningSources && r.reasoningSources.length > 0) {
206
+ s += Math.min(0.3, r.reasoningSources.length * 0.1);
130
207
  }
131
- if (r.summary?.trim()) {
132
- s += 0.3;
208
+ // 来源类型 (manual > mcp > bootstrap)
209
+ if (r.source === 'manual') {
210
+ s += 0.2;
133
211
  }
134
- return s;
135
- }
136
- /** 互动: views(0.3) + clicks(0.3) + rating(0.4) */
137
- #scoreEngagement(r) {
138
- let s = 0;
139
- if (r.views && r.views > 0) {
140
- s += Math.min(0.3, (r.views / 100) * 0.3);
212
+ else if (r.source === 'mcp') {
213
+ s += 0.15;
141
214
  }
142
- if (r.clicks && r.clicks > 0) {
143
- s += Math.min(0.3, (r.clicks / 50) * 0.3);
215
+ else if (r.source === 'bootstrap' || r.source === 'cursor-scan') {
216
+ s += 0.1;
144
217
  }
218
+ // usage authority (0-5 → 0-0.20)
145
219
  if (r.rating && r.rating > 0) {
146
- s += (r.rating / 5) * 0.4;
220
+ s += (r.rating / 5) * 0.2;
147
221
  }
148
- return s;
222
+ return Math.min(1, s);
149
223
  }
150
224
  /** 分数转等级 */
151
225
  #toGrade(score) {
@@ -18,6 +18,7 @@ export { tokenize } from './tokenizer.js';
18
18
  * 整合召回评分 + 关键词 + 可选 AI 增强
19
19
  */
20
20
  export declare class SearchEngine {
21
+ #private;
21
22
  _cache: Map<string, {
22
23
  data: SearchResponse;
23
24
  time: number;
@@ -5,6 +5,7 @@
5
5
  * 从 V1 SearchServiceV2 迁移,适配 V2 架构
6
6
  */
7
7
  import Logger from '../../infrastructure/logging/Logger.js';
8
+ import { RawDbKnowledgeAdapter, RawDbSourceRefAdapter, unwrapSearchDb, } from '../../repository/search/SearchRepoAdapter.js';
8
9
  import { CoarseRanker } from './CoarseRanker.js';
9
10
  import { contextBoost } from './contextBoost.js';
10
11
  import { FieldWeightedScorer } from './FieldWeightedScorer.js';
@@ -32,12 +33,19 @@ export class SearchEngine {
32
33
  aiProvider;
33
34
  db;
34
35
  hybridRetriever;
36
+ #knowledgeRepo;
37
+ #sourceRefRepo;
35
38
  logger;
36
39
  scorer;
37
40
  vectorService;
38
41
  vectorStore;
39
42
  constructor(db, options = {}) {
40
- this.db = (typeof db?.getDb === 'function' ? db.getDb() : db);
43
+ this.db = unwrapSearchDb(db);
44
+ const opts = options;
45
+ this.#knowledgeRepo =
46
+ opts.knowledgeRepo ?? new RawDbKnowledgeAdapter(this.db);
47
+ this.#sourceRefRepo =
48
+ opts.sourceRefRepo ?? new RawDbSourceRefAdapter(this.db);
41
49
  this.logger = Logger.getInstance();
42
50
  this.aiProvider = options.aiProvider || null;
43
51
  this.vectorStore = options.vectorStore || null;
@@ -62,13 +70,8 @@ export class SearchEngine {
62
70
  try {
63
71
  let entries = [];
64
72
  try {
65
- entries = this.db
66
- .prepare(`SELECT id, title, description, language, category, knowledgeType, kind,
67
- content, lifecycle, tags, trigger, difficulty, quality, stats,
68
- updatedAt, createdAt
69
- FROM knowledge_entries WHERE lifecycle != 'deprecated'`)
70
- .all();
71
- entries = entries.map((e) => ({
73
+ const rawEntries = this.#knowledgeRepo.findNonDeprecatedSync();
74
+ entries = rawEntries.map((e) => ({
72
75
  ...e,
73
76
  status: e.lifecycle,
74
77
  }));
@@ -316,12 +319,12 @@ export class SearchEngine {
316
319
  try {
317
320
  let rows = [];
318
321
  try {
319
- rows = this.db
320
- .prepare(`SELECT id, title, description, language, category, knowledgeType, kind, lifecycle as status, content, trigger, headers, moduleName, 'knowledge' as type
321
- FROM knowledge_entries
322
- WHERE lifecycle != 'deprecated' AND (title LIKE ? ESCAPE '\\' OR description LIKE ? ESCAPE '\\' OR trigger LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\')
323
- LIMIT ?`)
324
- .all(pattern, pattern, pattern, pattern, limit);
322
+ const rawRows = this.#knowledgeRepo.keywordSearchSync(pattern, limit);
323
+ rows = rawRows.map((r) => ({
324
+ ...r,
325
+ status: r.lifecycle ?? r.status,
326
+ type: 'knowledge',
327
+ }));
325
328
  }
326
329
  catch {
327
330
  /* table may not exist */
@@ -549,15 +552,9 @@ export class SearchEngine {
549
552
  }
550
553
  try {
551
554
  const ids = items.map((it) => it.id);
552
- const placeholders = ids.map(() => '?').join(',');
553
555
  let rows = [];
554
556
  try {
555
- rows = this.db
556
- .prepare(`SELECT id, content, description, trigger, headers, moduleName,
557
- tags, language, category, updatedAt, createdAt, quality, stats, difficulty,
558
- whenClause, doClause
559
- FROM knowledge_entries WHERE id IN (${placeholders})`)
560
- .all(...ids);
557
+ rows = this.#knowledgeRepo.findByIdsDetailSync(ids);
561
558
  }
562
559
  catch {
563
560
  /* table may not exist */
@@ -642,23 +639,26 @@ export class SearchEngine {
642
639
  if (ids.length === 0) {
643
640
  return;
644
641
  }
645
- const placeholders = ids.map(() => '?').join(',');
646
- const refsRows = this.db
647
- .prepare(`SELECT recipe_id, source_path, status, new_path
648
- FROM recipe_source_refs
649
- WHERE recipe_id IN (${placeholders}) AND status != 'stale'`)
650
- .all(...ids);
642
+ let refsRows;
643
+ refsRows = this.#sourceRefRepo.findActiveByRecipeIds(ids);
651
644
  this.logger.debug('recipe_source_refs query', {
652
645
  idCount: ids.length,
653
646
  rowCount: refsRows.length,
654
647
  });
655
648
  const refsMap = new Map();
656
649
  for (const row of refsRows) {
657
- const refPath = row.status === 'renamed' && row.new_path ? row.new_path : row.source_path;
658
- if (!refsMap.has(row.recipe_id)) {
659
- refsMap.set(row.recipe_id, []);
650
+ const recipeId = row.recipeId ??
651
+ row.recipe_id;
652
+ const sourcePath = row.sourcePath ??
653
+ row.source_path;
654
+ const status = row.status;
655
+ const newPath = row.newPath ??
656
+ row.new_path;
657
+ const refPath = status === 'renamed' && newPath ? newPath : sourcePath;
658
+ if (!refsMap.has(recipeId)) {
659
+ refsMap.set(recipeId, []);
660
660
  }
661
- refsMap.get(row.recipe_id)?.push(refPath);
661
+ refsMap.get(recipeId)?.push(refPath);
662
662
  }
663
663
  for (const item of items) {
664
664
  const refs = refsMap.get(item.id);
@@ -692,12 +692,7 @@ export class SearchEngine {
692
692
  this._cache.clear();
693
693
  try {
694
694
  // 查找自上次索引后更新的条目
695
- const changed = this.db
696
- .prepare(`SELECT id, title, description, language, category, knowledgeType, kind,
697
- content, lifecycle, tags, trigger, difficulty, quality, stats,
698
- updatedAt, createdAt
699
- FROM knowledge_entries WHERE updatedAt > ?`)
700
- .all(this._lastIndexTime);
695
+ const changed = this.#knowledgeRepo.findUpdatedSinceSync(this._lastIndexTime);
701
696
  let added = 0;
702
697
  let removed = 0;
703
698
  for (const r of changed) {
@@ -11,6 +11,7 @@
11
11
  *
12
12
  * @module service/signal/HitRecorder
13
13
  */
14
+ import { unwrapRawDb } from '../../repository/search/SearchRepoAdapter.js';
14
15
  /** 事件类型 → Stats JSON 字段 映射 */
15
16
  const EVENT_TO_STATS_FIELD = {
16
17
  guardHit: 'guardHits',
@@ -39,10 +40,7 @@ export class HitRecorder {
39
40
  #totalFlushed = 0;
40
41
  constructor(bus, db, config = {}) {
41
42
  this.#bus = bus;
42
- this.#db =
43
- 'getDb' in db && typeof db.getDb === 'function'
44
- ? db.getDb()
45
- : db;
43
+ this.#db = unwrapRawDb(db);
46
44
  this.#flushIntervalMs = config.flushIntervalMs ?? 30_000;
47
45
  this.#maxBufferSize = config.maxBufferSize ?? 100;
48
46
  }
@@ -123,7 +121,9 @@ export class HitRecorder {
123
121
  let flushed = 0;
124
122
  const now = Math.floor(Date.now() / 1000);
125
123
  try {
126
- const stmt = this.#db.prepare(`UPDATE knowledge_entries
124
+ const stmt = this.#db.prepare(
125
+ // @escape-hatch(permanent) — json_set() not expressible in Drizzle
126
+ `UPDATE knowledge_entries
127
127
  SET stats = json_set(
128
128
  COALESCE(stats, '{}'),
129
129
  '$.' || ?,
@@ -10,11 +10,15 @@ export class RuleRecallStrategy {
10
10
  name = 'rule';
11
11
  type = 'rule';
12
12
  async recall(context) {
13
- const db = context.database;
13
+ const ct = context.container;
14
+ const knowledgeRepo = (ct?.get?.('knowledgeRepository') ||
15
+ null);
16
+ const auditRepo = (ct?.get?.('auditRepository') || null);
14
17
  const advisor = new SkillAdvisor(context.projectRoot, {
15
- database: db,
18
+ knowledgeRepo,
19
+ auditRepo,
16
20
  });
17
- const result = advisor.suggest();
21
+ const result = await advisor.suggest();
18
22
  // 过滤已有 Skill
19
23
  const existingSet = context.existingSkills ?? new Set();
20
24
  return result.suggestions
@@ -36,9 +36,12 @@
36
36
  * 生命周期:
37
37
  * new SignalCollector(opts) → instance.start() → ... → instance.stop()
38
38
  */
39
+ import type { AuditRepositoryImpl } from '../../repository/audit/AuditRepository.js';
40
+ import type { KnowledgeRepositoryImpl } from '../../repository/knowledge/KnowledgeRepository.impl.js';
39
41
  interface SignalCollectorOpts {
40
42
  projectRoot: string;
41
- database?: DatabaseLike | null;
43
+ knowledgeRepo?: KnowledgeRepositoryImpl | null;
44
+ auditRepo?: AuditRepositoryImpl | null;
42
45
  agentFactory?: AgentFactoryLike | null;
43
46
  container?: ContainerLike | null;
44
47
  signalBus?: import('../../infrastructure/signal/SignalBus.js').SignalBus | null;
@@ -46,12 +49,6 @@ interface SignalCollectorOpts {
46
49
  intervalMs?: number;
47
50
  onSuggestions?: ((suggestions: Record<string, unknown>[]) => void) | null;
48
51
  }
49
- interface DatabaseLike {
50
- prepare(sql: string): {
51
- all(...args: unknown[]): Record<string, unknown>[];
52
- get(...args: unknown[]): Record<string, unknown> | undefined;
53
- };
54
- }
55
52
  interface AgentResult {
56
53
  reply?: string;
57
54
  text?: string;
@@ -87,7 +84,7 @@ export declare class SignalCollector {
87
84
  * @param [opts.intervalMs] 初始收集间隔(毫秒),后续由 AI 动态调整
88
85
  * @param [opts.onSuggestions] 新建议回调 (suggestions[]) => void
89
86
  */
90
- constructor({ projectRoot, database, agentFactory, container, signalBus, mode, intervalMs, onSuggestions, }: SignalCollectorOpts);
87
+ constructor({ projectRoot, knowledgeRepo, auditRepo, agentFactory, container, signalBus, mode, intervalMs, onSuggestions, }: SignalCollectorOpts);
91
88
  start(): void;
92
89
  stop(): void;
93
90
  /**