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,253 @@
1
+ /**
2
+ * ContradictionDetector — Recipe 级矛盾检测
3
+ *
4
+ * 从 MemoryConsolidator 提升:Memory 层只做 session 内去重,
5
+ * Recipe 层做跨 lifecycle 的持久化矛盾检测。
6
+ *
7
+ * 检测维度:
8
+ * 1. 否定模式检测(中/英双语 negation patterns)
9
+ * 2. 主题词重叠 ≥ 30% Jaccard
10
+ * 3. doClause vs dontClause 交叉引用
11
+ * 4. guard regex 互斥检测
12
+ *
13
+ * 结果:硬矛盾 (confidence ≥ 0.8) / 软矛盾 (0.4-0.8)
14
+ */
15
+ var _a;
16
+ import Logger from '../../infrastructure/logging/Logger.js';
17
+ /* ────────────────────── Constants ────────────────────── */
18
+ const NEGATION_PATTERNS_ZH = /不(再)?使用|禁止|废弃|移除|取消|停止|不要|不采用|弃用|淘汰/;
19
+ const NEGATION_PATTERNS_EN = /\b(don'?t|do\s+not|never|no\s+longer|removed?|deprecated?|stop|avoid|disable|abandon|drop)\b/i;
20
+ const MIN_TOPIC_OVERLAP_WORDS = 2;
21
+ const MIN_TOPIC_OVERLAP_RATIO = 0.3;
22
+ const STOP_WORDS = new Set([
23
+ '我们',
24
+ '使用',
25
+ '项目',
26
+ '需要',
27
+ '可以',
28
+ '应该',
29
+ '建议',
30
+ '目前',
31
+ '已经',
32
+ '这个',
33
+ '那个',
34
+ '一个',
35
+ '进行',
36
+ '通过',
37
+ '对于',
38
+ 'the',
39
+ 'is',
40
+ 'are',
41
+ 'was',
42
+ 'were',
43
+ 'be',
44
+ 'been',
45
+ 'have',
46
+ 'has',
47
+ 'had',
48
+ 'do',
49
+ 'does',
50
+ 'did',
51
+ 'will',
52
+ 'would',
53
+ 'could',
54
+ 'should',
55
+ 'may',
56
+ 'might',
57
+ 'can',
58
+ 'this',
59
+ 'that',
60
+ 'these',
61
+ 'those',
62
+ 'for',
63
+ 'and',
64
+ 'but',
65
+ 'with',
66
+ 'not',
67
+ 'from',
68
+ 'use',
69
+ 'all',
70
+ 'any',
71
+ ]);
72
+ /* ────────────────────── Class ────────────────────── */
73
+ export class ContradictionDetector {
74
+ #db;
75
+ #signalBus;
76
+ #logger = Logger.getInstance();
77
+ constructor(db, options = {}) {
78
+ this.#db = db;
79
+ this.#signalBus = options.signalBus ?? null;
80
+ }
81
+ /**
82
+ * 检测所有 active/staging/evolving Recipe 之间的矛盾
83
+ */
84
+ detectAll() {
85
+ const recipes = this.#loadRecipes();
86
+ const results = [];
87
+ for (let i = 0; i < recipes.length; i++) {
88
+ for (let j = i + 1; j < recipes.length; j++) {
89
+ const result = this.detectPair(recipes[i], recipes[j]);
90
+ if (result) {
91
+ results.push(result);
92
+ }
93
+ }
94
+ }
95
+ // 发射矛盾信号
96
+ if (this.#signalBus && results.length > 0) {
97
+ for (const r of results) {
98
+ this.#signalBus.send('lifecycle', 'ContradictionDetector', r.confidence, {
99
+ target: r.recipeA,
100
+ metadata: {
101
+ contradictsWith: r.recipeB,
102
+ type: r.type,
103
+ evidence: r.evidence,
104
+ },
105
+ });
106
+ }
107
+ }
108
+ this.#logger.debug(`ContradictionDetector: found ${results.length} contradictions`);
109
+ return results;
110
+ }
111
+ /**
112
+ * 检测两条 Recipe 是否矛盾
113
+ */
114
+ detectPair(a, b) {
115
+ const evidence = [];
116
+ let score = 0;
117
+ // 维度 1: 否定模式 + 主题重叠
118
+ const textA = [a.title, a.description, a.doClause, a.dontClause, a.content_markdown]
119
+ .filter(Boolean)
120
+ .join(' ');
121
+ const textB = [b.title, b.description, b.doClause, b.dontClause, b.content_markdown]
122
+ .filter(Boolean)
123
+ .join(' ');
124
+ if (this.#hasNegationConflict(textA, textB)) {
125
+ evidence.push('negation_pattern_conflict');
126
+ score += 0.4;
127
+ }
128
+ // 维度 2: doClause vs dontClause 交叉引用
129
+ if (a.doClause && b.dontClause && this.#hasTopicOverlap(a.doClause, b.dontClause)) {
130
+ evidence.push('doClause_vs_dontClause_cross');
131
+ score += 0.3;
132
+ }
133
+ if (b.doClause && a.dontClause && this.#hasTopicOverlap(b.doClause, a.dontClause)) {
134
+ evidence.push('dontClause_vs_doClause_cross');
135
+ score += 0.3;
136
+ }
137
+ // 维度 3: guard regex 互斥检测
138
+ if (a.guardPattern && b.guardPattern) {
139
+ if (this.#areRegexMutuallyExclusive(a.guardPattern, b.guardPattern)) {
140
+ evidence.push('guard_regex_mutual_exclusive');
141
+ score += 0.2;
142
+ }
143
+ }
144
+ if (evidence.length === 0) {
145
+ return null;
146
+ }
147
+ const confidence = Math.min(1, score);
148
+ const type = confidence >= 0.8 ? 'hard' : 'soft';
149
+ return {
150
+ recipeA: a.id,
151
+ recipeB: b.id,
152
+ confidence,
153
+ type,
154
+ evidence,
155
+ };
156
+ }
157
+ /* ── Internal ── */
158
+ #loadRecipes() {
159
+ try {
160
+ const rows = this.#db
161
+ .prepare(`SELECT id, title, lifecycle, description,
162
+ json_extract(content, '$.markdown') AS content_markdown,
163
+ doClause,
164
+ dontClause,
165
+ json_extract(content, '$.pattern') AS guardPattern
166
+ FROM knowledge_entries
167
+ WHERE lifecycle IN ('active', 'staging', 'evolving')`)
168
+ .all();
169
+ return rows.map((r) => ({
170
+ id: r.id,
171
+ title: r.title,
172
+ lifecycle: r.lifecycle,
173
+ doClause: r.doClause ?? null,
174
+ dontClause: r.dontClause ?? null,
175
+ guardPattern: r.guardPattern ?? null,
176
+ description: r.description ?? null,
177
+ content_markdown: r.content_markdown ?? null,
178
+ }));
179
+ }
180
+ catch {
181
+ return [];
182
+ }
183
+ }
184
+ #hasNegationConflict(textA, textB) {
185
+ if (!textA || !textB) {
186
+ return false;
187
+ }
188
+ const aNeg = NEGATION_PATTERNS_ZH.test(textA) || NEGATION_PATTERNS_EN.test(textA);
189
+ const bNeg = NEGATION_PATTERNS_ZH.test(textB) || NEGATION_PATTERNS_EN.test(textB);
190
+ // 同极性不算矛盾
191
+ if (aNeg === bNeg) {
192
+ return false;
193
+ }
194
+ return this.#hasTopicOverlap(textA, textB);
195
+ }
196
+ #hasTopicOverlap(textA, textB) {
197
+ const wordsA = _a.extractTopicWords(textA);
198
+ const wordsB = _a.extractTopicWords(textB);
199
+ let overlap = 0;
200
+ for (const w of wordsA) {
201
+ if (wordsB.has(w)) {
202
+ overlap++;
203
+ }
204
+ }
205
+ const minSize = Math.min(wordsA.size, wordsB.size);
206
+ if (minSize === 0) {
207
+ return false;
208
+ }
209
+ return overlap >= MIN_TOPIC_OVERLAP_WORDS || overlap / minSize >= MIN_TOPIC_OVERLAP_RATIO;
210
+ }
211
+ #areRegexMutuallyExclusive(patternA, patternB) {
212
+ // 简单启发式:如果两个 pattern 的核心词完全相同但一个含否定前缀
213
+ // 例如 "use.*SnapKit" vs "(?!.*SnapKit)" 或 "avoid.*SnapKit"
214
+ try {
215
+ const coreA = patternA
216
+ .replace(/[\\^$.*+?()[\]{}|]/g, ' ')
217
+ .trim()
218
+ .toLowerCase();
219
+ const coreB = patternB
220
+ .replace(/[\\^$.*+?()[\]{}|]/g, ' ')
221
+ .trim()
222
+ .toLowerCase();
223
+ const wordsA = new Set(coreA.split(/\s+/).filter((w) => w.length >= 3));
224
+ const wordsB = new Set(coreB.split(/\s+/).filter((w) => w.length >= 3));
225
+ let overlap = 0;
226
+ for (const w of wordsA) {
227
+ if (wordsB.has(w)) {
228
+ overlap++;
229
+ }
230
+ }
231
+ // 高重叠 + 一个含否定前瞻
232
+ if (overlap >= 2 && (patternA.includes('(?!') || patternB.includes('(?!'))) {
233
+ return true;
234
+ }
235
+ }
236
+ catch {
237
+ // regex parsing error
238
+ }
239
+ return false;
240
+ }
241
+ /** 提取主题词(公开为静态方法,供 RedundancyAnalyzer 复用) */
242
+ static extractTopicWords(text) {
243
+ if (!text) {
244
+ return new Set();
245
+ }
246
+ const tokens = text
247
+ .toLowerCase()
248
+ .split(/[\s,;:!?。,;:!?\-_/\\|()[\]{}'"<>·、]+/)
249
+ .filter((t) => t.length >= 2);
250
+ return new Set(tokens.filter((t) => !STOP_WORDS.has(t)));
251
+ }
252
+ }
253
+ _a = ContradictionDetector;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * DecayDetector — 知识衰退检测 + 评分
3
+ *
4
+ * 5 种衰退检测策略(任一满足即触发 decaying 转换):
5
+ * 1. daysSinceLastHit > 90 — 90 天无使用
6
+ * 2. ruleFalsePositiveRate > 0.4 && triggers > 10 — 规则已不准
7
+ * 3. ReverseGuard: coreCode 引用的 API 符号已删除
8
+ * 4. 同域新 Recipe 发布且 deprecated_by 关系指向它
9
+ * 5. ContradictionDetector: 与更新的 Recipe 硬矛盾
10
+ *
11
+ * 衰退评分 (decayScore 0-100):
12
+ * freshness(0.3) + usage(0.3) + quality(0.2) + authority(0.2)
13
+ *
14
+ * 80-100: 健康 → 不转换
15
+ * 60-79: 关注 → Dashboard 警告
16
+ * 40-59: 衰退 → active → decaying
17
+ * 20-39: 严重 → Grace Period 缩短到 15d
18
+ * 0-19: 死亡 → 跳过确认直接 deprecated
19
+ */
20
+ import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
21
+ interface DatabaseLike {
22
+ prepare(sql: string): {
23
+ all(...params: unknown[]): Record<string, unknown>[];
24
+ get(...params: unknown[]): Record<string, unknown> | undefined;
25
+ };
26
+ }
27
+ export interface DecaySignal {
28
+ recipeId: string;
29
+ strategy: DecayStrategy;
30
+ detail: string;
31
+ }
32
+ export type DecayStrategy = 'no_recent_usage' | 'high_false_positive' | 'symbol_drift' | 'superseded' | 'contradiction';
33
+ export interface DecayScoreResult {
34
+ recipeId: string;
35
+ title: string;
36
+ decayScore: number;
37
+ level: 'healthy' | 'watch' | 'decaying' | 'severe' | 'dead';
38
+ signals: DecaySignal[];
39
+ dimensions: {
40
+ freshness: number;
41
+ usage: number;
42
+ quality: number;
43
+ authority: number;
44
+ };
45
+ /** 建议的 Grace Period (ms)。severe=15d,dead=0 */
46
+ suggestedGracePeriod: number;
47
+ }
48
+ interface RecipeForDecay {
49
+ id: string;
50
+ title: string;
51
+ lifecycle: string;
52
+ stats: string | null;
53
+ quality_grade: string | null;
54
+ quality_score: number | null;
55
+ created_at: string | null;
56
+ }
57
+ export declare class DecayDetector {
58
+ #private;
59
+ constructor(db: DatabaseLike, options?: {
60
+ signalBus?: SignalBus;
61
+ });
62
+ /**
63
+ * 扫描所有 active 条目的衰退状态
64
+ */
65
+ scanAll(): DecayScoreResult[];
66
+ /**
67
+ * 评估单条 Recipe 的衰退状态
68
+ */
69
+ evaluate(recipe: RecipeForDecay): DecayScoreResult;
70
+ }
71
+ export {};
@@ -0,0 +1,244 @@
1
+ /**
2
+ * DecayDetector — 知识衰退检测 + 评分
3
+ *
4
+ * 5 种衰退检测策略(任一满足即触发 decaying 转换):
5
+ * 1. daysSinceLastHit > 90 — 90 天无使用
6
+ * 2. ruleFalsePositiveRate > 0.4 && triggers > 10 — 规则已不准
7
+ * 3. ReverseGuard: coreCode 引用的 API 符号已删除
8
+ * 4. 同域新 Recipe 发布且 deprecated_by 关系指向它
9
+ * 5. ContradictionDetector: 与更新的 Recipe 硬矛盾
10
+ *
11
+ * 衰退评分 (decayScore 0-100):
12
+ * freshness(0.3) + usage(0.3) + quality(0.2) + authority(0.2)
13
+ *
14
+ * 80-100: 健康 → 不转换
15
+ * 60-79: 关注 → Dashboard 警告
16
+ * 40-59: 衰退 → active → decaying
17
+ * 20-39: 严重 → Grace Period 缩短到 15d
18
+ * 0-19: 死亡 → 跳过确认直接 deprecated
19
+ */
20
+ import Logger from '../../infrastructure/logging/Logger.js';
21
+ /* ────────────────────── Constants ────────────────────── */
22
+ const DAY_MS = 24 * 60 * 60 * 1000;
23
+ const GRACE_PERIOD_STANDARD = 30 * DAY_MS;
24
+ const GRACE_PERIOD_SEVERE = 15 * DAY_MS;
25
+ const DECAY_THRESHOLDS = {
26
+ /** 无使用天数上限 */
27
+ NO_USAGE_DAYS: 90,
28
+ /** FP 率上限 */
29
+ FALSE_POSITIVE_RATE: 0.4,
30
+ /** FP 率可靠性所需最少触发次数 */
31
+ MIN_FP_TRIGGERS: 10,
32
+ };
33
+ const SCORE_WEIGHTS = {
34
+ freshness: 0.3,
35
+ usage: 0.3,
36
+ quality: 0.2,
37
+ authority: 0.2,
38
+ };
39
+ /* ────────────────────── Class ────────────────────── */
40
+ export class DecayDetector {
41
+ #db;
42
+ #signalBus;
43
+ #logger = Logger.getInstance();
44
+ constructor(db, options = {}) {
45
+ this.#db = db;
46
+ this.#signalBus = options.signalBus ?? null;
47
+ }
48
+ /**
49
+ * 扫描所有 active 条目的衰退状态
50
+ */
51
+ scanAll() {
52
+ const recipes = this.#loadActiveRecipes();
53
+ const results = [];
54
+ for (const recipe of recipes) {
55
+ const result = this.evaluate(recipe);
56
+ results.push(result);
57
+ }
58
+ // 发射衰退信号
59
+ if (this.#signalBus) {
60
+ for (const r of results) {
61
+ if (r.level !== 'healthy') {
62
+ this.#signalBus.send('decay', 'DecayDetector', 1 - r.decayScore / 100, {
63
+ target: r.recipeId,
64
+ metadata: {
65
+ level: r.level,
66
+ decayScore: r.decayScore,
67
+ signals: r.signals.map((s) => s.strategy),
68
+ },
69
+ });
70
+ }
71
+ }
72
+ }
73
+ this.#logger.debug(`DecayDetector: scanned ${results.length} recipes, ${results.filter((r) => r.level !== 'healthy').length} need attention`);
74
+ return results;
75
+ }
76
+ /**
77
+ * 评估单条 Recipe 的衰退状态
78
+ */
79
+ evaluate(recipe) {
80
+ const stats = DecayDetector.#parseStats(recipe.stats);
81
+ const signals = [];
82
+ const now = Date.now();
83
+ // 策略 1: 90 天无使用
84
+ const lastHitAt = stats.lastHitAt ?? null;
85
+ if (lastHitAt) {
86
+ const daysSince = (now - lastHitAt) / DAY_MS;
87
+ if (daysSince > DECAY_THRESHOLDS.NO_USAGE_DAYS) {
88
+ signals.push({
89
+ recipeId: recipe.id,
90
+ strategy: 'no_recent_usage',
91
+ detail: `No usage in ${Math.round(daysSince)} days (threshold: ${DECAY_THRESHOLDS.NO_USAGE_DAYS}d)`,
92
+ });
93
+ }
94
+ }
95
+ else {
96
+ // 无 lastHitAt,检查创建时间
97
+ const createdAt = recipe.created_at ? new Date(recipe.created_at).getTime() : now;
98
+ const daysSinceCreation = (now - createdAt) / DAY_MS;
99
+ if (daysSinceCreation > DECAY_THRESHOLDS.NO_USAGE_DAYS) {
100
+ signals.push({
101
+ recipeId: recipe.id,
102
+ strategy: 'no_recent_usage',
103
+ detail: `Never used, created ${Math.round(daysSinceCreation)} days ago`,
104
+ });
105
+ }
106
+ }
107
+ // 策略 2: 高 FP 率
108
+ const fpRate = stats.ruleFalsePositiveRate ?? 0;
109
+ const triggers = stats.guardHits ?? 0;
110
+ if (fpRate > DECAY_THRESHOLDS.FALSE_POSITIVE_RATE &&
111
+ triggers >= DECAY_THRESHOLDS.MIN_FP_TRIGGERS) {
112
+ signals.push({
113
+ recipeId: recipe.id,
114
+ strategy: 'high_false_positive',
115
+ detail: `FP rate ${(fpRate * 100).toFixed(0)}% with ${triggers} triggers (threshold: ${DECAY_THRESHOLDS.FALSE_POSITIVE_RATE * 100}%)`,
116
+ });
117
+ }
118
+ // 策略 3: 符号漂移(由 ReverseGuard 提供,此处从 DB 查 drift 标记)
119
+ if (this.#hasSymbolDrift(recipe.id)) {
120
+ signals.push({
121
+ recipeId: recipe.id,
122
+ strategy: 'symbol_drift',
123
+ detail: 'ReverseGuard detected symbol drift in coreCode',
124
+ });
125
+ }
126
+ // 策略 4: 被取代(有 deprecated_by 关系指向更新版本)
127
+ if (this.#isSuperseded(recipe.id)) {
128
+ signals.push({
129
+ recipeId: recipe.id,
130
+ strategy: 'superseded',
131
+ detail: 'Newer version exists via deprecated_by relation',
132
+ });
133
+ }
134
+ // 计算 decayScore
135
+ const dimensions = this.#computeScoreDimensions(stats, recipe);
136
+ const decayScore = Math.round(dimensions.freshness * SCORE_WEIGHTS.freshness * 100 +
137
+ dimensions.usage * SCORE_WEIGHTS.usage * 100 +
138
+ dimensions.quality * SCORE_WEIGHTS.quality * 100 +
139
+ dimensions.authority * SCORE_WEIGHTS.authority * 100);
140
+ const level = DecayDetector.#scoreToLevel(decayScore);
141
+ const suggestedGracePeriod = level === 'dead' ? 0 : level === 'severe' ? GRACE_PERIOD_SEVERE : GRACE_PERIOD_STANDARD;
142
+ return {
143
+ recipeId: recipe.id,
144
+ title: recipe.title,
145
+ decayScore,
146
+ level,
147
+ signals,
148
+ dimensions,
149
+ suggestedGracePeriod,
150
+ };
151
+ }
152
+ /* ── Internal ── */
153
+ #loadActiveRecipes() {
154
+ try {
155
+ const rows = this.#db
156
+ .prepare(`SELECT id, title, lifecycle, stats, quality_grade, quality_score, created_at
157
+ FROM knowledge_entries
158
+ WHERE lifecycle = 'active'`)
159
+ .all();
160
+ return rows.map((r) => ({
161
+ id: r.id,
162
+ title: r.title,
163
+ lifecycle: r.lifecycle,
164
+ stats: r.stats ?? null,
165
+ quality_grade: r.quality_grade ?? null,
166
+ quality_score: r.quality_score !== undefined ? Number(r.quality_score) : null,
167
+ created_at: r.created_at ?? null,
168
+ }));
169
+ }
170
+ catch {
171
+ return [];
172
+ }
173
+ }
174
+ static #parseStats(statsJson) {
175
+ if (!statsJson) {
176
+ return {};
177
+ }
178
+ try {
179
+ return JSON.parse(statsJson);
180
+ }
181
+ catch {
182
+ return {};
183
+ }
184
+ }
185
+ #computeScoreDimensions(stats, recipe) {
186
+ const now = Date.now();
187
+ // freshness: days since last hit → 0-1 (0 = 365+ days, 1 = today)
188
+ const lastHit = stats.lastHitAt ?? 0;
189
+ const daysSinceHit = lastHit > 0 ? (now - lastHit) / DAY_MS : 365;
190
+ const freshness = Math.max(0, 1 - daysSinceHit / 365);
191
+ // usage: hitsLast90d 归一化 (0 = 0 hits, 1 = 50+ hits)
192
+ const hitsLast90d = stats.hitsLast90d ?? 0;
193
+ const usage = Math.min(1, hitsLast90d / 50);
194
+ // quality: qualityScore 直接使用
195
+ const quality = recipe.quality_score ?? 0.5;
196
+ // authority: from stats.authority 归一化 (0-100 → 0-1)
197
+ const authorityRaw = stats.authority ?? 50;
198
+ const authority = Math.min(1, authorityRaw / 100);
199
+ return { freshness, usage, quality, authority };
200
+ }
201
+ #hasSymbolDrift(recipeId) {
202
+ try {
203
+ // 查找 audit_logs 中 ReverseGuard 为此 recipe 发过 drift 信号
204
+ const row = this.#db
205
+ .prepare(`SELECT 1 FROM audit_logs
206
+ WHERE action LIKE '%ReverseGuard%'
207
+ AND json_extract(details, '$.target') = ?
208
+ LIMIT 1`)
209
+ .get(recipeId);
210
+ return !!row;
211
+ }
212
+ catch {
213
+ return false;
214
+ }
215
+ }
216
+ #isSuperseded(recipeId) {
217
+ try {
218
+ const row = this.#db
219
+ .prepare(`SELECT 1 FROM knowledge_edges
220
+ WHERE source_id = ? AND relation_type = 'deprecated_by'
221
+ LIMIT 1`)
222
+ .get(recipeId);
223
+ return !!row;
224
+ }
225
+ catch {
226
+ return false;
227
+ }
228
+ }
229
+ static #scoreToLevel(score) {
230
+ if (score >= 80) {
231
+ return 'healthy';
232
+ }
233
+ if (score >= 60) {
234
+ return 'watch';
235
+ }
236
+ if (score >= 40) {
237
+ return 'decaying';
238
+ }
239
+ if (score >= 20) {
240
+ return 'severe';
241
+ }
242
+ return 'dead';
243
+ }
244
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * EnhancementSuggester — 使用数据反推增强建议
3
+ *
4
+ * 4 种增强策略:
5
+ * ① Guard 频繁命中但无 coreCode → 建议补充代码示例
6
+ * ② Search 高频命中但 adoptions=0 → 建议改善 usageGuide
7
+ * ③ 同类知识中 authority 偏低 → 建议补充 whenClause
8
+ * ④ 关联 Recipe 已 deprecated → 建议检查引用是否过时
9
+ */
10
+ import type { ReportStore } from '../../infrastructure/report/ReportStore.js';
11
+ import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
12
+ interface DatabaseLike {
13
+ prepare(sql: string): {
14
+ all(...params: unknown[]): Record<string, unknown>[];
15
+ get(...params: unknown[]): Record<string, unknown> | undefined;
16
+ };
17
+ }
18
+ export type EnhancementType = 'missing_code_example' | 'low_adoption' | 'low_authority' | 'deprecated_reference';
19
+ export interface EnhancementSuggestion {
20
+ recipeId: string;
21
+ title: string;
22
+ type: EnhancementType;
23
+ description: string;
24
+ priority: 'high' | 'medium' | 'low';
25
+ evidence: string[];
26
+ }
27
+ export declare class EnhancementSuggester {
28
+ #private;
29
+ constructor(db: DatabaseLike, options?: {
30
+ signalBus?: SignalBus;
31
+ reportStore?: ReportStore;
32
+ });
33
+ /**
34
+ * 运行全部 4 种增强策略
35
+ */
36
+ analyzeAll(): EnhancementSuggestion[];
37
+ }
38
+ export {};