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,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
+ }
@@ -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
  }
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module BM25Scorer
8
8
  */
9
- import type { BM25Document, BM25SearchResult, Scorer } from './SearchTypes.js';
9
+ import type { BM25Document, Scorer } from './SearchTypes.js';
10
10
  /** BM25 评分器 */
11
11
  export declare class BM25Scorer implements Scorer {
12
12
  _idIndex: Map<string, number>;
@@ -31,7 +31,7 @@ export declare class BM25Scorer implements Scorer {
31
31
  /** 压缩 documents 数组,清除 tombstone 空洞 */
32
32
  _compact(): void;
33
33
  /** 查询文档,返回按 BM25 分数排序的结果 */
34
- search(query: string, limit?: number): BM25SearchResult[];
34
+ search(query: string, limit?: number): import("./SearchTypes.js").ScorerResult[];
35
35
  /** 清空索引 */
36
36
  clear(): void;
37
37
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * SearchEngine - 统一搜索引擎
3
3
  *
4
- * 三级搜索策略: keyword → BM25 ranking → semantic(可选)
4
+ * 三级搜索策略: keyword → FieldWeighted ranking → semantic(可选)
5
5
  * 从 V1 SearchServiceV2 迁移,适配 V2 架构
6
6
  */
7
7
  import Logger from '../../infrastructure/logging/Logger.js';
@@ -10,7 +10,7 @@ import { MultiSignalRanker } from './MultiSignalRanker.js';
10
10
  import type { DbRow, RankingContext, Scorer, SearchAiProvider, SearchCrossEncoder, SearchDb, SearchEngineOptions, SearchHybridRetriever, SearchOptions, SearchResponse, SearchResultItem, SearchVectorService, SearchVectorStore } from './SearchTypes.js';
11
11
  export { BM25Scorer } from './BM25Scorer.js';
12
12
  export { FieldWeightedScorer } from './FieldWeightedScorer.js';
13
- export type { BM25DocMeta, BM25SearchResult, DbRow, RankingContext, RrfHit, Scorer, SearchAiProvider, SearchCrossEncoder, SearchDb, SearchEngineOptions, SearchHybridRetriever, SearchOptions, SearchResponse, SearchResultItem, SearchVectorService, SearchVectorStore, SlimSearchResult, VectorHit, } from './SearchTypes.js';
13
+ export type { BM25DocMeta, DbRow, DocMeta, RankingContext, RrfHit, Scorer, ScorerResult, SearchAiProvider, SearchCrossEncoder, SearchDb, SearchEngineOptions, SearchHybridRetriever, SearchOptions, SearchResponse, SearchResultItem, SearchVectorService, SearchVectorStore, SlimSearchResult, VectorHit, } from './SearchTypes.js';
14
14
  export { groupByKind, slimSearchResult } from './SearchTypes.js';
15
15
  export { tokenize } from './tokenizer.js';
16
16
  /**
@@ -97,18 +97,18 @@ export declare class SearchEngine {
97
97
  /**
98
98
  * 关键词搜索 - 直接 SQL LIKE
99
99
  * 返回包含 kind 字段的完整结果,使用 ESCAPE 防止通配符注入
100
- * 当 SQL LIKE 无结果时,降级到 BM25 搜索以提升自然语言查询的召回率
100
+ * 当 SQL LIKE 无结果时,降级到 FieldWeighted 搜索以提升自然语言查询的召回率
101
101
  */
102
102
  _keywordSearch(query: string, type: string, limit: number): SearchResultItem[];
103
103
  /**
104
- * BM25 排序搜索
104
+ * 加权字段搜索(FieldWeightedScorer)
105
105
  * 增加 Title/Trigger 精确匹配 bonus — 当 query 出现在标题/触发词中时
106
- * 给予额外 BM25 分数加成,确保精确匹配的条目排名靠前
106
+ * 给予额外分数加成,确保精确匹配的条目排名靠前
107
107
  */
108
- _bm25Search(query: string, type: string, limit: number): SearchResultItem[];
108
+ _scorerSearch(query: string, type: string, limit: number): SearchResultItem[];
109
109
  /**
110
110
  * 语义搜索 - 需要 AI Provider 的 embed 功能
111
- * 降级到 BM25 如果 AI 不可用
111
+ * 不可用时降级到 FieldWeighted 搜索
112
112
  * @returns >}
113
113
  */
114
114
  _semanticSearch(query: string, type: string, limit: number): Promise<{
@@ -117,7 +117,7 @@ export declare class SearchEngine {
117
117
  }>;
118
118
  /**
119
119
  * 补充详细字段(content / description / trigger / delivery 字段)— 批量 IN 查询
120
- * 用于向量搜索结果与 BM25 结果的一致性
120
+ * 用于向量搜索结果与 FieldWeighted 结果的一致性
121
121
  */
122
122
  _supplementDetails(items: SearchResultItem[]): void;
123
123
  /**
@@ -138,9 +138,10 @@ export declare class SearchEngine {
138
138
  /**
139
139
  * 从 DB 行构建索引文本
140
140
  *
141
- * 使用 BM25F 思想:高价值字段(title, trigger)重复出现以提升 TF 权重
141
+ * 高价值字段(title, trigger)通过重复出现提升 TF 权重
142
142
  * — title ×3, trigger ×2, description ×1.5(通过重复 token 实现)
143
- * 这确保标题匹配的文档获得显著更高的 BM25 分数
143
+ * 这确保标题匹配的文档获得显著更高的分数
144
+ * 注:此逻辑主要服务于 BM25Scorer,FieldWeightedScorer 内部已有字段权重机制
144
145
  */
145
146
  _buildDocText(r: DbRow): string;
146
147
  /**