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.
- package/dashboard/dist/assets/icons-D1aVZYFW.js +1 -0
- package/dashboard/dist/assets/index-CxHOu8Hd.css +1 -0
- package/dashboard/dist/assets/index-DDdAOpYT.js +128 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/api-server.js +1 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +136 -9
- package/dist/lib/agent/AgentFactory.d.ts +0 -17
- package/dist/lib/agent/AgentFactory.js +1 -25
- package/dist/lib/agent/capabilities.d.ts +11 -0
- package/dist/lib/agent/capabilities.js +29 -5
- package/dist/lib/agent/context/ExplorationTracker.js +10 -1
- package/dist/lib/agent/context/exploration/ExplorationStrategies.d.ts +2 -0
- package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -2
- package/dist/lib/agent/domain/insight-analyst.d.ts +47 -3
- package/dist/lib/agent/domain/insight-analyst.js +111 -11
- package/dist/lib/agent/domain/insight-evolver.d.ts +69 -0
- package/dist/lib/agent/domain/insight-evolver.js +230 -0
- package/dist/lib/agent/domain/insight-gate.d.ts +42 -0
- package/dist/lib/agent/domain/insight-gate.js +41 -0
- package/dist/lib/agent/domain/insight-producer.d.ts +27 -2
- package/dist/lib/agent/domain/insight-producer.js +60 -5
- package/dist/lib/agent/domain/scan-prompts.js +10 -7
- package/dist/lib/agent/memory/ActiveContext.d.ts +2 -28
- package/dist/lib/agent/memory/MemoryCoordinator.d.ts +2 -2
- package/dist/lib/agent/memory/SessionStore.d.ts +6 -12
- package/dist/lib/agent/memory/SessionStore.js +9 -15
- package/dist/lib/agent/memory/memory-flush-contract.d.ts +49 -0
- package/dist/lib/agent/memory/memory-flush-contract.js +16 -0
- package/dist/lib/agent/memory/session-store-schema.d.ts +20 -0
- package/dist/lib/agent/memory/session-store-schema.js +41 -0
- package/dist/lib/agent/presets.d.ts +89 -1
- package/dist/lib/agent/presets.js +53 -5
- package/dist/lib/agent/tools/_shared.d.ts +7 -15
- package/dist/lib/agent/tools/_shared.js +20 -21
- package/dist/lib/agent/tools/composite.d.ts +25 -22
- package/dist/lib/agent/tools/composite.js +108 -109
- package/dist/lib/agent/tools/evolution-tools.d.ts +145 -0
- package/dist/lib/agent/tools/evolution-tools.js +161 -0
- package/dist/lib/agent/tools/index.d.ts +163 -92
- package/dist/lib/agent/tools/index.js +9 -1
- package/dist/lib/agent/tools/lifecycle.d.ts +7 -1
- package/dist/lib/agent/tools/lifecycle.js +59 -75
- package/dist/lib/cli/AiScanService.js +1 -1
- package/dist/lib/cli/KnowledgeSyncService.js +1 -1
- package/dist/lib/core/AstAnalyzer.d.ts +1 -0
- package/dist/lib/{service/bootstrap/DimensionCopyRegistry.d.ts → domain/dimension/DimensionCopy.d.ts} +2 -2
- package/dist/lib/{service/bootstrap/DimensionCopyRegistry.js → domain/dimension/DimensionCopy.js} +22 -72
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +54 -0
- package/dist/lib/domain/dimension/DimensionRegistry.js +620 -0
- package/dist/lib/domain/dimension/DimensionSop.d.ts +55 -0
- package/dist/lib/domain/dimension/DimensionSop.js +1604 -0
- package/dist/lib/domain/dimension/UnifiedDimension.d.ts +61 -0
- package/dist/lib/domain/dimension/UnifiedDimension.js +53 -0
- package/dist/lib/domain/dimension/index.d.ts +10 -0
- package/dist/lib/domain/dimension/index.js +9 -0
- package/dist/lib/domain/knowledge/FieldSpec.d.ts +1 -1
- package/dist/lib/domain/knowledge/FieldSpec.js +29 -16
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +33 -111
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +27 -6
- package/dist/lib/domain/knowledge/KnowledgeRepository.d.ts +1 -0
- package/dist/lib/domain/knowledge/KnowledgeRepository.js +3 -0
- package/dist/lib/domain/knowledge/Lifecycle.js +1 -1
- package/dist/lib/domain/knowledge/StyleGuide.d.ts +1 -1
- package/dist/lib/domain/knowledge/StyleGuide.js +1 -1
- package/dist/lib/domain/knowledge/UnifiedValidator.js +15 -0
- package/dist/lib/external/mcp/McpServer.js +4 -0
- package/dist/lib/external/mcp/handlers/TargetClassifier.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.d.ts +8 -16
- package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +10 -10
- package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.d.ts +7 -0
- package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +52 -132
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +204 -17
- package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.d.ts +11 -75
- package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.js +40 -191
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.d.ts +13 -78
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +30 -52
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.d.ts +0 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +172 -161
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
- package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.d.ts +46 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.js +58 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.d.ts +25 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.js +47 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +50 -12
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +30 -10
- package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-text.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.d.ts +24 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.js +14 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.d.ts +14 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.js +48 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.d.ts +21 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.js +45 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/skill-generator.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.d.ts +27 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.js +44 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +14 -10
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +39 -51
- package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +115 -82
- package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
- package/dist/lib/external/mcp/handlers/consolidated.js +107 -332
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +69 -1
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +226 -0
- package/dist/lib/external/mcp/handlers/knowledge.js +26 -2
- package/dist/lib/external/mcp/handlers/rescan-external.d.ts +76 -0
- package/dist/lib/external/mcp/handlers/rescan-external.js +335 -0
- package/dist/lib/external/mcp/handlers/rescan-internal.d.ts +120 -0
- package/dist/lib/external/mcp/handlers/rescan-internal.js +359 -0
- package/dist/lib/external/mcp/handlers/search.d.ts +6 -5
- package/dist/lib/external/mcp/handlers/search.js +6 -5
- package/dist/lib/external/mcp/handlers/types.d.ts +2 -1
- package/dist/lib/external/mcp/handlers/wiki-external.js +2 -2
- package/dist/lib/external/mcp/tools.d.ts +8 -18
- package/dist/lib/external/mcp/tools.js +58 -2
- package/dist/lib/http/routes/knowledge.js +122 -1
- package/dist/lib/http/routes/modules.js +25 -3
- package/dist/lib/http/routes/panorama.js +16 -4
- package/dist/lib/infrastructure/cache/CacheCoordinator.d.ts +41 -0
- package/dist/lib/infrastructure/cache/CacheCoordinator.js +105 -0
- package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.d.ts +7 -0
- package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.js +28 -0
- package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +1 -1
- package/dist/lib/injection/ServiceContainer.js +55 -0
- package/dist/lib/injection/ServiceMap.d.ts +8 -1
- package/dist/lib/injection/modules/KnowledgeModule.js +15 -1
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +4 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +16 -1
- package/dist/lib/service/bootstrap/BootstrapEventEmitter.d.ts +3 -2
- package/dist/lib/service/bootstrap/BootstrapEventEmitter.js +1 -1
- package/dist/lib/service/bootstrap/DeliveryVerifier.d.ts +51 -0
- package/dist/lib/service/bootstrap/DeliveryVerifier.js +163 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +5 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +20 -0
- package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +54 -0
- package/dist/lib/service/bootstrap/bootstrap-event-types.js +10 -0
- package/dist/lib/service/cleanup/CleanupService.d.ts +85 -0
- package/dist/lib/service/cleanup/CleanupService.js +324 -0
- package/dist/lib/service/delivery/AgentInstructionsGenerator.js +39 -43
- package/dist/lib/service/delivery/FileProtection.d.ts +20 -0
- package/dist/lib/service/delivery/FileProtection.js +54 -0
- package/dist/lib/service/delivery/SkillsSyncer.js +16 -21
- package/dist/lib/service/evolution/ContentPatcher.d.ts +44 -0
- package/dist/lib/service/evolution/ContentPatcher.js +310 -0
- package/dist/lib/service/evolution/ProposalExecutor.d.ts +4 -0
- package/dist/lib/service/evolution/ProposalExecutor.js +77 -13
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +64 -0
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +458 -0
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +89 -0
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +492 -0
- package/dist/lib/service/evolution/createSupersedeProposal.d.ts +44 -0
- package/dist/lib/service/evolution/createSupersedeProposal.js +81 -0
- package/dist/lib/service/guard/ComplianceReporter.d.ts +4 -0
- package/dist/lib/service/guard/ComplianceReporter.js +51 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +5 -4
- package/dist/lib/service/knowledge/ConfidenceRouter.js +1 -1
- package/dist/lib/service/knowledge/KnowledgeService.d.ts +11 -1
- package/dist/lib/service/knowledge/KnowledgeService.js +44 -4
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +3 -2
- package/dist/lib/service/panorama/DimensionAnalyzer.js +15 -140
- package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
- package/dist/lib/service/search/SearchEngine.d.ts +11 -10
- package/dist/lib/service/search/SearchEngine.js +38 -36
- package/dist/lib/service/search/SearchTypes.d.ts +14 -8
- package/dist/lib/service/search/SearchTypes.js +1 -1
- package/dist/lib/service/search/tokenizer.d.ts +1 -1
- package/dist/lib/service/search/tokenizer.js +2 -2
- package/dist/lib/shared/schemas/common.d.ts +4 -4
- package/dist/lib/shared/schemas/http-requests.d.ts +12 -1
- package/dist/lib/shared/schemas/http-requests.js +8 -0
- package/dist/lib/shared/schemas/mcp-tools.d.ts +32 -2
- package/dist/lib/shared/schemas/mcp-tools.js +38 -0
- package/dist/lib/types/evolution.d.ts +135 -0
- package/dist/lib/types/evolution.js +6 -0
- package/dist/lib/types/graph-shared.d.ts +25 -0
- package/dist/lib/types/graph-shared.js +7 -0
- package/dist/lib/types/knowledge-wire.d.ts +131 -0
- package/dist/lib/types/knowledge-wire.js +7 -0
- package/dist/lib/types/project-snapshot-builder.d.ts +19 -0
- package/dist/lib/types/project-snapshot-builder.js +189 -0
- package/dist/lib/types/project-snapshot.d.ts +399 -0
- package/dist/lib/types/project-snapshot.js +17 -0
- package/dist/lib/types/search-wire.d.ts +46 -0
- package/dist/lib/types/search-wire.js +7 -0
- package/dist/lib/types/snapshot-views.d.ts +58 -0
- package/dist/lib/types/snapshot-views.js +103 -0
- package/package.json +1 -1
- package/skills/autosnippet-recipes/SKILL.md +1 -1
- package/templates/instructions/agent-static.md +2 -0
- package/templates/instructions/conventions.md +3 -1
- package/templates/recipes-setup/README.md +2 -2
- package/dashboard/dist/assets/icons-BJ2mUBi8.js +0 -1
- package/dashboard/dist/assets/index-B659K9t5.js +0 -128
- package/dashboard/dist/assets/index-NCm40PMD.css +0 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.d.ts +0 -169
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +0 -727
- package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.d.ts +0 -370
- 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
|
-
*
|
|
107
|
+
* 委托给 DimensionRegistry.classifyRecipeToDimension()
|
|
217
108
|
*/
|
|
218
109
|
#classifyRecipe(recipe) {
|
|
219
|
-
|
|
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.
|
|
272
|
-
description: def.
|
|
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.
|
|
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,
|
|
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):
|
|
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 →
|
|
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,
|
|
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 无结果时,降级到
|
|
100
|
+
* 当 SQL LIKE 无结果时,降级到 FieldWeighted 搜索以提升自然语言查询的召回率
|
|
101
101
|
*/
|
|
102
102
|
_keywordSearch(query: string, type: string, limit: number): SearchResultItem[];
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
104
|
+
* 加权字段搜索(FieldWeightedScorer)
|
|
105
105
|
* 增加 Title/Trigger 精确匹配 bonus — 当 query 出现在标题/触发词中时
|
|
106
|
-
*
|
|
106
|
+
* 给予额外分数加成,确保精确匹配的条目排名靠前
|
|
107
107
|
*/
|
|
108
|
-
|
|
108
|
+
_scorerSearch(query: string, type: string, limit: number): SearchResultItem[];
|
|
109
109
|
/**
|
|
110
110
|
* 语义搜索 - 需要 AI Provider 的 embed 功能
|
|
111
|
-
*
|
|
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
|
-
* 用于向量搜索结果与
|
|
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
|
-
*
|
|
141
|
+
* 高价值字段(title, trigger)通过重复出现提升 TF 权重
|
|
142
142
|
* — title ×3, trigger ×2, description ×1.5(通过重复 token 实现)
|
|
143
|
-
*
|
|
143
|
+
* 这确保标题匹配的文档获得显著更高的分数
|
|
144
|
+
* 注:此逻辑主要服务于 BM25Scorer,FieldWeightedScorer 内部已有字段权重机制
|
|
144
145
|
*/
|
|
145
146
|
_buildDocText(r: DbRow): string;
|
|
146
147
|
/**
|