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
@@ -0,0 +1,384 @@
1
+ /**
2
+ * RecipeProductionGateway — 统一 Recipe 生产入口
3
+ *
4
+ * 所有 Recipe 创建(Agent Tool / MCP / IDE Agent / Batch Import)
5
+ * 通过此 Gateway 的统一管道,保证前置校验一致:
6
+ *
7
+ * 1. Schema Validation (UnifiedValidator)
8
+ * 2. Similarity Check — 去重检测(可选跳过)
9
+ * 3. Consolidation Scan — 融合/重组建议(可选)
10
+ * 4. KnowledgeService.create() — 包含 ConfidenceRouter → staging / pending
11
+ * 5. Quality Scoring — 质量评分
12
+ * 6. Supersede Proposal — 创建替代提案
13
+ * 7. Audit — 统一审计
14
+ *
15
+ * @see docs/copilot/recipe-lifecycle-management.md §6
16
+ */
17
+ import { UnifiedValidator } from '#domain/knowledge/UnifiedValidator.js';
18
+ /* ═══════════════════ Gateway ═══════════════════ */
19
+ export class RecipeProductionGateway {
20
+ #knowledgeService;
21
+ #projectRoot;
22
+ #logger;
23
+ #consolidationAdvisor;
24
+ #proposalRepo;
25
+ #findSimilarRecipes;
26
+ constructor(deps) {
27
+ this.#knowledgeService = deps.knowledgeService;
28
+ this.#projectRoot = deps.projectRoot;
29
+ this.#logger = deps.logger;
30
+ this.#consolidationAdvisor = deps.consolidationAdvisor ?? null;
31
+ this.#proposalRepo = deps.proposalRepository ?? null;
32
+ this.#findSimilarRecipes = deps.findSimilarRecipes ?? null;
33
+ }
34
+ /**
35
+ * 统一创建入口
36
+ *
37
+ * Pipeline:
38
+ * 1. Schema Validation (UnifiedValidator)
39
+ * 2. Similarity Check (除非 skipSimilarityCheck)
40
+ * 3. Consolidation Scan (除非 skipConsolidation)
41
+ * 4. KnowledgeService.create() — ConfidenceRouter → staging / pending
42
+ * 5. Quality Scoring
43
+ * 6. Supersede Proposal 创建 (if supersedes)
44
+ */
45
+ async create(request) {
46
+ const { source, items, options = {} } = request;
47
+ const userId = options.userId || this.#sourceToUserId(source);
48
+ const result = {
49
+ created: [],
50
+ rejected: [],
51
+ merged: [],
52
+ blocked: [],
53
+ duplicates: [],
54
+ supersedeProposal: null,
55
+ };
56
+ if (items.length === 0) {
57
+ return result;
58
+ }
59
+ // ── Step 1: Schema Validation ──
60
+ const validator = new UnifiedValidator({
61
+ existingTitles: options.existingTitles,
62
+ existingFingerprints: options.existingFingerprints,
63
+ });
64
+ const validItems = [];
65
+ for (let i = 0; i < items.length; i++) {
66
+ const item = items[i];
67
+ const validation = validator.validate(item, {
68
+ systemInjectedFields: options.systemInjectedFields,
69
+ skipUniqueness: options.skipUniqueness,
70
+ });
71
+ if (!validation.pass) {
72
+ result.rejected.push({
73
+ index: i,
74
+ title: item.title || '(untitled)',
75
+ reason: 'validation_failed',
76
+ errors: validation.errors,
77
+ warnings: validation.warnings,
78
+ });
79
+ this.#logger?.info(`[Gateway] ✗ validation rejected item ${i}: ${validation.errors.join('; ')}`);
80
+ }
81
+ else {
82
+ validItems.push({ index: i, item });
83
+ // 记录已提交标题/指纹以防批量内重复
84
+ validator.recordSubmission(item.title, item.content?.pattern);
85
+ }
86
+ }
87
+ // ── Step 2: Similarity Check ──
88
+ let afterSimilarityItems = validItems;
89
+ if (!options.skipSimilarityCheck && this.#findSimilarRecipes) {
90
+ const threshold = options.similarityThreshold ?? 0.7;
91
+ afterSimilarityItems = [];
92
+ for (const entry of validItems) {
93
+ const { item, index } = entry;
94
+ const contentObj = item.content && typeof item.content === 'object' ? item.content : { markdown: '' };
95
+ const cand = {
96
+ title: item.title || '',
97
+ summary: item.description || '',
98
+ code: contentObj.markdown || contentObj.pattern || '',
99
+ };
100
+ const similar = this.#findSimilarRecipes(this.#projectRoot, cand, {
101
+ threshold: 0.5,
102
+ topK: 5,
103
+ });
104
+ const hasDuplicate = similar.some((s) => s.similarity >= threshold);
105
+ if (hasDuplicate) {
106
+ result.duplicates.push({
107
+ index,
108
+ title: item.title || '(untitled)',
109
+ similarTo: similar,
110
+ });
111
+ this.#logger?.info(`[Gateway] ✗ duplicate blocked item ${index}: similarity ${similar[0]?.similarity}`);
112
+ }
113
+ else {
114
+ afterSimilarityItems.push(entry);
115
+ }
116
+ }
117
+ }
118
+ // ── Step 3: Consolidation Scan ──
119
+ let submittableItems = afterSimilarityItems;
120
+ if (!options.skipConsolidation &&
121
+ this.#consolidationAdvisor &&
122
+ afterSimilarityItems.length > 0) {
123
+ submittableItems = [];
124
+ try {
125
+ const candidates = afterSimilarityItems.map((e) => ({
126
+ title: e.item.title || '',
127
+ category: e.item.category || e.item._category || '',
128
+ ...e.item,
129
+ }));
130
+ const batchAdvice = this.#consolidationAdvisor.analyzeBatch(candidates);
131
+ for (let ai = 0; ai < batchAdvice.items.length; ai++) {
132
+ const { advice } = batchAdvice.items[ai];
133
+ const validEntry = afterSimilarityItems[ai];
134
+ if (!validEntry) {
135
+ continue;
136
+ }
137
+ if (advice.action === 'create') {
138
+ submittableItems.push(validEntry);
139
+ }
140
+ else if (this.#proposalRepo) {
141
+ const proposal = this.#createProposalFromAdvice(advice, validEntry.item);
142
+ if (proposal) {
143
+ result.merged.push({
144
+ index: validEntry.index,
145
+ proposalId: proposal.proposalId,
146
+ type: proposal.type,
147
+ targetRecipeId: proposal.targetRecipeId,
148
+ targetTitle: proposal.targetTitle,
149
+ status: proposal.status,
150
+ expiresAt: proposal.expiresAt,
151
+ message: proposal.message,
152
+ });
153
+ }
154
+ else {
155
+ // Proposal 创建失败 → blocked
156
+ result.blocked.push({
157
+ index: validEntry.index,
158
+ title: validEntry.item.title || '(untitled)',
159
+ consolidation: advice,
160
+ });
161
+ }
162
+ }
163
+ else {
164
+ // 无 ProposalRepository → blocked
165
+ result.blocked.push({
166
+ index: validEntry.index,
167
+ title: validEntry.item.title || '(untitled)',
168
+ consolidation: advice,
169
+ });
170
+ }
171
+ }
172
+ }
173
+ catch (err) {
174
+ this.#logger?.warn(`[Gateway] ConsolidationAdvisor error, falling back to direct submit: ${err instanceof Error ? err.message : String(err)}`);
175
+ submittableItems = afterSimilarityItems;
176
+ }
177
+ }
178
+ // ── Step 4: Create via KnowledgeService ──
179
+ const createdIds = [];
180
+ for (const { item } of submittableItems) {
181
+ try {
182
+ const data = this.#prepareCreateData(item, source, userId);
183
+ const saved = await this.#knowledgeService.create(data, { userId });
184
+ result.created.push({
185
+ id: saved.id,
186
+ title: saved.title,
187
+ lifecycle: saved.lifecycle,
188
+ raw: saved,
189
+ });
190
+ createdIds.push(saved.id);
191
+ // ── Step 5: Quality Scoring (best effort) ──
192
+ try {
193
+ await this.#knowledgeService.updateQuality(saved.id, { userId });
194
+ }
195
+ catch {
196
+ /* best effort — 不阻塞创建流程 */
197
+ }
198
+ }
199
+ catch (err) {
200
+ result.rejected.push({
201
+ index: items.indexOf(item),
202
+ title: item.title || '(untitled)',
203
+ reason: 'create_failed',
204
+ errors: [err instanceof Error ? err.message : String(err)],
205
+ warnings: [],
206
+ });
207
+ this.#logger?.warn(`[Gateway] ✗ create failed for "${item.title}": ${err instanceof Error ? err.message : String(err)}`);
208
+ }
209
+ }
210
+ // ── Step 6: Supersede Proposal ──
211
+ if (options.supersedes && createdIds.length > 0) {
212
+ try {
213
+ // 直接使用 ProposalRepository(Gateway 不依赖 ServiceContainer)
214
+ if (this.#proposalRepo) {
215
+ const proposal = this.#proposalRepo.create({
216
+ type: 'supersede',
217
+ targetRecipeId: options.supersedes,
218
+ relatedRecipeIds: createdIds,
219
+ confidence: 0.9,
220
+ source: source === 'mcp-external' ? 'ide-agent' : 'ide-agent',
221
+ description: `Supersede proposal: ${createdIds.length} new recipe(s) replace ${options.supersedes}`,
222
+ evidence: [{ snapshotAt: Date.now(), newRecipeIds: createdIds }],
223
+ });
224
+ if (proposal) {
225
+ result.supersedeProposal = { proposalId: proposal.id };
226
+ }
227
+ }
228
+ }
229
+ catch (err) {
230
+ this.#logger?.warn(`[Gateway] Supersede proposal creation failed: ${err instanceof Error ? err.message : String(err)}`);
231
+ }
232
+ }
233
+ this.#logger?.info(`[Gateway] create complete: ${result.created.length} created, ${result.rejected.length} rejected, ${result.merged.length} merged, ${result.duplicates.length} duplicates | source=${source}`);
234
+ return result;
235
+ }
236
+ /* ═══════════════════ Private ═══════════════════ */
237
+ #sourceToUserId(source) {
238
+ switch (source) {
239
+ case 'agent-tool':
240
+ return 'agent';
241
+ case 'mcp-external':
242
+ return 'mcp';
243
+ case 'ide-agent':
244
+ return 'ide-agent';
245
+ case 'batch-import':
246
+ return 'batch-import';
247
+ }
248
+ }
249
+ #prepareCreateData(item, source, _userId) {
250
+ const contentObj = item.content && typeof item.content === 'object'
251
+ ? item.content
252
+ : { markdown: '', pattern: '' };
253
+ const reasoning = item.reasoning || {
254
+ whyStandard: '',
255
+ sources: ['agent'],
256
+ confidence: 0.7,
257
+ };
258
+ if (Array.isArray(reasoning.sources) && reasoning.sources.length === 0) {
259
+ reasoning.sources = ['agent'];
260
+ }
261
+ return {
262
+ language: item.language || '',
263
+ category: item.category || item._category || 'general',
264
+ knowledgeType: item.knowledgeType || 'code-pattern',
265
+ source: item.source || this.#sourceLabel(source),
266
+ title: item.title || '',
267
+ description: item.description || '',
268
+ tags: item.tags || [],
269
+ trigger: item.trigger || '',
270
+ kind: item.kind || 'pattern',
271
+ topicHint: item.topicHint || '',
272
+ whenClause: item.whenClause || '',
273
+ doClause: item.doClause || '',
274
+ dontClause: item.dontClause || '',
275
+ coreCode: item.coreCode || contentObj.pattern || '',
276
+ sourceRefs: item.sourceRefs || [],
277
+ content: contentObj,
278
+ reasoning,
279
+ headers: item.headers || [],
280
+ usageGuide: item.usageGuide || '',
281
+ scope: item.scope || '',
282
+ complexity: item.complexity || '',
283
+ sourceFile: '',
284
+ agentNotes: item.agentNotes || null,
285
+ aiInsight: reasoning.whyStandard || item.description || null,
286
+ };
287
+ }
288
+ #sourceLabel(source) {
289
+ switch (source) {
290
+ case 'agent-tool':
291
+ return 'agent';
292
+ case 'mcp-external':
293
+ return 'mcp';
294
+ case 'ide-agent':
295
+ return 'ide-agent';
296
+ case 'batch-import':
297
+ return 'batch-import';
298
+ }
299
+ }
300
+ #createProposalFromAdvice(advice, item) {
301
+ if (!this.#proposalRepo) {
302
+ return null;
303
+ }
304
+ const evidence = [
305
+ {
306
+ snapshotAt: Date.now(),
307
+ candidateTitle: item.title,
308
+ candidateCategory: item.category,
309
+ analysisReason: advice.reason,
310
+ mergeDirection: advice.mergeDirection,
311
+ },
312
+ ];
313
+ if (advice.action === 'merge' && advice.targetRecipe) {
314
+ const proposal = this.#proposalRepo.create({
315
+ type: 'merge',
316
+ targetRecipeId: advice.targetRecipe.id,
317
+ confidence: advice.confidence,
318
+ source: 'ide-agent',
319
+ description: advice.reason,
320
+ evidence,
321
+ });
322
+ if (!proposal) {
323
+ return null;
324
+ }
325
+ return {
326
+ proposalId: proposal.id,
327
+ type: 'merge',
328
+ targetRecipeId: advice.targetRecipe.id,
329
+ targetTitle: advice.targetRecipe.title,
330
+ status: proposal.status,
331
+ expiresAt: proposal.expiresAt,
332
+ message: `已为「${advice.targetRecipe.title}」创建融合提案,${proposal.status === 'observing' ? '观察窗口 72h 后自动执行' : '等待开发者确认'}。`,
333
+ };
334
+ }
335
+ if (advice.action === 'reorganize' && advice.reorganizeTargets?.length) {
336
+ const target = advice.reorganizeTargets[0];
337
+ const proposal = this.#proposalRepo.create({
338
+ type: 'reorganize',
339
+ targetRecipeId: target.id,
340
+ relatedRecipeIds: advice.reorganizeTargets.slice(1).map((t) => t.id),
341
+ confidence: advice.confidence,
342
+ source: 'ide-agent',
343
+ description: advice.reason,
344
+ evidence,
345
+ });
346
+ if (!proposal) {
347
+ return null;
348
+ }
349
+ return {
350
+ proposalId: proposal.id,
351
+ type: 'reorganize',
352
+ targetRecipeId: target.id,
353
+ targetTitle: target.title,
354
+ status: proposal.status,
355
+ expiresAt: proposal.expiresAt,
356
+ message: `已为 ${advice.reorganizeTargets.length} 条 Recipe 创建重组提案,需开发者在 Dashboard 确认。`,
357
+ };
358
+ }
359
+ if (advice.action === 'insufficient' && advice.coveredBy?.length) {
360
+ const target = advice.coveredBy[0];
361
+ const proposal = this.#proposalRepo.create({
362
+ type: 'enhance',
363
+ targetRecipeId: target.id,
364
+ confidence: advice.confidence,
365
+ source: 'ide-agent',
366
+ description: advice.reason,
367
+ evidence,
368
+ });
369
+ if (!proposal) {
370
+ return null;
371
+ }
372
+ return {
373
+ proposalId: proposal.id,
374
+ type: 'enhance',
375
+ targetRecipeId: target.id,
376
+ targetTitle: target.title,
377
+ status: proposal.status,
378
+ expiresAt: proposal.expiresAt,
379
+ message: `候选独立价值不足,已创建增强提案建议补充到「${target.title}」。`,
380
+ };
381
+ }
382
+ return null;
383
+ }
384
+ }
@@ -9,6 +9,7 @@
9
9
  * renamed — 文件已移动到 new_path,等待修复
10
10
  * stale — 路径失效,无法自动修复
11
11
  */
12
+ import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
12
13
  interface DatabaseLike {
13
14
  prepare(sql: string): {
14
15
  all(...params: unknown[]): Record<string, unknown>[];
@@ -46,6 +47,7 @@ export declare class SourceRefReconciler {
46
47
  #private;
47
48
  constructor(projectRoot: string, db: DatabaseLike, options?: {
48
49
  ttlMs?: number;
50
+ signalBus?: SignalBus;
49
51
  });
50
52
  /**
51
53
  * 从 knowledge_entries.reasoning 填充 recipe_source_refs 表。
@@ -21,11 +21,13 @@ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
21
21
  export class SourceRefReconciler {
22
22
  #projectRoot;
23
23
  #db;
24
+ #signalBus;
24
25
  #logger = Logger.getInstance();
25
26
  #ttlMs;
26
27
  constructor(projectRoot, db, options) {
27
28
  this.#projectRoot = projectRoot;
28
29
  this.#db = db;
30
+ this.#signalBus = options?.signalBus ?? null;
29
31
  this.#ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;
30
32
  }
31
33
  /**
@@ -122,8 +124,44 @@ export class SourceRefReconciler {
122
124
  skipped: report.skipped,
123
125
  recipesProcessed: report.recipesProcessed,
124
126
  });
127
+ // 通过 SignalBus 发射信号 — 让 Governance 子系统感知 sourceRef 健康状况
128
+ if (this.#signalBus && report.stale > 0) {
129
+ this.#emitStaleSignals();
130
+ }
125
131
  return report;
126
132
  }
133
+ /**
134
+ * 为每个有 stale sourceRef 的 Recipe 发射 quality 信号。
135
+ * KnowledgeMetabolism 订阅 quality → 触发完整治理周期。
136
+ */
137
+ #emitStaleSignals() {
138
+ if (!this.#signalBus) {
139
+ return;
140
+ }
141
+ try {
142
+ const staleRecipes = this.#db
143
+ .prepare(`SELECT recipe_id, COUNT(*) AS stale_count,
144
+ (SELECT COUNT(*) FROM recipe_source_refs r2 WHERE r2.recipe_id = r.recipe_id) AS total_count
145
+ FROM recipe_source_refs r
146
+ WHERE status = 'stale'
147
+ GROUP BY recipe_id`)
148
+ .all();
149
+ for (const row of staleRecipes) {
150
+ const staleRatio = row.stale_count / row.total_count;
151
+ this.#signalBus.send('quality', 'SourceRefReconciler', staleRatio, {
152
+ target: row.recipe_id,
153
+ metadata: {
154
+ reason: 'source_ref_stale',
155
+ staleCount: row.stale_count,
156
+ totalRefs: row.total_count,
157
+ },
158
+ });
159
+ }
160
+ }
161
+ catch {
162
+ // 信号发射失败不影响主流程
163
+ }
164
+ }
127
165
  /**
128
166
  * 对 stale 条目尝试 git rename 修复。
129
167
  * 使用 execFile() 安全执行 git log(防止命令注入)。
@@ -160,6 +198,16 @@ export class SourceRefReconciler {
160
198
  renamed: report.renamed,
161
199
  stillStale: report.stillStale,
162
200
  });
201
+ // 修复成功 → 发射正向 quality 信号(value≈0 表示健康方向)
202
+ if (this.#signalBus) {
203
+ this.#signalBus.send('quality', 'SourceRefReconciler', 0.1, {
204
+ metadata: {
205
+ reason: 'source_ref_repaired',
206
+ renamed: report.renamed,
207
+ stillStale: report.stillStale,
208
+ },
209
+ });
210
+ }
163
211
  }
164
212
  return report;
165
213
  }
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * DimensionAnalyzer — 多维度知识健康分析
3
3
  *
4
+ * **v2: 从统一维度注册表 (DimensionRegistry) 派生维度**
5
+ *
4
6
  * 灵感来源:
5
7
  * - ISO/IEC 25010 质量模型 (8 大特性: 可靠性、安全性、可维护性…)
6
8
  * - ThoughtWorks Tech Radar (Adopt/Trial/Assess/Hold 四环)
7
9
  * - 雷达图/蛛网图可视化模型
8
10
  *
9
- * 核心思路: 不再按「模块 × 文件数」衡量覆盖,
10
- * 而是按「知识维度」衡量项目在各工程方向上的规范成熟度。
11
+ * 核心思路: 按「知识维度」衡量项目在各工程方向上的规范成熟度。
11
12
  * 某维度 Recipe 为 0 → 该方向完全空白,标示为 gap。
12
13
  *
13
14
  * @module DimensionAnalyzer
@@ -1,135 +1,26 @@
1
1
  /**
2
2
  * DimensionAnalyzer — 多维度知识健康分析
3
3
  *
4
+ * **v2: 从统一维度注册表 (DimensionRegistry) 派生维度**
5
+ *
4
6
  * 灵感来源:
5
7
  * - ISO/IEC 25010 质量模型 (8 大特性: 可靠性、安全性、可维护性…)
6
8
  * - ThoughtWorks Tech Radar (Adopt/Trial/Assess/Hold 四环)
7
9
  * - 雷达图/蛛网图可视化模型
8
10
  *
9
- * 核心思路: 不再按「模块 × 文件数」衡量覆盖,
10
- * 而是按「知识维度」衡量项目在各工程方向上的规范成熟度。
11
+ * 核心思路: 按「知识维度」衡量项目在各工程方向上的规范成熟度。
11
12
  * 某维度 Recipe 为 0 → 该方向完全空白,标示为 gap。
12
13
  *
13
14
  * @module DimensionAnalyzer
14
15
  */
16
+ import { classifyRecipeToDimension, DIMENSION_REGISTRY } from '#domain/dimension/index.js';
17
+ /* ═══ 维度定义 — 从统一注册表派生 ═══════════════════════ */
15
18
  /**
16
- * 标准维度列表
17
- *
18
- * 覆盖主流软件工程关切方向,任何项目都应有所涉猎。
19
- * `topics` 与 `categories` 匹配 knowledge_entries 的字段。
19
+ * Panorama 使用全量维度注册表进行健康评估。
20
+ * 所有维度(含语言/框架条件维度)都参与评估 —
21
+ * 若该语言未激活但有 Recipe → 仍计入(只是不生成 gap 建议)。
20
22
  */
21
- const DIMENSION_DEFS = [
22
- {
23
- id: 'architecture',
24
- name: '架构设计',
25
- description: '模块结构、分层策略、依赖管理、设计模式',
26
- topics: ['architecture', 'scaffold', 'workflow'],
27
- categories: ['architecture', 'project-profile'],
28
- weight: 1.0,
29
- suggestedTopics: ['module-boundary', 'dependency-rule', 'layer-strategy'],
30
- relatedRoles: ['core', 'foundation', 'app'],
31
- },
32
- {
33
- id: 'coding-standards',
34
- name: '编码规范',
35
- description: '命名约定、代码风格、文档注释、import 顺序',
36
- topics: ['conventions'],
37
- categories: ['code-standard'],
38
- weight: 0.8,
39
- suggestedTopics: ['naming-convention', 'code-style', 'documentation'],
40
- relatedRoles: [],
41
- },
42
- {
43
- id: 'error-handling',
44
- name: '错误处理',
45
- description: '异常模式、错误恢复、输入验证、防御性编程',
46
- topics: ['error-handling', 'constraints'],
47
- categories: [],
48
- weight: 1.0,
49
- suggestedTopics: ['exception-pattern', 'error-recovery', 'input-validation'],
50
- relatedRoles: ['service', 'networking', 'core'],
51
- },
52
- {
53
- id: 'concurrency',
54
- name: '并发与线程',
55
- description: '线程安全、异步模式、竞态条件防护、锁策略',
56
- topics: ['concurrency', 'async'],
57
- categories: [],
58
- weight: 0.9,
59
- suggestedTopics: ['thread-safety', 'async-pattern', 'race-condition'],
60
- relatedRoles: ['service', 'networking', 'storage'],
61
- },
62
- {
63
- id: 'data-management',
64
- name: '数据管理',
65
- description: '持久化、缓存、序列化、数据流向完整性',
66
- topics: ['data', 'data-flow', 'memory'],
67
- categories: ['event-and-data-flow'],
68
- weight: 0.8,
69
- suggestedTopics: ['persistence', 'caching', 'serialization', 'data-integrity'],
70
- relatedRoles: ['storage', 'model'],
71
- },
72
- {
73
- id: 'networking',
74
- name: '网络通信',
75
- description: 'API 契约、请求模式、重试策略、实时通信',
76
- topics: ['networking', 'real-time'],
77
- categories: [],
78
- weight: 0.7,
79
- suggestedTopics: ['api-contract', 'retry-strategy', 'request-pattern'],
80
- relatedRoles: ['networking'],
81
- },
82
- {
83
- id: 'ui-patterns',
84
- name: '界面模式',
85
- description: 'UI 组件规范、生命周期、导航、数据绑定',
86
- topics: ['ui', 'binding', 'pagination'],
87
- categories: [],
88
- weight: 0.7,
89
- suggestedTopics: ['component-pattern', 'lifecycle', 'navigation'],
90
- relatedRoles: ['ui', 'feature'],
91
- },
92
- {
93
- id: 'testing',
94
- name: '测试策略',
95
- description: '测试模式、Mock 策略、CI/CD 流程',
96
- topics: ['testing', 'test'],
97
- categories: [],
98
- weight: 0.9,
99
- suggestedTopics: ['unit-test', 'mock-strategy', 'ci-cd'],
100
- relatedRoles: [],
101
- },
102
- {
103
- id: 'security',
104
- name: '安全',
105
- description: '认证授权、输入校验、加密、权限控制',
106
- topics: ['security', 'auth'],
107
- categories: [],
108
- weight: 1.0,
109
- suggestedTopics: ['authentication', 'authorization', 'encryption'],
110
- relatedRoles: ['networking', 'service'],
111
- },
112
- {
113
- id: 'performance',
114
- name: '性能优化',
115
- description: '内存管理、懒加载、缓存策略、渲染优化',
116
- topics: ['performance', 'optimization'],
117
- categories: [],
118
- weight: 0.8,
119
- suggestedTopics: ['memory-management', 'lazy-loading', 'rendering'],
120
- relatedRoles: ['ui', 'storage'],
121
- },
122
- {
123
- id: 'observability',
124
- name: '可观测性',
125
- description: '日志规范、事件追踪、监控诊断',
126
- topics: ['logging', 'event', 'monitoring'],
127
- categories: [],
128
- weight: 0.7,
129
- suggestedTopics: ['logging-standard', 'event-tracking', 'diagnostics'],
130
- relatedRoles: ['service', 'core'],
131
- },
132
- ];
23
+ const DIMENSION_DEFS = DIMENSION_REGISTRY;
133
24
  /* ═══ DimensionAnalyzer Class ═════════════════════════════ */
134
25
  export class DimensionAnalyzer {
135
26
  #db;
@@ -213,26 +104,10 @@ export class DimensionAnalyzer {
213
104
  /**
214
105
  * 将 recipe 分类到最匹配的维度
215
106
  *
216
- * 优先级: topicHint 精确匹配 → category 匹配 → null
107
+ * 委托给 DimensionRegistry.classifyRecipeToDimension()
217
108
  */
218
109
  #classifyRecipe(recipe) {
219
- // 1. topicHint 精确匹配
220
- if (recipe.topicHint) {
221
- for (const def of DIMENSION_DEFS) {
222
- if (def.topics.includes(recipe.topicHint)) {
223
- return def.id;
224
- }
225
- }
226
- }
227
- // 2. category 匹配
228
- if (recipe.category) {
229
- for (const def of DIMENSION_DEFS) {
230
- if (def.categories.includes(recipe.category)) {
231
- return def.id;
232
- }
233
- }
234
- }
235
- return null;
110
+ return classifyRecipeToDimension(recipe.topicHint, recipe.category);
236
111
  }
237
112
  /* ─── 维度评分 ─────────────────────────────────── */
238
113
  #scoreDimension(def, recipeCount, titles) {
@@ -268,8 +143,8 @@ export class DimensionAnalyzer {
268
143
  }
269
144
  return {
270
145
  id: def.id,
271
- name: def.name,
272
- description: def.description,
146
+ name: def.label,
147
+ description: def.qualityDescription,
273
148
  recipeCount,
274
149
  score,
275
150
  status,
@@ -305,11 +180,11 @@ export class DimensionAnalyzer {
305
180
  const affectedRoles = def.relatedRoles.filter((r) => moduleRoles.has(r));
306
181
  gaps.push({
307
182
  dimension: def.id,
308
- dimensionName: def.name,
183
+ dimensionName: def.label,
309
184
  recipeCount: dim.recipeCount,
310
185
  status: dim.status,
311
186
  priority,
312
- suggestedTopics: def.suggestedTopics,
187
+ suggestedTopics: [...def.suggestedTopics],
313
188
  affectedRoles,
314
189
  });
315
190
  }