autosnippet 3.3.5 → 3.3.6

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 (203) hide show
  1. package/dashboard/dist/assets/icons-D1aVZYFW.js +1 -0
  2. package/dashboard/dist/assets/index-CxHOu8Hd.css +1 -0
  3. package/dashboard/dist/assets/index-DDdAOpYT.js +128 -0
  4. package/dashboard/dist/index.html +3 -3
  5. package/dist/bin/api-server.js +1 -0
  6. package/dist/bin/cli.d.ts +1 -0
  7. package/dist/bin/cli.js +136 -9
  8. package/dist/lib/agent/AgentFactory.d.ts +0 -17
  9. package/dist/lib/agent/AgentFactory.js +1 -25
  10. package/dist/lib/agent/capabilities.d.ts +11 -0
  11. package/dist/lib/agent/capabilities.js +29 -5
  12. package/dist/lib/agent/context/ExplorationTracker.js +10 -1
  13. package/dist/lib/agent/context/exploration/ExplorationStrategies.d.ts +2 -0
  14. package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -2
  15. package/dist/lib/agent/domain/insight-analyst.d.ts +47 -3
  16. package/dist/lib/agent/domain/insight-analyst.js +111 -11
  17. package/dist/lib/agent/domain/insight-evolver.d.ts +69 -0
  18. package/dist/lib/agent/domain/insight-evolver.js +230 -0
  19. package/dist/lib/agent/domain/insight-gate.d.ts +42 -0
  20. package/dist/lib/agent/domain/insight-gate.js +41 -0
  21. package/dist/lib/agent/domain/insight-producer.d.ts +27 -2
  22. package/dist/lib/agent/domain/insight-producer.js +60 -5
  23. package/dist/lib/agent/domain/scan-prompts.js +10 -7
  24. package/dist/lib/agent/memory/ActiveContext.d.ts +2 -28
  25. package/dist/lib/agent/memory/MemoryCoordinator.d.ts +2 -2
  26. package/dist/lib/agent/memory/SessionStore.d.ts +6 -12
  27. package/dist/lib/agent/memory/SessionStore.js +9 -15
  28. package/dist/lib/agent/memory/memory-flush-contract.d.ts +49 -0
  29. package/dist/lib/agent/memory/memory-flush-contract.js +16 -0
  30. package/dist/lib/agent/memory/session-store-schema.d.ts +20 -0
  31. package/dist/lib/agent/memory/session-store-schema.js +41 -0
  32. package/dist/lib/agent/presets.d.ts +89 -1
  33. package/dist/lib/agent/presets.js +53 -5
  34. package/dist/lib/agent/tools/_shared.d.ts +7 -15
  35. package/dist/lib/agent/tools/_shared.js +20 -21
  36. package/dist/lib/agent/tools/composite.d.ts +25 -22
  37. package/dist/lib/agent/tools/composite.js +108 -109
  38. package/dist/lib/agent/tools/evolution-tools.d.ts +145 -0
  39. package/dist/lib/agent/tools/evolution-tools.js +161 -0
  40. package/dist/lib/agent/tools/index.d.ts +163 -92
  41. package/dist/lib/agent/tools/index.js +9 -1
  42. package/dist/lib/agent/tools/lifecycle.d.ts +7 -1
  43. package/dist/lib/agent/tools/lifecycle.js +59 -75
  44. package/dist/lib/cli/AiScanService.js +1 -1
  45. package/dist/lib/cli/KnowledgeSyncService.js +1 -1
  46. package/dist/lib/core/AstAnalyzer.d.ts +1 -0
  47. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.d.ts → domain/dimension/DimensionCopy.d.ts} +2 -2
  48. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.js → domain/dimension/DimensionCopy.js} +22 -72
  49. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +54 -0
  50. package/dist/lib/domain/dimension/DimensionRegistry.js +620 -0
  51. package/dist/lib/domain/dimension/DimensionSop.d.ts +55 -0
  52. package/dist/lib/domain/dimension/DimensionSop.js +1604 -0
  53. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +61 -0
  54. package/dist/lib/domain/dimension/UnifiedDimension.js +53 -0
  55. package/dist/lib/domain/dimension/index.d.ts +10 -0
  56. package/dist/lib/domain/dimension/index.js +9 -0
  57. package/dist/lib/domain/knowledge/FieldSpec.d.ts +1 -1
  58. package/dist/lib/domain/knowledge/FieldSpec.js +29 -16
  59. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +33 -111
  60. package/dist/lib/domain/knowledge/KnowledgeEntry.js +27 -6
  61. package/dist/lib/domain/knowledge/KnowledgeRepository.d.ts +1 -0
  62. package/dist/lib/domain/knowledge/KnowledgeRepository.js +3 -0
  63. package/dist/lib/domain/knowledge/Lifecycle.js +1 -1
  64. package/dist/lib/domain/knowledge/StyleGuide.d.ts +1 -1
  65. package/dist/lib/domain/knowledge/StyleGuide.js +1 -1
  66. package/dist/lib/domain/knowledge/UnifiedValidator.js +15 -0
  67. package/dist/lib/external/mcp/McpServer.js +4 -0
  68. package/dist/lib/external/mcp/handlers/TargetClassifier.d.ts +1 -1
  69. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.d.ts +8 -16
  70. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +10 -10
  71. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.d.ts +7 -0
  72. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +20 -0
  73. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +52 -132
  74. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +204 -17
  75. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.d.ts +11 -75
  76. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.js +40 -191
  77. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.d.ts +13 -78
  78. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +30 -52
  79. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.d.ts +0 -1
  80. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
  81. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +172 -161
  82. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
  83. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.d.ts +46 -0
  84. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.js +58 -0
  85. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.d.ts +25 -0
  86. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.js +47 -0
  87. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +50 -12
  88. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +30 -10
  89. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-text.js +1 -1
  90. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.d.ts +24 -0
  91. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.js +14 -0
  92. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.d.ts +14 -0
  93. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.js +48 -0
  94. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.d.ts +21 -0
  95. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.js +45 -0
  96. package/dist/lib/external/mcp/handlers/bootstrap/shared/skill-generator.d.ts +1 -1
  97. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.d.ts +27 -0
  98. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.js +44 -0
  99. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +14 -10
  100. package/dist/lib/external/mcp/handlers/bootstrap-external.js +39 -51
  101. package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
  102. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +115 -82
  103. package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
  104. package/dist/lib/external/mcp/handlers/consolidated.js +107 -332
  105. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +69 -1
  106. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
  107. package/dist/lib/external/mcp/handlers/evolve-external.js +226 -0
  108. package/dist/lib/external/mcp/handlers/knowledge.js +26 -2
  109. package/dist/lib/external/mcp/handlers/rescan-external.d.ts +76 -0
  110. package/dist/lib/external/mcp/handlers/rescan-external.js +335 -0
  111. package/dist/lib/external/mcp/handlers/rescan-internal.d.ts +120 -0
  112. package/dist/lib/external/mcp/handlers/rescan-internal.js +359 -0
  113. package/dist/lib/external/mcp/handlers/search.d.ts +6 -5
  114. package/dist/lib/external/mcp/handlers/search.js +6 -5
  115. package/dist/lib/external/mcp/handlers/types.d.ts +2 -1
  116. package/dist/lib/external/mcp/handlers/wiki-external.js +2 -2
  117. package/dist/lib/external/mcp/tools.d.ts +8 -18
  118. package/dist/lib/external/mcp/tools.js +58 -2
  119. package/dist/lib/http/routes/knowledge.js +122 -1
  120. package/dist/lib/http/routes/modules.js +25 -3
  121. package/dist/lib/http/routes/panorama.js +16 -4
  122. package/dist/lib/infrastructure/cache/CacheCoordinator.d.ts +41 -0
  123. package/dist/lib/infrastructure/cache/CacheCoordinator.js +105 -0
  124. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.d.ts +7 -0
  125. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.js +28 -0
  126. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +1 -1
  127. package/dist/lib/injection/ServiceContainer.js +55 -0
  128. package/dist/lib/injection/ServiceMap.d.ts +8 -1
  129. package/dist/lib/injection/modules/KnowledgeModule.js +15 -1
  130. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +4 -0
  131. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +16 -1
  132. package/dist/lib/service/bootstrap/BootstrapEventEmitter.d.ts +3 -2
  133. package/dist/lib/service/bootstrap/BootstrapEventEmitter.js +1 -1
  134. package/dist/lib/service/bootstrap/DeliveryVerifier.d.ts +51 -0
  135. package/dist/lib/service/bootstrap/DeliveryVerifier.js +163 -0
  136. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +5 -0
  137. package/dist/lib/service/bootstrap/UiStartupTasks.js +20 -0
  138. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +54 -0
  139. package/dist/lib/service/bootstrap/bootstrap-event-types.js +10 -0
  140. package/dist/lib/service/cleanup/CleanupService.d.ts +85 -0
  141. package/dist/lib/service/cleanup/CleanupService.js +324 -0
  142. package/dist/lib/service/delivery/AgentInstructionsGenerator.js +39 -43
  143. package/dist/lib/service/delivery/FileProtection.d.ts +20 -0
  144. package/dist/lib/service/delivery/FileProtection.js +54 -0
  145. package/dist/lib/service/delivery/SkillsSyncer.js +16 -21
  146. package/dist/lib/service/evolution/ContentPatcher.d.ts +44 -0
  147. package/dist/lib/service/evolution/ContentPatcher.js +310 -0
  148. package/dist/lib/service/evolution/ProposalExecutor.d.ts +4 -0
  149. package/dist/lib/service/evolution/ProposalExecutor.js +77 -13
  150. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +64 -0
  151. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +458 -0
  152. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +89 -0
  153. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +492 -0
  154. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +44 -0
  155. package/dist/lib/service/evolution/createSupersedeProposal.js +81 -0
  156. package/dist/lib/service/guard/ComplianceReporter.d.ts +4 -0
  157. package/dist/lib/service/guard/ComplianceReporter.js +51 -0
  158. package/dist/lib/service/guard/GuardCheckEngine.js +5 -4
  159. package/dist/lib/service/knowledge/ConfidenceRouter.js +1 -1
  160. package/dist/lib/service/knowledge/KnowledgeService.d.ts +11 -1
  161. package/dist/lib/service/knowledge/KnowledgeService.js +44 -4
  162. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
  163. package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
  164. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +3 -2
  165. package/dist/lib/service/panorama/DimensionAnalyzer.js +15 -140
  166. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  167. package/dist/lib/service/search/SearchEngine.d.ts +11 -10
  168. package/dist/lib/service/search/SearchEngine.js +38 -36
  169. package/dist/lib/service/search/SearchTypes.d.ts +14 -8
  170. package/dist/lib/service/search/SearchTypes.js +1 -1
  171. package/dist/lib/service/search/tokenizer.d.ts +1 -1
  172. package/dist/lib/service/search/tokenizer.js +2 -2
  173. package/dist/lib/shared/schemas/common.d.ts +4 -4
  174. package/dist/lib/shared/schemas/http-requests.d.ts +12 -1
  175. package/dist/lib/shared/schemas/http-requests.js +8 -0
  176. package/dist/lib/shared/schemas/mcp-tools.d.ts +32 -2
  177. package/dist/lib/shared/schemas/mcp-tools.js +38 -0
  178. package/dist/lib/types/evolution.d.ts +135 -0
  179. package/dist/lib/types/evolution.js +6 -0
  180. package/dist/lib/types/graph-shared.d.ts +25 -0
  181. package/dist/lib/types/graph-shared.js +7 -0
  182. package/dist/lib/types/knowledge-wire.d.ts +131 -0
  183. package/dist/lib/types/knowledge-wire.js +7 -0
  184. package/dist/lib/types/project-snapshot-builder.d.ts +19 -0
  185. package/dist/lib/types/project-snapshot-builder.js +189 -0
  186. package/dist/lib/types/project-snapshot.d.ts +399 -0
  187. package/dist/lib/types/project-snapshot.js +17 -0
  188. package/dist/lib/types/search-wire.d.ts +46 -0
  189. package/dist/lib/types/search-wire.js +7 -0
  190. package/dist/lib/types/snapshot-views.d.ts +58 -0
  191. package/dist/lib/types/snapshot-views.js +103 -0
  192. package/package.json +1 -1
  193. package/skills/autosnippet-recipes/SKILL.md +1 -1
  194. package/templates/instructions/agent-static.md +2 -0
  195. package/templates/instructions/conventions.md +3 -1
  196. package/templates/recipes-setup/README.md +2 -2
  197. package/dashboard/dist/assets/icons-BJ2mUBi8.js +0 -1
  198. package/dashboard/dist/assets/index-B659K9t5.js +0 -128
  199. package/dashboard/dist/assets/index-NCm40PMD.css +0 -1
  200. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.d.ts +0 -169
  201. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +0 -727
  202. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.d.ts +0 -370
  203. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +0 -821
@@ -0,0 +1,492 @@
1
+ /**
2
+ * RecipeRelevanceAuditor — 基于代码证据验证 Recipe 当前相关性
3
+ *
4
+ * Rescan 时主动触发,检查每个保留 Recipe 的代码证据是否仍然存在:
5
+ * 1. 触发模式匹配 (trigger 引用的文件类型/路径模式是否有匹配)
6
+ * 2. 代码符号存活 (content.pattern 引用的类名/函数名是否在 AST 中)
7
+ * 3. 依赖关系完整 (涉及模块依赖是否在依赖图中)
8
+ * 4. 源代码文件存活 (reasoning.sources + content.codeChanges 的文件是否存在)
9
+ *
10
+ * 评分后驱动快速衰退:
11
+ * - healthy (80-100): 无操作
12
+ * - watch (60-79): 报告警告
13
+ * - decay (40-59): active → decaying (7d grace)
14
+ * - severe (20-39): active → decaying (3d grace)
15
+ * - dead (0-19): active → deprecated (immediate)
16
+ *
17
+ * 支持 Category 权重豁免:架构/规范类 Recipe 侧重触发模式而非具体符号。
18
+ *
19
+ * @module service/evolution/RecipeRelevanceAuditor
20
+ */
21
+ // ── 常量 ────────────────────────────────────────────────────
22
+ /** 默认证据权重
23
+ *
24
+ * 注意:不包含 sourceFileExists。DB 中 sourceFile 存储的是 Recipe md 文件路径
25
+ * (如 AutoSnippet/candidates/xxx.md),不是源代码路径。
26
+ * 真正的源代码来源在 reasoning.sources 中,由 codeFilesExist 维度检查。
27
+ */
28
+ const DEFAULT_WEIGHTS = {
29
+ triggerStillMatches: 0.2,
30
+ symbolsAlive: 0.3,
31
+ depsIntact: 0.15,
32
+ codeFilesExist: 0.35,
33
+ };
34
+ /**
35
+ * 按 category 覆盖权重 — 架构/规范类侧重触发模式和来源文件
36
+ */
37
+ const CATEGORY_WEIGHT_OVERRIDES = {
38
+ architecture: {
39
+ symbolsAlive: 0.05,
40
+ depsIntact: 0.05,
41
+ triggerStillMatches: 0.45,
42
+ codeFilesExist: 0.45,
43
+ },
44
+ 'coding-standards': {
45
+ symbolsAlive: 0.05,
46
+ depsIntact: 0.05,
47
+ triggerStillMatches: 0.45,
48
+ codeFilesExist: 0.45,
49
+ },
50
+ 'agent-guidelines': {
51
+ symbolsAlive: 0.0,
52
+ depsIntact: 0.0,
53
+ triggerStillMatches: 0.5,
54
+ codeFilesExist: 0.5,
55
+ },
56
+ };
57
+ /** Grace Period 常量 */
58
+ const GRACE_PERIOD_DECAY = 7 * 24 * 60 * 60 * 1000; // 7d
59
+ const GRACE_PERIOD_SEVERE = 3 * 24 * 60 * 60 * 1000; // 3d
60
+ // ── RecipeRelevanceAuditor ──────────────────────────────────
61
+ export class RecipeRelevanceAuditor {
62
+ #db;
63
+ #logger;
64
+ constructor(opts) {
65
+ const dbRaw = opts.db;
66
+ this.#db = typeof dbRaw?.getDb === 'function' ? dbRaw.getDb() : opts.db;
67
+ this.#logger = opts.logger || { info() { }, warn() { } };
68
+ }
69
+ /**
70
+ * 审计所有保留 Recipe 的代码证据
71
+ */
72
+ async audit(recipes, analysisData) {
73
+ const summary = {
74
+ totalAudited: 0,
75
+ healthy: 0,
76
+ watch: 0,
77
+ decay: 0,
78
+ severe: 0,
79
+ dead: 0,
80
+ results: [],
81
+ proposalsCreated: 0,
82
+ immediateDeprecated: 0,
83
+ };
84
+ // 预处理:构建快速查找集合
85
+ const fileSet = new Set(analysisData.fileList.map((f) => f.toLowerCase()));
86
+ const entityNames = new Set(analysisData.codeEntities.map((e) => e.name.toLowerCase()));
87
+ const depModules = new Set();
88
+ for (const edge of analysisData.dependencyGraph) {
89
+ depModules.add(edge.from.toLowerCase());
90
+ depModules.add(edge.to.toLowerCase());
91
+ }
92
+ for (const recipe of recipes) {
93
+ const fullRecipe = this.#loadFullRecipe(recipe.id);
94
+ if (!fullRecipe) {
95
+ continue;
96
+ }
97
+ const result = this.#computeRelevanceScore(fullRecipe, {
98
+ fileSet,
99
+ entityNames,
100
+ depModules,
101
+ fileList: analysisData.fileList,
102
+ });
103
+ summary.totalAudited++;
104
+ summary[result.verdict]++;
105
+ summary.results.push(result);
106
+ // 执行衰退状态转换
107
+ if (result.verdict === 'dead' || result.verdict === 'severe' || result.verdict === 'decay') {
108
+ const executed = this.#executeDecay(result);
109
+ if (result.verdict === 'dead') {
110
+ summary.immediateDeprecated += executed ? 1 : 0;
111
+ }
112
+ if (executed) {
113
+ summary.proposalsCreated++;
114
+ }
115
+ }
116
+ }
117
+ this.#logger.info('[RecipeRelevanceAuditor] Audit complete', {
118
+ total: summary.totalAudited,
119
+ healthy: summary.healthy,
120
+ watch: summary.watch,
121
+ decay: summary.decay,
122
+ severe: summary.severe,
123
+ dead: summary.dead,
124
+ });
125
+ return summary;
126
+ }
127
+ // ─── 内部方法 ─────────────────────────────────────────
128
+ /** 从 DB 加载完整 Recipe 数据 */
129
+ #loadFullRecipe(id) {
130
+ try {
131
+ const row = this.#db
132
+ .prepare(`SELECT id, title, trigger, category,
133
+ content, doClause, coreCode
134
+ FROM knowledge_entries WHERE id = ?`)
135
+ .get(id);
136
+ return row || null;
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ }
142
+ /** 计算单个 Recipe 的 relevanceScore */
143
+ #computeRelevanceScore(recipe, ctx) {
144
+ const category = recipe.category || '';
145
+ const weights = {
146
+ ...DEFAULT_WEIGHTS,
147
+ ...(CATEGORY_WEIGHT_OVERRIDES[category] || {}),
148
+ };
149
+ const decayReasons = [];
150
+ // 1. trigger 模式匹配
151
+ const triggerStillMatches = this.#checkTriggerMatch(recipe.trigger, ctx.fileList);
152
+ if (!triggerStillMatches) {
153
+ decayReasons.push(`触发条件 "${recipe.trigger}" 无匹配文件`);
154
+ }
155
+ // 2. 代码符号存活率
156
+ const referencedSymbols = this.#extractReferencedSymbols(recipe);
157
+ let symbolsAlive = 1.0;
158
+ if (referencedSymbols.length > 0) {
159
+ const aliveCount = referencedSymbols.filter((s) => ctx.entityNames.has(s.toLowerCase())).length;
160
+ symbolsAlive = aliveCount / referencedSymbols.length;
161
+ if (symbolsAlive < 0.5) {
162
+ decayReasons.push(`引用符号存活 ${aliveCount}/${referencedSymbols.length} (${(symbolsAlive * 100).toFixed(0)}%)`);
163
+ }
164
+ }
165
+ // 3. 依赖关系完整性
166
+ const referencedModules = this.#extractModuleReferences(recipe);
167
+ let depsIntact = true;
168
+ if (referencedModules.length > 0) {
169
+ const intactCount = referencedModules.filter((m) => ctx.depModules.has(m.toLowerCase())).length;
170
+ depsIntact = intactCount >= referencedModules.length * 0.5;
171
+ if (!depsIntact) {
172
+ decayReasons.push(`模块依赖 ${intactCount}/${referencedModules.length} 存活`);
173
+ }
174
+ }
175
+ // 4. 源代码文件存活率(来自 reasoning.sources + content.codeChanges)
176
+ const codeFiles = this.#extractCodeFiles(recipe);
177
+ let codeFilesExist = 1.0;
178
+ if (codeFiles.length > 0) {
179
+ const existCount = codeFiles.filter((f) => ctx.fileSet.has(f.toLowerCase())).length;
180
+ codeFilesExist = existCount / codeFiles.length;
181
+ if (codeFilesExist < 0.5) {
182
+ decayReasons.push(`codeChanges 文件存活 ${existCount}/${codeFiles.length}`);
183
+ }
184
+ }
185
+ // 加权计算 relevanceScore
186
+ const relevanceScore = Math.round((triggerStillMatches ? 1 : 0) * weights.triggerStillMatches * 100 +
187
+ symbolsAlive * weights.symbolsAlive * 100 +
188
+ (depsIntact ? 1 : 0) * weights.depsIntact * 100 +
189
+ codeFilesExist * weights.codeFilesExist * 100);
190
+ // 分级判定
191
+ let verdict;
192
+ if (relevanceScore >= 80) {
193
+ verdict = 'healthy';
194
+ }
195
+ else if (relevanceScore >= 60) {
196
+ verdict = 'watch';
197
+ }
198
+ else if (relevanceScore >= 40) {
199
+ verdict = 'decay';
200
+ }
201
+ else if (relevanceScore >= 20) {
202
+ verdict = 'severe';
203
+ }
204
+ else {
205
+ verdict = 'dead';
206
+ }
207
+ return {
208
+ recipeId: recipe.id,
209
+ title: recipe.title,
210
+ relevanceScore,
211
+ verdict,
212
+ evidence: {
213
+ triggerStillMatches,
214
+ symbolsAlive,
215
+ depsIntact,
216
+ codeFilesExist,
217
+ },
218
+ decayReasons,
219
+ };
220
+ }
221
+ /** 检查 trigger 模式是否仍有匹配文件 */
222
+ #checkTriggerMatch(trigger, fileList) {
223
+ if (!trigger || trigger.trim() === '') {
224
+ return true; // 无 trigger 视为匹配
225
+ }
226
+ const triggerLower = trigger.toLowerCase();
227
+ // 检查 @trigger 格式 (如 @bilidili-api-response-model)
228
+ // 这些是自定义 trigger,不与文件路径匹配,视为始终有效
229
+ if (triggerLower.startsWith('@')) {
230
+ return true;
231
+ }
232
+ // 检查文件扩展名匹配 (如 "When creating .swift files")
233
+ const extMatch = triggerLower.match(/\.(swift|ts|tsx|js|jsx|py|java|kt|rb|go|rs|vue|svelte)\b/);
234
+ if (extMatch) {
235
+ const ext = extMatch[0];
236
+ return fileList.some((f) => f.toLowerCase().endsWith(ext));
237
+ }
238
+ // 检查路径模式匹配 (如 "When modifying Packages/")
239
+ const pathPatterns = trigger.match(/(?:[\w.-]+\/)+[\w.-]*/g) || [];
240
+ if (pathPatterns.length > 0) {
241
+ return pathPatterns.some((pattern) => {
242
+ const p = pattern.toLowerCase();
243
+ return fileList.some((f) => f.toLowerCase().includes(p));
244
+ });
245
+ }
246
+ // 无法判断时视为匹配
247
+ return true;
248
+ }
249
+ /** 从 Recipe content 中提取引用的符号 */
250
+ #extractReferencedSymbols(recipe) {
251
+ const symbols = [];
252
+ // 从 content JSON 中提取
253
+ try {
254
+ const content = JSON.parse(recipe.content || '{}');
255
+ const pattern = content.pattern || '';
256
+ const markdown = content.markdown || '';
257
+ const text = `${pattern} ${markdown} ${recipe.doClause || ''} ${recipe.coreCode || ''}`;
258
+ // 匹配 PascalCase 标识符 (类名/协议名)
259
+ const identifiers = text.match(/\b[A-Z][a-zA-Z0-9]{2,}\b/g) || [];
260
+ // 去掉常见英文单词
261
+ const COMMON_WORDS = new Set([
262
+ 'When',
263
+ 'Then',
264
+ 'The',
265
+ 'This',
266
+ 'That',
267
+ 'Use',
268
+ 'Not',
269
+ 'All',
270
+ 'For',
271
+ 'With',
272
+ 'From',
273
+ 'Each',
274
+ 'Must',
275
+ 'May',
276
+ 'Can',
277
+ 'Will',
278
+ 'Has',
279
+ 'Are',
280
+ 'New',
281
+ 'Set',
282
+ 'Get',
283
+ 'Add',
284
+ 'Run',
285
+ 'End',
286
+ 'Try',
287
+ 'Nil',
288
+ 'True',
289
+ 'False',
290
+ 'Void',
291
+ 'Self',
292
+ 'Type',
293
+ 'Error',
294
+ 'Result',
295
+ 'String',
296
+ 'Int',
297
+ 'Bool',
298
+ 'Array',
299
+ 'Dict',
300
+ 'Optional',
301
+ 'Protocol',
302
+ 'Class',
303
+ 'Struct',
304
+ 'Enum',
305
+ 'Import',
306
+ 'Return',
307
+ 'Override',
308
+ 'Private',
309
+ 'Public',
310
+ 'Internal',
311
+ 'Func',
312
+ 'Var',
313
+ 'Let',
314
+ 'Guard',
315
+ 'Async',
316
+ 'Await',
317
+ 'Throws',
318
+ 'Release',
319
+ 'Debug',
320
+ 'Swift',
321
+ 'Function',
322
+ 'Method',
323
+ 'Property',
324
+ 'Value',
325
+ 'Default',
326
+ 'Shared',
327
+ 'Static',
328
+ 'Final',
329
+ 'Weak',
330
+ 'Lazy',
331
+ ]);
332
+ for (const id of identifiers) {
333
+ if (!COMMON_WORDS.has(id) && id.length >= 3) {
334
+ symbols.push(id);
335
+ }
336
+ }
337
+ }
338
+ catch {
339
+ /* invalid JSON */
340
+ }
341
+ // 去重
342
+ return [...new Set(symbols)];
343
+ }
344
+ /** 从 Recipe 中提取模块/依赖引用 */
345
+ #extractModuleReferences(recipe) {
346
+ const modules = [];
347
+ try {
348
+ const content = JSON.parse(recipe.content || '{}');
349
+ const text = `${content.markdown || ''} ${content.pattern || ''} ${recipe.doClause || ''}`;
350
+ // 匹配 import 语句中的模块名
351
+ const importMatches = text.match(/import\s+(\w+)/g) || [];
352
+ for (const m of importMatches) {
353
+ const name = m.replace(/^import\s+/, '');
354
+ if (name.length >= 2) {
355
+ modules.push(name);
356
+ }
357
+ }
358
+ }
359
+ catch {
360
+ /* invalid JSON */
361
+ }
362
+ return [...new Set(modules)];
363
+ }
364
+ /** 从 Recipe 中提取 codeChanges 引用的文件路径 */
365
+ #extractCodeFiles(recipe) {
366
+ const files = [];
367
+ try {
368
+ const content = JSON.parse(recipe.content || '{}');
369
+ const codeChanges = content.codeChanges;
370
+ if (Array.isArray(codeChanges)) {
371
+ for (const change of codeChanges) {
372
+ if (change.file) {
373
+ files.push(change.file);
374
+ }
375
+ }
376
+ }
377
+ // reasoning.sources 在 content 外层,由下方独立查询处理
378
+ }
379
+ catch {
380
+ /* invalid JSON */
381
+ }
382
+ // 也从 recipe 的 sourceFile 来源引用
383
+ try {
384
+ const row = this.#db
385
+ .prepare(`SELECT reasoning FROM knowledge_entries WHERE id = ?`)
386
+ .get(recipe.id);
387
+ if (row?.reasoning) {
388
+ const reasoning = JSON.parse(row.reasoning);
389
+ if (Array.isArray(reasoning.sources)) {
390
+ for (const src of reasoning.sources) {
391
+ if (typeof src === 'string') {
392
+ files.push(src);
393
+ }
394
+ else if (src?.file) {
395
+ files.push(src.file);
396
+ }
397
+ else if (src?.path) {
398
+ files.push(src.path);
399
+ }
400
+ }
401
+ }
402
+ }
403
+ }
404
+ catch {
405
+ /* invalid JSON */
406
+ }
407
+ return [...new Set(files)];
408
+ }
409
+ /** 执行衰退状态转换 */
410
+ #executeDecay(result) {
411
+ try {
412
+ const now = Date.now();
413
+ switch (result.verdict) {
414
+ case 'dead': {
415
+ // 直接 deprecated,无需观察
416
+ this.#db
417
+ .prepare(`UPDATE knowledge_entries SET lifecycle = 'deprecated', updatedAt = ? WHERE id = ?`)
418
+ .run(now, result.recipeId);
419
+ // 记录已执行的 proposal(审计追溯)
420
+ this.#createProposal({
421
+ targetRecipeId: result.recipeId,
422
+ type: 'deprecate',
423
+ source: 'rescan-relevance-audit',
424
+ status: 'executed',
425
+ description: `[Rescan Relevance Audit] Score: ${result.relevanceScore}. ${result.decayReasons.join('; ')}`,
426
+ evidence: { relevanceScore: result.relevanceScore, evidence: result.evidence },
427
+ expiresAt: now,
428
+ });
429
+ this.#logger.info(`[RecipeRelevanceAuditor] DEAD: "${result.title}" → deprecated (score: ${result.relevanceScore})`);
430
+ return true;
431
+ }
432
+ case 'severe': {
433
+ // 加速衰退:3 天观察窗口
434
+ this.#db
435
+ .prepare(`UPDATE knowledge_entries SET lifecycle = 'decaying', updatedAt = ? WHERE id = ?`)
436
+ .run(now, result.recipeId);
437
+ this.#createProposal({
438
+ targetRecipeId: result.recipeId,
439
+ type: 'deprecate',
440
+ source: 'rescan-relevance-audit',
441
+ status: 'observing',
442
+ description: `[Rescan Relevance Audit] Score: ${result.relevanceScore}. ${result.decayReasons.join('; ')}`,
443
+ evidence: { relevanceScore: result.relevanceScore, evidence: result.evidence },
444
+ expiresAt: now + GRACE_PERIOD_SEVERE,
445
+ });
446
+ this.#logger.info(`[RecipeRelevanceAuditor] SEVERE: "${result.title}" → decaying (3d grace, score: ${result.relevanceScore})`);
447
+ return true;
448
+ }
449
+ case 'decay': {
450
+ // 加速衰退:7 天观察窗口
451
+ this.#db
452
+ .prepare(`UPDATE knowledge_entries SET lifecycle = 'decaying', updatedAt = ? WHERE id = ?`)
453
+ .run(now, result.recipeId);
454
+ this.#createProposal({
455
+ targetRecipeId: result.recipeId,
456
+ type: 'deprecate',
457
+ source: 'rescan-relevance-audit',
458
+ status: 'observing',
459
+ description: `[Rescan Relevance Audit] Score: ${result.relevanceScore}. ${result.decayReasons.join('; ')}`,
460
+ evidence: { relevanceScore: result.relevanceScore, evidence: result.evidence },
461
+ expiresAt: now + GRACE_PERIOD_DECAY,
462
+ });
463
+ this.#logger.info(`[RecipeRelevanceAuditor] DECAY: "${result.title}" → decaying (7d grace, score: ${result.relevanceScore})`);
464
+ return true;
465
+ }
466
+ default:
467
+ return false;
468
+ }
469
+ }
470
+ catch (err) {
471
+ const msg = err instanceof Error ? err.message : String(err);
472
+ this.#logger.warn(`[RecipeRelevanceAuditor] executeDecay failed for ${result.recipeId}: ${msg}`);
473
+ return false;
474
+ }
475
+ }
476
+ /** 创建 evolution proposal */
477
+ #createProposal(input) {
478
+ try {
479
+ const id = `ep-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
480
+ this.#db
481
+ .prepare(`INSERT INTO evolution_proposals
482
+ (id, type, target_recipe_id, related_recipe_ids, confidence, source,
483
+ description, evidence, status, proposed_at, expires_at)
484
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
485
+ .run(id, input.type, input.targetRecipeId, '[]', 0.95, input.source, input.description, JSON.stringify([input.evidence]), input.status, Date.now(), input.expiresAt);
486
+ }
487
+ catch (err) {
488
+ const msg = err instanceof Error ? err.message : String(err);
489
+ this.#logger.warn(`[RecipeRelevanceAuditor] createProposal failed: ${msg}`);
490
+ }
491
+ }
492
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * createSupersedeProposal — 统一的 supersede 提案创建逻辑
3
+ *
4
+ * 内部 Agent 路径 (lifecycle.ts / composite.ts) 和外部 MCP 路径 (consolidated.ts)
5
+ * 共用此函数,确保知识替代的进化架构入口唯一。
6
+ *
7
+ * 流程:
8
+ * 1. 从 DI 容器获取 ProposalRepository
9
+ * 2. 验证旧 Recipe 存在
10
+ * 3. 去重检查(ProposalRepository 内部)
11
+ * 4. 创建 type='supersede' 提案,进入 72h 观察窗口
12
+ */
13
+ import type { ProposalSource } from '../../repository/evolution/ProposalRepository.js';
14
+ /** 最小 DI 容器接口 — 兼容 ServiceContainer / McpServiceContainer / ToolHandlerContext.container */
15
+ interface MinimalContainer {
16
+ get(name: string): unknown;
17
+ }
18
+ export interface SupersedeInput {
19
+ /** 被替代的旧 Recipe ID */
20
+ oldRecipeId: string;
21
+ /** 新提交的 Recipe ID 列表 */
22
+ newRecipeIds: string[];
23
+ /** 来源标识:'ide-agent' | 'metabolism' | 'decay-scan' */
24
+ source?: ProposalSource;
25
+ /** 置信度,默认 0.8 */
26
+ confidence?: number;
27
+ }
28
+ export interface SupersedeResult {
29
+ proposalId: string;
30
+ type: 'supersede';
31
+ targetRecipe: {
32
+ id: string;
33
+ };
34
+ status: string;
35
+ expiresAt: number;
36
+ message: string;
37
+ }
38
+ /**
39
+ * 在 DI 容器中查找 ProposalRepository,验证旧 Recipe 存在后创建 supersede 提案。
40
+ *
41
+ * @returns SupersedeResult(成功)| null(ProposalRepo 不可用 / 旧 Recipe 不存在 / 去重拒绝)
42
+ */
43
+ export declare function createSupersedeProposal(container: MinimalContainer, input: SupersedeInput): SupersedeResult | null;
44
+ export {};
@@ -0,0 +1,81 @@
1
+ /**
2
+ * createSupersedeProposal — 统一的 supersede 提案创建逻辑
3
+ *
4
+ * 内部 Agent 路径 (lifecycle.ts / composite.ts) 和外部 MCP 路径 (consolidated.ts)
5
+ * 共用此函数,确保知识替代的进化架构入口唯一。
6
+ *
7
+ * 流程:
8
+ * 1. 从 DI 容器获取 ProposalRepository
9
+ * 2. 验证旧 Recipe 存在
10
+ * 3. 去重检查(ProposalRepository 内部)
11
+ * 4. 创建 type='supersede' 提案,进入 72h 观察窗口
12
+ */
13
+ /* ────────────────────── Main ────────────────────── */
14
+ /**
15
+ * 在 DI 容器中查找 ProposalRepository,验证旧 Recipe 存在后创建 supersede 提案。
16
+ *
17
+ * @returns SupersedeResult(成功)| null(ProposalRepo 不可用 / 旧 Recipe 不存在 / 去重拒绝)
18
+ */
19
+ export function createSupersedeProposal(container, input) {
20
+ const { oldRecipeId, newRecipeIds, source = 'ide-agent', confidence = 0.8 } = input;
21
+ if (!oldRecipeId || newRecipeIds.length === 0) {
22
+ return null;
23
+ }
24
+ // 1. 获取 ProposalRepository
25
+ let proposalRepo = null;
26
+ try {
27
+ proposalRepo = container.get('proposalRepository') ?? null;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ if (!proposalRepo) {
33
+ return null;
34
+ }
35
+ // 2. 验证旧 Recipe 存在
36
+ if (!verifyRecipeExists(container, oldRecipeId)) {
37
+ return null;
38
+ }
39
+ // 3. 创建 supersede 提案(ProposalRepository 内部做去重检查)
40
+ const proposal = proposalRepo.create({
41
+ type: 'supersede',
42
+ targetRecipeId: oldRecipeId,
43
+ relatedRecipeIds: newRecipeIds,
44
+ confidence,
45
+ source,
46
+ description: `Agent 声明新 Recipe [${newRecipeIds.join(', ')}] 替代旧 Recipe [${oldRecipeId}]。观察窗口内将对比新旧表现。`,
47
+ evidence: [
48
+ {
49
+ snapshotAt: Date.now(),
50
+ newRecipeIds,
51
+ declaredBy: source,
52
+ },
53
+ ],
54
+ });
55
+ if (!proposal) {
56
+ return null;
57
+ }
58
+ return {
59
+ proposalId: proposal.id,
60
+ type: 'supersede',
61
+ targetRecipe: { id: oldRecipeId },
62
+ status: proposal.status,
63
+ expiresAt: proposal.expiresAt,
64
+ message: `已创建替代提案:新 Recipe 将在观察窗口到期后自动替代旧 Recipe [${oldRecipeId}]。`,
65
+ };
66
+ }
67
+ /* ────────────────────── Helpers ────────────────────── */
68
+ function verifyRecipeExists(container, recipeId) {
69
+ try {
70
+ const db = container.get('database');
71
+ if (!db) {
72
+ return false;
73
+ }
74
+ const rawDb = db.getDb();
75
+ const row = rawDb.prepare('SELECT id FROM knowledge_entries WHERE id = ?').get(recipeId);
76
+ return row !== undefined;
77
+ }
78
+ catch {
79
+ return false;
80
+ }
81
+ }
@@ -72,6 +72,10 @@ interface GuardCheckEngineLike {
72
72
  }[];
73
73
  };
74
74
  };
75
+ /** Enhancement Pack 注入(可选,引擎不一定暴露) */
76
+ isEpInjected?(): boolean;
77
+ injectExternalRules?(rules: unknown[]): void;
78
+ markEpInjected?(): void;
75
79
  }
76
80
  interface ViolationItem {
77
81
  ruleId: string;
@@ -82,6 +82,53 @@ export class ComplianceReporter {
82
82
  });
83
83
  }
84
84
  }
85
+ /**
86
+ * 确保 Enhancement Pack 规则已注入到 engine
87
+ * 与 MCP guard handler 的 _injectEnhancementGuardRules 逻辑一致
88
+ */
89
+ async #ensureEnhancementPackRules() {
90
+ if (!this.engine.isEpInjected || this.engine.isEpInjected()) {
91
+ return;
92
+ }
93
+ try {
94
+ const { initEnhancementRegistry } = await import('#core/enhancement/index.js');
95
+ const enhReg = await initEnhancementRegistry();
96
+ const allPacks = enhReg.all();
97
+ const allGuardRules = [];
98
+ for (const pack of allPacks) {
99
+ try {
100
+ const rules = pack.getGuardRules();
101
+ if (rules.length > 0) {
102
+ allGuardRules.push(...rules);
103
+ }
104
+ }
105
+ catch {
106
+ /* graceful degradation per pack */
107
+ }
108
+ }
109
+ if (allGuardRules.length > 0 && this.engine.injectExternalRules) {
110
+ this.engine.injectExternalRules(allGuardRules);
111
+ this.logger.info(`[ComplianceReporter] Injected ${allGuardRules.length} Enhancement Pack rules`);
112
+ }
113
+ this.engine.markEpInjected?.();
114
+ }
115
+ catch {
116
+ /* Enhancement registry not available — non-critical */
117
+ }
118
+ }
119
+ /**
120
+ * 确保 AST 语言插件已加载(Tree-sitter WASM)
121
+ * 未加载时 _runAstLayer2Checks 会静默跳过,导致 AST 类违规无法检测
122
+ */
123
+ async #ensureAstPlugins() {
124
+ try {
125
+ const { loadPlugins } = await import('../../core/ast/index.js');
126
+ await loadPlugins();
127
+ }
128
+ catch {
129
+ /* AST not available — graceful degradation */
130
+ }
131
+ }
85
132
  /**
86
133
  * 生成全项目合规报告
87
134
  * @param projectRoot 项目根目录
@@ -91,6 +138,10 @@ export class ComplianceReporter {
91
138
  async generate(projectRoot, options = {}) {
92
139
  const thresholds = { ...this.qualityGateConfig, ...(options.qualityGate || {}) };
93
140
  const maxFiles = options.maxFiles || 500;
141
+ // 0. 确保 Enhancement Pack 规则已注入(与 MCP guard handler 保持一致)
142
+ await this.#ensureEnhancementPackRules();
143
+ // 0b. 确保 AST 语言插件已加载(Tree-sitter WASM)
144
+ await this.#ensureAstPlugins();
94
145
  // 1. 收集源文件
95
146
  const files = await collectSourceFilesWithContent(projectRoot, { maxFiles });
96
147
  this.logger.info(`[ComplianceReporter] Collected ${files.length} source files`);