autosnippet 3.3.4 → 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 (221) hide show
  1. package/README.md +174 -83
  2. package/config/constitution.yaml +2 -0
  3. package/dashboard/dist/assets/icons-D1aVZYFW.js +1 -0
  4. package/dashboard/dist/assets/index-CxHOu8Hd.css +1 -0
  5. package/dashboard/dist/assets/index-DDdAOpYT.js +128 -0
  6. package/dashboard/dist/index.html +3 -3
  7. package/dist/bin/api-server.js +1 -0
  8. package/dist/bin/cli.d.ts +1 -0
  9. package/dist/bin/cli.js +136 -9
  10. package/dist/lib/agent/AgentFactory.d.ts +0 -17
  11. package/dist/lib/agent/AgentFactory.js +1 -25
  12. package/dist/lib/agent/capabilities.d.ts +11 -0
  13. package/dist/lib/agent/capabilities.js +29 -5
  14. package/dist/lib/agent/context/ExplorationTracker.js +10 -1
  15. package/dist/lib/agent/context/exploration/ExplorationStrategies.d.ts +2 -0
  16. package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -2
  17. package/dist/lib/agent/domain/insight-analyst.d.ts +47 -3
  18. package/dist/lib/agent/domain/insight-analyst.js +111 -11
  19. package/dist/lib/agent/domain/insight-evolver.d.ts +69 -0
  20. package/dist/lib/agent/domain/insight-evolver.js +230 -0
  21. package/dist/lib/agent/domain/insight-gate.d.ts +42 -0
  22. package/dist/lib/agent/domain/insight-gate.js +41 -0
  23. package/dist/lib/agent/domain/insight-producer.d.ts +27 -2
  24. package/dist/lib/agent/domain/insight-producer.js +60 -5
  25. package/dist/lib/agent/domain/scan-prompts.js +10 -7
  26. package/dist/lib/agent/memory/ActiveContext.d.ts +2 -28
  27. package/dist/lib/agent/memory/MemoryCoordinator.d.ts +2 -2
  28. package/dist/lib/agent/memory/SessionStore.d.ts +6 -12
  29. package/dist/lib/agent/memory/SessionStore.js +9 -15
  30. package/dist/lib/agent/memory/memory-flush-contract.d.ts +49 -0
  31. package/dist/lib/agent/memory/memory-flush-contract.js +16 -0
  32. package/dist/lib/agent/memory/session-store-schema.d.ts +20 -0
  33. package/dist/lib/agent/memory/session-store-schema.js +41 -0
  34. package/dist/lib/agent/presets.d.ts +89 -1
  35. package/dist/lib/agent/presets.js +53 -5
  36. package/dist/lib/agent/tools/_shared.d.ts +7 -15
  37. package/dist/lib/agent/tools/_shared.js +20 -21
  38. package/dist/lib/agent/tools/composite.d.ts +25 -22
  39. package/dist/lib/agent/tools/composite.js +108 -109
  40. package/dist/lib/agent/tools/evolution-tools.d.ts +145 -0
  41. package/dist/lib/agent/tools/evolution-tools.js +161 -0
  42. package/dist/lib/agent/tools/index.d.ts +163 -92
  43. package/dist/lib/agent/tools/index.js +9 -1
  44. package/dist/lib/agent/tools/lifecycle.d.ts +7 -1
  45. package/dist/lib/agent/tools/lifecycle.js +59 -75
  46. package/dist/lib/cli/AiScanService.js +1 -1
  47. package/dist/lib/cli/KnowledgeSyncService.d.ts +5 -1
  48. package/dist/lib/cli/KnowledgeSyncService.js +6 -3
  49. package/dist/lib/core/AstAnalyzer.d.ts +1 -0
  50. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.d.ts → domain/dimension/DimensionCopy.d.ts} +2 -2
  51. package/dist/lib/{service/bootstrap/DimensionCopyRegistry.js → domain/dimension/DimensionCopy.js} +22 -72
  52. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +54 -0
  53. package/dist/lib/domain/dimension/DimensionRegistry.js +620 -0
  54. package/dist/lib/domain/dimension/DimensionSop.d.ts +55 -0
  55. package/dist/lib/domain/dimension/DimensionSop.js +1604 -0
  56. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +61 -0
  57. package/dist/lib/domain/dimension/UnifiedDimension.js +53 -0
  58. package/dist/lib/domain/dimension/index.d.ts +10 -0
  59. package/dist/lib/domain/dimension/index.js +9 -0
  60. package/dist/lib/domain/knowledge/FieldSpec.d.ts +1 -1
  61. package/dist/lib/domain/knowledge/FieldSpec.js +29 -16
  62. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +33 -111
  63. package/dist/lib/domain/knowledge/KnowledgeEntry.js +27 -6
  64. package/dist/lib/domain/knowledge/KnowledgeRepository.d.ts +1 -0
  65. package/dist/lib/domain/knowledge/KnowledgeRepository.js +3 -0
  66. package/dist/lib/domain/knowledge/Lifecycle.js +1 -1
  67. package/dist/lib/domain/knowledge/StyleGuide.d.ts +1 -1
  68. package/dist/lib/domain/knowledge/StyleGuide.js +1 -1
  69. package/dist/lib/domain/knowledge/UnifiedValidator.js +15 -0
  70. package/dist/lib/domain/knowledge/values/Stats.d.ts +1 -1
  71. package/dist/lib/domain/knowledge/values/Stats.js +2 -2
  72. package/dist/lib/external/mcp/McpServer.js +4 -0
  73. package/dist/lib/external/mcp/handlers/TargetClassifier.d.ts +1 -1
  74. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.d.ts +8 -16
  75. package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +10 -10
  76. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.d.ts +7 -0
  77. package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +20 -0
  78. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +52 -132
  79. package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +204 -17
  80. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.d.ts +11 -75
  81. package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.js +40 -191
  82. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.d.ts +13 -78
  83. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +30 -52
  84. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.d.ts +0 -1
  85. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
  86. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +172 -161
  87. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
  88. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.d.ts +46 -0
  89. package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.js +58 -0
  90. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.d.ts +25 -0
  91. package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.js +47 -0
  92. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +50 -12
  93. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +30 -10
  94. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-text.js +1 -1
  95. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.d.ts +24 -0
  96. package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.js +14 -0
  97. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.d.ts +14 -0
  98. package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.js +48 -0
  99. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.d.ts +21 -0
  100. package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.js +45 -0
  101. package/dist/lib/external/mcp/handlers/bootstrap/shared/skill-generator.d.ts +1 -1
  102. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.d.ts +27 -0
  103. package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.js +44 -0
  104. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +14 -10
  105. package/dist/lib/external/mcp/handlers/bootstrap-external.js +39 -51
  106. package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
  107. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +115 -82
  108. package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
  109. package/dist/lib/external/mcp/handlers/consolidated.js +115 -162
  110. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +69 -1
  111. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
  112. package/dist/lib/external/mcp/handlers/evolve-external.js +226 -0
  113. package/dist/lib/external/mcp/handlers/knowledge.js +26 -2
  114. package/dist/lib/external/mcp/handlers/rescan-external.d.ts +76 -0
  115. package/dist/lib/external/mcp/handlers/rescan-external.js +335 -0
  116. package/dist/lib/external/mcp/handlers/rescan-internal.d.ts +120 -0
  117. package/dist/lib/external/mcp/handlers/rescan-internal.js +359 -0
  118. package/dist/lib/external/mcp/handlers/search.d.ts +6 -5
  119. package/dist/lib/external/mcp/handlers/search.js +6 -5
  120. package/dist/lib/external/mcp/handlers/types.d.ts +2 -1
  121. package/dist/lib/external/mcp/handlers/wiki-external.js +2 -2
  122. package/dist/lib/external/mcp/tools.d.ts +8 -18
  123. package/dist/lib/external/mcp/tools.js +60 -3
  124. package/dist/lib/http/routes/knowledge.js +122 -1
  125. package/dist/lib/http/routes/modules.js +25 -3
  126. package/dist/lib/http/routes/panorama.js +16 -4
  127. package/dist/lib/infrastructure/cache/CacheCoordinator.d.ts +41 -0
  128. package/dist/lib/infrastructure/cache/CacheCoordinator.js +105 -0
  129. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.d.ts +7 -0
  130. package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.js +28 -0
  131. package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +1 -1
  132. package/dist/lib/injection/ServiceContainer.js +55 -0
  133. package/dist/lib/injection/ServiceMap.d.ts +8 -1
  134. package/dist/lib/injection/modules/InfraModule.js +4 -1
  135. package/dist/lib/injection/modules/KnowledgeModule.js +38 -1
  136. package/dist/lib/repository/evolution/ProposalRepository.d.ts +99 -0
  137. package/dist/lib/repository/evolution/ProposalRepository.js +255 -0
  138. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +4 -0
  139. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +16 -1
  140. package/dist/lib/service/bootstrap/BootstrapEventEmitter.d.ts +3 -2
  141. package/dist/lib/service/bootstrap/BootstrapEventEmitter.js +1 -1
  142. package/dist/lib/service/bootstrap/DeliveryVerifier.d.ts +51 -0
  143. package/dist/lib/service/bootstrap/DeliveryVerifier.js +163 -0
  144. package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +22 -4
  145. package/dist/lib/service/bootstrap/UiStartupTasks.js +73 -5
  146. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +54 -0
  147. package/dist/lib/service/bootstrap/bootstrap-event-types.js +10 -0
  148. package/dist/lib/service/cleanup/CleanupService.d.ts +85 -0
  149. package/dist/lib/service/cleanup/CleanupService.js +324 -0
  150. package/dist/lib/service/delivery/AgentInstructionsGenerator.js +39 -43
  151. package/dist/lib/service/delivery/FileProtection.d.ts +20 -0
  152. package/dist/lib/service/delivery/FileProtection.js +54 -0
  153. package/dist/lib/service/delivery/SkillsSyncer.js +16 -21
  154. package/dist/lib/service/evolution/ContentPatcher.d.ts +44 -0
  155. package/dist/lib/service/evolution/ContentPatcher.js +310 -0
  156. package/dist/lib/service/evolution/DecayDetector.d.ts +4 -3
  157. package/dist/lib/service/evolution/DecayDetector.js +97 -22
  158. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -2
  159. package/dist/lib/service/evolution/KnowledgeMetabolism.js +29 -2
  160. package/dist/lib/service/evolution/ProposalExecutor.d.ts +66 -0
  161. package/dist/lib/service/evolution/ProposalExecutor.js +424 -0
  162. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +64 -0
  163. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +458 -0
  164. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +89 -0
  165. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +492 -0
  166. package/dist/lib/service/evolution/StagingManager.js +5 -3
  167. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +44 -0
  168. package/dist/lib/service/evolution/createSupersedeProposal.js +81 -0
  169. package/dist/lib/service/guard/ComplianceReporter.d.ts +4 -0
  170. package/dist/lib/service/guard/ComplianceReporter.js +51 -0
  171. package/dist/lib/service/guard/GuardCheckEngine.js +5 -4
  172. package/dist/lib/service/guard/GuardCrossFileChecks.js +2 -0
  173. package/dist/lib/service/guard/ReverseGuard.d.ts +1 -1
  174. package/dist/lib/service/guard/ReverseGuard.js +32 -2
  175. package/dist/lib/service/knowledge/ConfidenceRouter.js +1 -1
  176. package/dist/lib/service/knowledge/KnowledgeService.d.ts +11 -1
  177. package/dist/lib/service/knowledge/KnowledgeService.js +44 -4
  178. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
  179. package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
  180. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +2 -0
  181. package/dist/lib/service/knowledge/SourceRefReconciler.js +48 -0
  182. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +3 -2
  183. package/dist/lib/service/panorama/DimensionAnalyzer.js +15 -140
  184. package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
  185. package/dist/lib/service/search/SearchEngine.d.ts +11 -10
  186. package/dist/lib/service/search/SearchEngine.js +38 -36
  187. package/dist/lib/service/search/SearchTypes.d.ts +14 -8
  188. package/dist/lib/service/search/SearchTypes.js +1 -1
  189. package/dist/lib/service/search/tokenizer.d.ts +1 -1
  190. package/dist/lib/service/search/tokenizer.js +2 -2
  191. package/dist/lib/shared/schemas/common.d.ts +4 -4
  192. package/dist/lib/shared/schemas/http-requests.d.ts +12 -1
  193. package/dist/lib/shared/schemas/http-requests.js +8 -0
  194. package/dist/lib/shared/schemas/mcp-tools.d.ts +33 -2
  195. package/dist/lib/shared/schemas/mcp-tools.js +42 -0
  196. package/dist/lib/types/evolution.d.ts +135 -0
  197. package/dist/lib/types/evolution.js +6 -0
  198. package/dist/lib/types/graph-shared.d.ts +25 -0
  199. package/dist/lib/types/graph-shared.js +7 -0
  200. package/dist/lib/types/knowledge-wire.d.ts +131 -0
  201. package/dist/lib/types/knowledge-wire.js +7 -0
  202. package/dist/lib/types/project-snapshot-builder.d.ts +19 -0
  203. package/dist/lib/types/project-snapshot-builder.js +189 -0
  204. package/dist/lib/types/project-snapshot.d.ts +399 -0
  205. package/dist/lib/types/project-snapshot.js +17 -0
  206. package/dist/lib/types/search-wire.d.ts +46 -0
  207. package/dist/lib/types/search-wire.js +7 -0
  208. package/dist/lib/types/snapshot-views.d.ts +58 -0
  209. package/dist/lib/types/snapshot-views.js +103 -0
  210. package/package.json +1 -1
  211. package/skills/autosnippet-recipes/SKILL.md +1 -1
  212. package/templates/instructions/agent-static.md +2 -0
  213. package/templates/instructions/conventions.md +3 -1
  214. package/templates/recipes-setup/README.md +2 -2
  215. package/dashboard/dist/assets/icons-BJ2mUBi8.js +0 -1
  216. package/dashboard/dist/assets/index-B659K9t5.js +0 -128
  217. package/dashboard/dist/assets/index-NCm40PMD.css +0 -1
  218. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.d.ts +0 -169
  219. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +0 -727
  220. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.d.ts +0 -370
  221. package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +0 -821
@@ -192,10 +192,10 @@ export async function consolidatedSkill(ctx, args) {
192
192
  * 统一提交管线:单条与批量走同一代码路径。
193
193
  *
194
194
  * 流程:
195
- * 1. 解析 items[] → 限流
196
- * 2. 严格校验所有条目(UnifiedValidator)→ valid[] + rejected[]
197
- * 3. 融合分析(ConsolidationAdvisor.analyzeBatch)→ submittable[] + blocked[]
198
- * 4. 提交 submittable → enrich + service.create()
195
+ * 1. 限流
196
+ * 2. V3 字段增强(MCP 特有预处理)
197
+ * 3. RecipeProductionGateway.create() 统一管道
198
+ * 4. Bootstrap session 追踪
199
199
  * 5. 返回统一结果
200
200
  *
201
201
  * 设计原则:
@@ -205,8 +205,7 @@ export async function consolidatedSkill(ctx, args) {
205
205
  * - 单条/批量完全一致的校验与融合逻辑
206
206
  */
207
207
  export async function enhancedSubmitKnowledge(ctx, args) {
208
- const { submitKnowledge } = await import('./knowledge.js');
209
- const { UnifiedValidator } = await import('#domain/knowledge/UnifiedValidator.js');
208
+ const { RecipeProductionGateway } = await import('#service/knowledge/RecipeProductionGateway.js');
210
209
  const items = args.items;
211
210
  if (!items || !Array.isArray(items) || items.length === 0) {
212
211
  return envelope({
@@ -220,6 +219,7 @@ export async function enhancedSubmitKnowledge(ctx, args) {
220
219
  const source = args.source || 'mcp';
221
220
  const dimensionId = args.dimensionId;
222
221
  const clientId = args.client_id;
222
+ const supersedes = args.supersedes;
223
223
  // ── Step 1: 限流 ──
224
224
  const { checkRecipeSave } = await import('#http/middleware/RateLimiter.js');
225
225
  const { resolveProjectRoot } = await import('#shared/resolveProjectRoot.js');
@@ -233,175 +233,85 @@ export async function enhancedSubmitKnowledge(ctx, args) {
233
233
  meta: { tool: 'autosnippet_submit_knowledge' },
234
234
  });
235
235
  }
236
- // ── Step 2: 严格校验所有条目 ──
237
- const validator = new UnifiedValidator();
238
- const validItems = [];
239
- const rejectedItems = [];
240
- for (let i = 0; i < items.length; i++) {
241
- const item = items[i];
242
- // 合并批次级选项到条目
236
+ // ── Step 2: MCP 特有预处理 ──
237
+ // 注入批次级选项到各条目
238
+ for (const item of items) {
243
239
  if (!item.source) {
244
240
  item.source = source;
245
241
  }
246
242
  if (dimensionId && !item.dimensionId) {
247
243
  item.dimensionId = dimensionId;
248
244
  }
249
- const validation = validator.validate(item, { skipUniqueness: false });
250
- if (validation.pass) {
251
- validItems.push({ index: i, item });
252
- // 记录标题/指纹供后续去重检测
253
- validator.recordSubmission(item.title, item.content?.pattern);
254
- }
255
- else {
256
- rejectedItems.push({
257
- index: i,
258
- title: item.title || '(untitled)',
259
- errors: validation.errors,
260
- warnings: validation.warnings,
261
- });
262
- // 记录拒绝到 BootstrapSession tracker
263
- _trackRejection(ctx, item, dimensionId);
264
- // 仍然记录标题/指纹防止后续条目重复
265
- validator.recordSubmission(item.title, item.content?.pattern);
245
+ }
246
+ // 获取 bootstrapSession 已提交标题用于跨维度去重
247
+ let existingTitles;
248
+ try {
249
+ const sessionManager = ctx.container.get('bootstrapSessionManager');
250
+ const bsSession = sessionManager?.getSession?.();
251
+ if (bsSession?.submissionTracker?.getAllSubmittedTitles) {
252
+ existingTitles = bsSession.submissionTracker.getAllSubmittedTitles();
266
253
  }
267
254
  }
268
- // 全部被拒绝
269
- if (validItems.length === 0) {
270
- const allMissing = [...new Set(rejectedItems.flatMap((it) => it.errors))];
271
- return envelope({
272
- success: false,
273
- errorCode: 'INCOMPLETE_SUBMISSION',
274
- message: `全部 ${items.length} 条知识条目被拒绝。请在单次调用中补齐所有字段后重新提交。`,
275
- data: {
276
- rejectedItems,
277
- requiredFields: getRequiredFieldsDescription(),
278
- commonErrors: allMissing,
279
- },
280
- meta: { tool: 'autosnippet_submit_knowledge' },
281
- });
255
+ catch {
256
+ /* best effort */
282
257
  }
283
- // ── Step 3: 融合分析(统一对所有有效条目运行) ──
284
- const submittableItems = [];
285
- const blockedItems = [];
286
- if (skipConsolidation) {
287
- submittableItems.push(...validItems);
288
- }
289
- else {
290
- const advisor = ctx.container.get('consolidationAdvisor');
291
- if (!advisor || typeof advisor.analyzeBatch !== 'function') {
292
- // DI 未注册时降级放行
293
- submittableItems.push(...validItems);
294
- }
295
- else {
296
- try {
297
- const candidates = validItems.map((v) => ({
298
- title: v.item.title || '',
299
- description: v.item.description || '',
300
- doClause: v.item.doClause,
301
- dontClause: v.item.dontClause,
302
- coreCode: v.item.coreCode,
303
- category: v.item.category,
304
- trigger: v.item.trigger,
305
- whenClause: v.item.whenClause,
306
- kind: v.item.kind,
307
- content: v.item.content,
308
- }));
309
- const batchAdvice = advisor.analyzeBatch(candidates);
310
- for (const { index: adviceIdx, advice } of batchAdvice.items) {
311
- const validEntry = validItems[adviceIdx];
312
- if (advice.action === 'create') {
313
- submittableItems.push(validEntry);
314
- }
315
- else {
316
- blockedItems.push({
317
- index: validEntry.index,
318
- title: validEntry.item.title || '(untitled)',
319
- consolidation: advice,
320
- });
321
- }
322
- }
323
- // 将批次内重叠信息附加到 blockedItems
324
- if (batchAdvice.internalOverlaps.length > 0) {
325
- for (const overlap of batchAdvice.internalOverlaps) {
326
- const entryB = validItems[overlap.indexB];
327
- // 如果 B 已经被放行,降级为 blocked(批次内碎片化警告)
328
- const alreadyBlocked = blockedItems.some((b) => b.index === entryB.index);
329
- if (!alreadyBlocked) {
330
- const entryA = validItems[overlap.indexA];
331
- blockedItems.push({
332
- index: entryB.index,
333
- title: entryB.item.title || '(untitled)',
334
- consolidation: {
335
- action: 'merge',
336
- reason: `与同批次候选「${entryA.item.title || ''}」高度重叠(${(overlap.similarity * 100).toFixed(0)}%),建议合并后再提交。`,
337
- internalOverlap: true,
338
- overlapWith: {
339
- index: entryA.index,
340
- title: entryA.item.title,
341
- similarity: overlap.similarity,
342
- },
343
- },
344
- });
345
- // 从 submittable 中移除
346
- const subIdx = submittableItems.findIndex((s) => s.index === entryB.index);
347
- if (subIdx >= 0) {
348
- submittableItems.splice(subIdx, 1);
349
- }
350
- }
351
- }
352
- }
353
- }
354
- catch {
355
- // 分析失败时静默降级放行
356
- submittableItems.push(...validItems.filter((v) => !submittableItems.some((s) => s.index === v.index)));
357
- }
358
- }
258
+ // ── Step 3: 委托 RecipeProductionGateway 统一管道 ──
259
+ const knowledgeService = ctx.container.get('knowledgeService');
260
+ let consolidationAdvisor = null;
261
+ try {
262
+ consolidationAdvisor = ctx.container.get('consolidationAdvisor');
359
263
  }
360
- // ── Step 4: 提交所有通过的条目 ──
361
- let successCount = 0;
362
- const successIds = [];
363
- const submitErrors = [];
364
- for (const { index, item } of submittableItems) {
365
- try {
366
- const result = await submitKnowledge(ctx, {
367
- ...item,
368
- source: item.source || source,
369
- client_id: clientId,
370
- });
371
- if (result?.success && result.data?.id) {
372
- successCount++;
373
- const recipeId = result.data.id;
374
- successIds.push(recipeId);
375
- _trackSubmission(ctx, item, dimensionId, recipeId);
376
- }
377
- else {
378
- submitErrors.push({
379
- index,
380
- title: item.title || '(untitled)',
381
- error: result?.message || 'unknown error',
382
- });
383
- }
384
- }
385
- catch (err) {
386
- submitErrors.push({
387
- index,
388
- title: item.title || '(untitled)',
389
- error: err instanceof Error ? err.message : String(err),
390
- });
391
- }
264
+ catch {
265
+ /* not registered */
266
+ }
267
+ let proposalRepository = null;
268
+ try {
269
+ proposalRepository = ctx.container.get('proposalRepository');
270
+ }
271
+ catch {
272
+ /* not registered */
273
+ }
274
+ const gateway = new RecipeProductionGateway({
275
+ knowledgeService,
276
+ projectRoot,
277
+ consolidationAdvisor: consolidationAdvisor ?? null,
278
+ proposalRepository: proposalRepository ?? null,
279
+ });
280
+ const gatewayResult = await gateway.create({
281
+ source: 'mcp-external',
282
+ items: items,
283
+ options: {
284
+ skipSimilarityCheck: true,
285
+ skipConsolidation,
286
+ supersedes,
287
+ existingTitles,
288
+ userId: 'mcp',
289
+ },
290
+ });
291
+ // ── Step 4: Bootstrap session 追踪 ──
292
+ for (const created of gatewayResult.created) {
293
+ _trackSubmission(ctx, items.find((it) => it.title === created.title) || {}, dimensionId, created.id);
294
+ }
295
+ for (const rej of gatewayResult.rejected) {
296
+ const item = items[rej.index] || {};
297
+ _trackRejection(ctx, item, dimensionId);
392
298
  }
393
299
  // ── Step 5: 构建统一响应 ──
300
+ const successCount = gatewayResult.created.length;
394
301
  const data = {
395
302
  count: successCount,
396
303
  total: items.length,
397
304
  };
398
- if (successIds.length > 0) {
399
- data.ids = successIds;
400
- }
401
- if (submitErrors.length > 0) {
402
- data.errors = submitErrors;
305
+ if (gatewayResult.created.length > 0) {
306
+ data.ids = gatewayResult.created.map((c) => c.id);
403
307
  }
404
- if (rejectedItems.length > 0) {
308
+ if (gatewayResult.rejected.length > 0) {
309
+ const rejectedItems = gatewayResult.rejected.map((r) => ({
310
+ index: r.index,
311
+ title: r.title,
312
+ errors: r.errors,
313
+ warnings: r.warnings,
314
+ }));
405
315
  const allMissing = [...new Set(rejectedItems.flatMap((it) => it.errors))];
406
316
  data.rejectedItems = rejectedItems;
407
317
  data.rejectedSummary = {
@@ -410,13 +320,56 @@ export async function enhancedSubmitKnowledge(ctx, args) {
410
320
  message: `${rejectedItems.length}/${items.length} 条知识条目因校验未通过被拒绝。`,
411
321
  };
412
322
  }
413
- if (blockedItems.length > 0) {
414
- data.blockedItems = blockedItems;
323
+ if (gatewayResult.blocked.length > 0) {
324
+ data.blockedItems = gatewayResult.blocked;
415
325
  data.blockedSummary = {
416
- blockedCount: blockedItems.length,
417
- message: `${blockedItems.length} 条因融合分析被阻塞(与已有 Recipe 重叠或实质性不足)。设 skipConsolidation: true 可跳过。`,
326
+ blockedCount: gatewayResult.blocked.length,
327
+ message: `${gatewayResult.blocked.length} 条因融合分析被阻塞(与已有 Recipe 重叠或实质性不足)。设 skipConsolidation: true 可跳过。`,
328
+ };
329
+ }
330
+ const createdProposals = [];
331
+ for (const m of gatewayResult.merged) {
332
+ createdProposals.push({
333
+ proposalId: m.proposalId,
334
+ type: m.type,
335
+ targetRecipe: { id: m.targetRecipeId, title: m.targetTitle },
336
+ status: m.status,
337
+ expiresAt: m.expiresAt,
338
+ message: m.message,
339
+ });
340
+ }
341
+ if (gatewayResult.supersedeProposal) {
342
+ createdProposals.push({
343
+ proposalId: gatewayResult.supersedeProposal.proposalId,
344
+ type: 'supersede',
345
+ targetRecipe: { id: supersedes, title: supersedes },
346
+ status: 'observing',
347
+ expiresAt: 0,
348
+ message: `已创建替代提案。`,
349
+ });
350
+ }
351
+ if (createdProposals.length > 0) {
352
+ data.proposals = createdProposals;
353
+ data.proposalSummary = {
354
+ proposalCount: createdProposals.length,
355
+ message: `${createdProposals.length} 条已创建进化提案,系统将在观察窗口到期后自动执行。无需额外操作。`,
418
356
  };
419
357
  }
358
+ // 全部拒绝 → 特殊错误响应
359
+ if (successCount === 0 && gatewayResult.rejected.length === items.length) {
360
+ const allMissing = [...new Set(gatewayResult.rejected.flatMap((it) => it.errors))];
361
+ return envelope({
362
+ success: false,
363
+ errorCode: 'INCOMPLETE_SUBMISSION',
364
+ message: `全部 ${items.length} 条知识条目被拒绝。请在单次调用中补齐所有字段后重新提交。`,
365
+ data: {
366
+ rejectedItems: data.rejectedItems,
367
+ requiredFields: getRequiredFieldsDescription(),
368
+ commonErrors: allMissing,
369
+ },
370
+ meta: { tool: 'autosnippet_submit_knowledge' },
371
+ });
372
+ }
420
373
  const allOk = successCount === items.length;
421
374
  return envelope({
422
375
  success: successCount > 0,
@@ -298,8 +298,9 @@ export async function dimensionComplete(ctx, args) {
298
298
  emitter.emitAllComplete(session.id, progress.total, 'external-agent');
299
299
  }
300
300
  // ═══════════════════════════════════════════════════════════
301
- // 6.5 Bootstrap 完成后,自动触发 Delivery / Wiki / SemanticMemory (R4/R5/R6)
301
+ // 6.5 Bootstrap 完成后,自动触发 Delivery / Panorama / Wiki / SemanticMemory (R4/R4.5/R5/R6)
302
302
  // ═══════════════════════════════════════════════════════════
303
+ let deliveryVerification = null;
303
304
  if (isComplete) {
304
305
  // R4: 自动触发 Cursor Delivery
305
306
  try {
@@ -318,6 +319,44 @@ export async function dimensionComplete(ctx, args) {
318
319
  catch (e) {
319
320
  logger.warn(`[DimensionComplete] Auto CursorDelivery failed (non-blocking): ${e instanceof Error ? e.message : String(e)}`);
320
321
  }
322
+ // R4+: DeliveryVerifier — 交付完整性检查
323
+ try {
324
+ const { DeliveryVerifier } = await import('#service/bootstrap/DeliveryVerifier.js');
325
+ const { resolveProjectRoot } = await import('#shared/resolveProjectRoot.js');
326
+ const projectRoot = resolveProjectRoot(ctx.container);
327
+ const verifier = new DeliveryVerifier(projectRoot);
328
+ const verification = verifier.verify();
329
+ if (!verification.allPassed) {
330
+ logger.warn('[DimensionComplete] Delivery verification incomplete', {
331
+ failures: verification.failures,
332
+ });
333
+ }
334
+ else {
335
+ logger.info('[DimensionComplete] Delivery verification passed — all channels OK');
336
+ }
337
+ // 附加到响应中的 completionExtras
338
+ deliveryVerification = verification;
339
+ }
340
+ catch (e) {
341
+ logger.warn(`[DimensionComplete] DeliveryVerifier failed (non-blocking): ${e instanceof Error ? e.message : String(e)}`);
342
+ }
343
+ // R4.5: Panorama 数据刷新(冷启动完成后知识库已填充,需重新计算全景)
344
+ try {
345
+ const { getServiceContainer: getPanoramaContainer } = await import('#inject/ServiceContainer.js');
346
+ const panoramaContainer = getPanoramaContainer();
347
+ const panoramaService = panoramaContainer.services.panoramaService
348
+ ? panoramaContainer.get('panoramaService')
349
+ : null;
350
+ if (panoramaService &&
351
+ typeof panoramaService.rescan === 'function') {
352
+ await panoramaService.rescan();
353
+ const overview = panoramaService.getOverview();
354
+ logger.info(`[DimensionComplete] Panorama refreshed — ${overview.moduleCount} modules, ${overview.gapCount} gaps`);
355
+ }
356
+ }
357
+ catch (e) {
358
+ logger.warn(`[DimensionComplete] Panorama refresh failed (non-blocking): ${e instanceof Error ? e.message : String(e)}`);
359
+ }
321
360
  // R5: 自动触发 Wiki 生成 (fire-and-forget)
322
361
  setImmediate(async () => {
323
362
  try {
@@ -392,6 +431,31 @@ export async function dimensionComplete(ctx, args) {
392
431
  }
393
432
  // Wiki 生成提示(冷启动完成时)
394
433
  const nextActions = isComplete ? BOOTSTRAP_COMPLETE_ACTIONS : undefined;
434
+ // §9: 子包覆盖校验 — 检查 referencedFiles 是否覆盖了关键本地子包
435
+ let subpackageCoverageWarning;
436
+ try {
437
+ const snapshotCache = session.getSnapshotCache?.();
438
+ const localPkgs = snapshotCache?.localPackageModules;
439
+ if (localPkgs && localPkgs.length > 0 && referencedFiles.length > 0) {
440
+ const uncoveredPkgs = [];
441
+ for (const pkg of localPkgs) {
442
+ const pkgPrefix = pkg.packageName.replace(/\/$/, '');
443
+ const covered = referencedFiles.some((f) => f.includes(pkgPrefix) || f.includes(pkg.name));
444
+ if (!covered) {
445
+ uncoveredPkgs.push(pkg.name);
446
+ }
447
+ }
448
+ if (uncoveredPkgs.length > 0) {
449
+ subpackageCoverageWarning =
450
+ `本维度未覆盖以下本地子包: ${uncoveredPkgs.join(', ')}。` +
451
+ `建议在分析中纳入这些模块的源码,以确保知识库完整性。`;
452
+ logger.info(`[DimensionComplete] Subpackage coverage gap for "${dimensionId}": ${uncoveredPkgs.join(', ')}`);
453
+ }
454
+ }
455
+ }
456
+ catch {
457
+ /* best effort */
458
+ }
395
459
  // v2: 为下游维度构建结构化提示 (基于累积证据)
396
460
  let evidenceHints;
397
461
  if (!isComplete &&
@@ -450,6 +514,10 @@ export async function dimensionComplete(ctx, args) {
450
514
  qualityFeedback,
451
515
  // v2: 跨维度证据 (供后续维度利用)
452
516
  evidenceHints,
517
+ // v3: 子包覆盖校验警告
518
+ subpackageCoverageWarning,
519
+ // v3.1: 交付完整性验证 (仅 bootstrap 完成时)
520
+ deliveryVerification: isComplete ? deliveryVerification : undefined,
453
521
  nextActions,
454
522
  },
455
523
  meta: {
@@ -0,0 +1,54 @@
1
+ /**
2
+ * MCP Handler — autosnippet_evolve (批量 Recipe 进化决策)
3
+ *
4
+ * 双入口工具:
5
+ * - Rescan 模式: 每个维度内先 evolve 再 gap-fill,与内部 Agent Pipeline 一致
6
+ * - 独立模式: 用户通过提示词触发,验证已有 Recipe 的有效性
7
+ *
8
+ * 三种决策委托给 evolution-tools.ts 中已有的 handler 实现:
9
+ * - propose_evolution → ProposalRepository.create (观察窗口)
10
+ * - confirm_deprecation → RecipeLifecycleSupervisor.transition → deprecated (优先) / KnowledgeService.deprecate (回退)
11
+ * - skip → 不变更状态,skip(still_valid) 刷新 stats.lastVerifiedAt
12
+ *
13
+ * @module handlers/evolve-external
14
+ */
15
+ import type { ServiceContainer } from '#inject/ServiceContainer.js';
16
+ import type { EvolveInput } from '#shared/schemas/mcp-tools.js';
17
+ /** MCP handler context */
18
+ interface McpContext {
19
+ container: ServiceContainer;
20
+ logger: {
21
+ info(msg: string, meta?: Record<string, unknown>): void;
22
+ warn(msg: string, meta?: Record<string, unknown>): void;
23
+ };
24
+ startedAt?: number;
25
+ [key: string]: unknown;
26
+ }
27
+ interface EvolveResult {
28
+ processed: number;
29
+ proposed: number;
30
+ deprecated: number;
31
+ skipped: number;
32
+ refreshed: number;
33
+ quotaChange: {
34
+ freed: number;
35
+ occupied: number;
36
+ };
37
+ errors: Array<{
38
+ recipeId: string;
39
+ error: string;
40
+ }>;
41
+ }
42
+ export declare function evolveExternal(ctx: McpContext, args: EvolveInput): Promise<{
43
+ success: boolean;
44
+ errorCode: string | null;
45
+ message: string;
46
+ data: EvolveResult | null;
47
+ meta: {
48
+ source?: string | undefined;
49
+ responseTimeMs?: number | undefined;
50
+ version: string;
51
+ tool?: string | undefined;
52
+ };
53
+ }>;
54
+ export {};