autosnippet 3.3.7 → 3.3.8
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/README.md +1 -0
- package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
- package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
- package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +7 -4
- package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
- package/dist/lib/agent/core/LoopContext.d.ts +1 -0
- package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
- package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
- package/dist/lib/agent/memory/ActiveContext.js +0 -2
- package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
- package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
- package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
- package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
- package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
- package/dist/lib/agent/memory/MemoryStore.js +196 -261
- package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
- package/dist/lib/agent/memory/PersistentMemory.js +4 -5
- package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
- package/dist/lib/agent/memory/SessionStore.js +0 -2
- package/dist/lib/agent/tools/ast-graph.js +21 -19
- package/dist/lib/agent/tools/infrastructure.js +3 -2
- package/dist/lib/agent/tools/project-access.d.ts +2 -2
- package/dist/lib/agent/tools/project-access.js +5 -4
- package/dist/lib/bootstrap.js +2 -1
- package/dist/lib/cli/AiScanService.js +4 -17
- package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
- package/dist/lib/cli/KnowledgeSyncService.js +23 -51
- package/dist/lib/core/ast/ProjectGraph.js +5 -27
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +0 -2
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
- package/dist/lib/domain/dimension/DimensionSop.js +44 -33
- package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
- package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
- package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
- package/dist/lib/domain/knowledge/index.d.ts +2 -1
- package/dist/lib/domain/knowledge/index.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +33 -16
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +7 -3
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +13 -16
- package/dist/lib/external/mcp/handlers/guard.js +15 -24
- package/dist/lib/external/mcp/handlers/panorama.js +9 -9
- package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
- package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
- package/dist/lib/external/mcp/handlers/search.js +3 -1
- package/dist/lib/external/mcp/handlers/skill.js +4 -4
- package/dist/lib/external/mcp/handlers/structure.js +8 -12
- package/dist/lib/external/mcp/handlers/system.js +10 -34
- package/dist/lib/http/routes/ai.js +11 -13
- package/dist/lib/http/routes/guardReport.js +3 -5
- package/dist/lib/http/routes/panorama.js +12 -12
- package/dist/lib/http/routes/recipes.js +59 -8
- package/dist/lib/http/routes/remote.js +3 -13
- package/dist/lib/http/routes/search.js +11 -8
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
- package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
- package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
- package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
- package/dist/lib/injection/ServiceContainer.js +7 -4
- package/dist/lib/injection/ServiceMap.d.ts +20 -0
- package/dist/lib/injection/modules/AppModule.js +2 -1
- package/dist/lib/injection/modules/GuardModule.js +5 -5
- package/dist/lib/injection/modules/InfraModule.js +60 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
- package/dist/lib/injection/modules/PanoramaModule.js +16 -10
- package/dist/lib/injection/modules/VectorModule.js +3 -0
- package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
- package/dist/lib/repository/audit/AuditRepository.js +272 -0
- package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
- package/dist/lib/repository/base/RepositoryBase.js +32 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
- package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
- package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
- package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
- package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
- package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
- package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
- package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
- package/dist/lib/repository/memory/MemoryRepository.js +260 -0
- package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
- package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
- package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
- package/dist/lib/repository/session/SessionRepository.js +110 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
- package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
- package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
- package/dist/lib/service/cleanup/CleanupService.js +8 -4
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
- package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
- package/dist/lib/service/evolution/ContentPatcher.js +48 -19
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
- package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
- package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
- package/dist/lib/service/evolution/DecayDetector.js +63 -57
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
- package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
- package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
- package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
- package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
- package/dist/lib/service/evolution/StagingManager.js +37 -95
- package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
- package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
- package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
- package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
- package/dist/lib/service/guard/ReverseGuard.js +21 -31
- package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
- package/dist/lib/service/guard/ViolationsStore.js +75 -69
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +39 -63
- package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -512
- package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
- package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
- package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
- package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
- package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
- package/dist/lib/service/knowledge/KnowledgeService.js +76 -38
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
- package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +5 -3
- package/dist/lib/service/panorama/CouplingAnalyzer.js +102 -39
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
- package/dist/lib/service/panorama/DimensionAnalyzer.js +72 -25
- package/dist/lib/service/panorama/LayerInferrer.js +1 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +7 -6
- package/dist/lib/service/panorama/ModuleDiscoverer.js +174 -82
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +10 -3
- package/dist/lib/service/panorama/PanoramaAggregator.js +67 -79
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
- package/dist/lib/service/panorama/PanoramaScanner.js +32 -31
- package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
- package/dist/lib/service/panorama/PanoramaService.js +41 -66
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +3 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +8 -5
- package/dist/lib/service/panorama/RoleRefiner.js +52 -283
- package/dist/lib/service/panorama/TechStackProfiler.js +7 -119
- package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
- package/dist/lib/service/quality/QualityScorer.js +157 -83
- package/dist/lib/service/search/SearchEngine.d.ts +1 -0
- package/dist/lib/service/search/SearchEngine.js +32 -37
- package/dist/lib/service/signal/HitRecorder.js +5 -5
- package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
- package/dist/lib/service/skills/SignalCollector.d.ts +5 -8
- package/dist/lib/service/skills/SignalCollector.js +28 -55
- package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
- package/dist/lib/service/skills/SkillAdvisor.js +30 -79
- package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
- package/dist/lib/service/vector/SyncCoordinator.js +25 -3
- package/dist/lib/service/vector/VectorService.d.ts +2 -0
- package/dist/lib/service/vector/VectorService.js +3 -0
- package/dist/lib/service/wiki/WikiGenerator.js +1 -1
- package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
- package/dist/lib/shared/LanguageProfiles.js +939 -0
- package/dist/lib/shared/LanguageService.d.ts +6 -0
- package/dist/lib/shared/LanguageService.js +16 -0
- package/dist/lib/shared/constants.d.ts +19 -19
- package/dist/lib/shared/constants.js +10 -10
- package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
- package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
- package/dist/lib/types/project-snapshot-builder.js +0 -1
- package/dist/lib/types/project-snapshot.d.ts +0 -1
- package/dist/lib/types/project-snapshot.js +0 -1
- package/dist/lib/types/snapshot-views.d.ts +0 -2
- package/dist/lib/types/snapshot-views.js +0 -1
- package/package.json +2 -1
- package/dashboard/dist/assets/icons-FHns2ypa.js +0 -1
- package/dashboard/dist/assets/index-BRJv5Y3r.js +0 -135
- package/dashboard/dist/assets/index-DzoB7kxK.css +0 -1
- package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
- package/dist/lib/repository/base/BaseRepository.js +0 -226
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { and, eq, sql } from 'drizzle-orm';
|
|
1
|
+
import { and, count, desc, eq, gt, inArray, isNotNull, like, ne, or, sql } from 'drizzle-orm';
|
|
2
2
|
import { inferKind, KnowledgeEntry } from '../../domain/knowledge/index.js';
|
|
3
|
+
import { COUNTABLE_LIFECYCLES } from '../../domain/knowledge/Lifecycle.js';
|
|
3
4
|
import { getDrizzle } from '../../infrastructure/database/drizzle/index.js';
|
|
4
5
|
import { knowledgeEntries } from '../../infrastructure/database/drizzle/schema.js';
|
|
5
6
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
6
7
|
import { safeJsonParse, safeJsonStringify, unixNow } from '../../shared/utils/common.js';
|
|
7
|
-
|
|
8
|
+
/** Only allow safe SQL identifier characters */
|
|
9
|
+
const SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
8
10
|
/**
|
|
9
11
|
* KnowledgeRepositoryImpl — 统一知识实体仓储实现 (Drizzle ORM)
|
|
10
12
|
*
|
|
@@ -15,14 +17,62 @@ import { BaseRepository } from '../base/BaseRepository.js';
|
|
|
15
17
|
* - CRUD (create/findById/update/delete/findActiveRules) → drizzle 类型安全 API
|
|
16
18
|
* - 复杂动态查询 (findWithPagination/getStats) → 保留 raw SQL→渐进迁移
|
|
17
19
|
*/
|
|
18
|
-
export class KnowledgeRepositoryImpl
|
|
20
|
+
export class KnowledgeRepositoryImpl {
|
|
21
|
+
/** Raw DB for complex dynamic queries (ORM limitation — used within repository layer) */
|
|
22
|
+
db;
|
|
23
|
+
logger;
|
|
19
24
|
#drizzle;
|
|
25
|
+
/** Lazily-populated column whitelist for SQL-injection prevention */
|
|
26
|
+
#columnWhitelist = null;
|
|
20
27
|
constructor(database, drizzle) {
|
|
21
|
-
|
|
28
|
+
this.db = database.getDb();
|
|
22
29
|
this.logger = Logger.getInstance();
|
|
23
30
|
this.#drizzle = drizzle ?? getDrizzle();
|
|
24
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Validate column name is safe for SQL interpolation (copied from retired BaseRepository).
|
|
34
|
+
* Rejects anything that doesn't match /^[a-zA-Z_]\w*$/ or is not a real column.
|
|
35
|
+
*/
|
|
36
|
+
_assertSafeColumn(key) {
|
|
37
|
+
if (!SAFE_IDENTIFIER_RE.test(key)) {
|
|
38
|
+
throw new Error(`Invalid column name: ${key}`);
|
|
39
|
+
}
|
|
40
|
+
if (!this.#columnWhitelist) {
|
|
41
|
+
try {
|
|
42
|
+
const cols = this.db
|
|
43
|
+
.prepare('PRAGMA table_info(knowledge_entries)')
|
|
44
|
+
.all();
|
|
45
|
+
this.#columnWhitelist = new Set(cols.map((c) => c.name));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
this.#columnWhitelist = new Set();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (this.#columnWhitelist.size > 0 && !this.#columnWhitelist.has(key)) {
|
|
52
|
+
throw new Error(`Unknown column "${key}" for table knowledge_entries`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
25
55
|
/* ═══ CRUD ═══════════════════════════════════════════ */
|
|
56
|
+
/**
|
|
57
|
+
* 按 ID 查找
|
|
58
|
+
* ★ Drizzle 类型安全 SELECT
|
|
59
|
+
*/
|
|
60
|
+
async findById(id) {
|
|
61
|
+
try {
|
|
62
|
+
const row = this.#drizzle
|
|
63
|
+
.select()
|
|
64
|
+
.from(knowledgeEntries)
|
|
65
|
+
.where(eq(knowledgeEntries.id, id))
|
|
66
|
+
.limit(1)
|
|
67
|
+
.get();
|
|
68
|
+
return row ? this._rowToEntity(row) : null;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
72
|
+
this.logger.error('Error finding knowledge entry by id', { id, error: message });
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
26
76
|
/**
|
|
27
77
|
* 创建 KnowledgeEntry
|
|
28
78
|
* ★ Drizzle 类型安全 INSERT — 列名拼写编译期检查
|
|
@@ -116,6 +166,30 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
|
|
|
116
166
|
}
|
|
117
167
|
}
|
|
118
168
|
/* ═══ 查询 ═══════════════════════════════════════════ */
|
|
169
|
+
/**
|
|
170
|
+
* 更新生命周期状态
|
|
171
|
+
* ★ Drizzle 类型安全 UPDATE — 供 RecipeLifecycleSupervisor / ProposalExecutor 使用
|
|
172
|
+
*/
|
|
173
|
+
async updateLifecycle(id, lifecycle) {
|
|
174
|
+
const result = this.#drizzle
|
|
175
|
+
.update(knowledgeEntries)
|
|
176
|
+
.set({ lifecycle, updatedAt: unixNow() })
|
|
177
|
+
.where(eq(knowledgeEntries.id, id))
|
|
178
|
+
.run();
|
|
179
|
+
return result.changes > 0;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 更新 stats JSON 字段
|
|
183
|
+
* ★ Drizzle 类型安全 UPDATE — 供 HitRecorder / RecipeLifecycleSupervisor 使用
|
|
184
|
+
*/
|
|
185
|
+
async updateStats(id, stats) {
|
|
186
|
+
const result = this.#drizzle
|
|
187
|
+
.update(knowledgeEntries)
|
|
188
|
+
.set({ stats: safeJsonStringify(stats), updatedAt: unixNow() })
|
|
189
|
+
.where(eq(knowledgeEntries.id, id))
|
|
190
|
+
.run();
|
|
191
|
+
return result.changes > 0;
|
|
192
|
+
}
|
|
119
193
|
/**
|
|
120
194
|
* 分页查询
|
|
121
195
|
* @override
|
|
@@ -127,8 +201,15 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
|
|
|
127
201
|
const params = [];
|
|
128
202
|
const { _tagLike, _search, lifecycle: lcFilter, ...normalFilters } = filters;
|
|
129
203
|
if (lcFilter) {
|
|
130
|
-
|
|
131
|
-
|
|
204
|
+
if (Array.isArray(lcFilter)) {
|
|
205
|
+
const placeholders = lcFilter.map(() => '?').join(', ');
|
|
206
|
+
conditions.push(`lifecycle IN (${placeholders})`);
|
|
207
|
+
params.push(...lcFilter);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
conditions.push(`lifecycle = ?`);
|
|
211
|
+
params.push(lcFilter);
|
|
212
|
+
}
|
|
132
213
|
}
|
|
133
214
|
for (const [key, value] of Object.entries(normalFilters)) {
|
|
134
215
|
if (value == null) {
|
|
@@ -195,6 +276,123 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
|
|
|
195
276
|
throw error;
|
|
196
277
|
}
|
|
197
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Guard 专用:active 的 rule + boundary-constraint
|
|
281
|
+
* ★ Phase 5b: supply guard.ts _loadRuleRecipes
|
|
282
|
+
*/
|
|
283
|
+
async findActiveGuardRecipes() {
|
|
284
|
+
const rows = this.#drizzle
|
|
285
|
+
.select()
|
|
286
|
+
.from(knowledgeEntries)
|
|
287
|
+
.where(and(eq(knowledgeEntries.lifecycle, 'active'), or(eq(knowledgeEntries.kind, 'rule'), eq(knowledgeEntries.knowledgeType, 'boundary-constraint'))))
|
|
288
|
+
.all();
|
|
289
|
+
return rows
|
|
290
|
+
.map((row) => this._rowToEntity(row))
|
|
291
|
+
.filter(Boolean);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* 按 source 字段查询 ID 列表
|
|
295
|
+
* ★ Phase 5b: supply ai.ts mock cleanup
|
|
296
|
+
*/
|
|
297
|
+
async findIdsBySource(source) {
|
|
298
|
+
const rows = this.#drizzle
|
|
299
|
+
.select({ id: knowledgeEntries.id })
|
|
300
|
+
.from(knowledgeEntries)
|
|
301
|
+
.where(eq(knowledgeEntries.source, source))
|
|
302
|
+
.all();
|
|
303
|
+
return rows.map((r) => r.id);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 统计指定 lifecycle 集合中的条目数量
|
|
307
|
+
* ★ Phase 5b: supply recipes.ts pre-check
|
|
308
|
+
*/
|
|
309
|
+
async countByLifecycles(lifecycles) {
|
|
310
|
+
const rows = this.#drizzle
|
|
311
|
+
.select({ cnt: count() })
|
|
312
|
+
.from(knowledgeEntries)
|
|
313
|
+
.where(inArray(knowledgeEntries.lifecycle, lifecycles))
|
|
314
|
+
.all();
|
|
315
|
+
return Number(rows[0]?.cnt ?? 0);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* 查询指定 lifecycle 集合中的所有条目(不分页)
|
|
319
|
+
* ★ Phase 5c: supply Evolution domain services (ContradictionDetector, RedundancyAnalyzer, etc.)
|
|
320
|
+
*/
|
|
321
|
+
async findAllByLifecycles(lifecycles) {
|
|
322
|
+
const rows = this.#drizzle
|
|
323
|
+
.select()
|
|
324
|
+
.from(knowledgeEntries)
|
|
325
|
+
.where(inArray(knowledgeEntries.lifecycle, lifecycles))
|
|
326
|
+
.all();
|
|
327
|
+
return rows
|
|
328
|
+
.map((row) => this._rowToEntity(row))
|
|
329
|
+
.filter(Boolean);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* 查询指定 lifecycle + category 的条目(带 limit)
|
|
333
|
+
* ★ Phase 5c: supply ConsolidationAdvisor category-filtered query
|
|
334
|
+
*/
|
|
335
|
+
async findAllByLifecyclesAndCategory(lifecycles, category, limit) {
|
|
336
|
+
const rows = this.#drizzle
|
|
337
|
+
.select()
|
|
338
|
+
.from(knowledgeEntries)
|
|
339
|
+
.where(and(inArray(knowledgeEntries.lifecycle, lifecycles), eq(knowledgeEntries.category, category)))
|
|
340
|
+
.limit(limit)
|
|
341
|
+
.all();
|
|
342
|
+
return rows
|
|
343
|
+
.map((row) => this._rowToEntity(row))
|
|
344
|
+
.filter(Boolean);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* 查询指定 lifecycle 中 trigger 匹配前缀且排除指定 category 的条目
|
|
348
|
+
* ★ Phase 5c: supply ConsolidationAdvisor trigger-prefix fallback
|
|
349
|
+
*/
|
|
350
|
+
async findByLifecyclesAndTriggerPrefix(lifecycles, excludeCategory, triggerPrefix, limit) {
|
|
351
|
+
const rows = this.#drizzle
|
|
352
|
+
.select()
|
|
353
|
+
.from(knowledgeEntries)
|
|
354
|
+
.where(and(inArray(knowledgeEntries.lifecycle, lifecycles), ne(knowledgeEntries.category, excludeCategory), like(knowledgeEntries.trigger, `${triggerPrefix}%`)))
|
|
355
|
+
.limit(limit)
|
|
356
|
+
.all();
|
|
357
|
+
return rows
|
|
358
|
+
.map((row) => this._rowToEntity(row))
|
|
359
|
+
.filter(Boolean);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* 按 lifecycle 分组统计全部条目数量
|
|
363
|
+
* ★ Phase 5c: supply RecipeLifecycleSupervisor health summary
|
|
364
|
+
*/
|
|
365
|
+
async countGroupByLifecycle() {
|
|
366
|
+
const rows = this.#drizzle
|
|
367
|
+
.select({
|
|
368
|
+
lifecycle: knowledgeEntries.lifecycle,
|
|
369
|
+
cnt: count(),
|
|
370
|
+
})
|
|
371
|
+
.from(knowledgeEntries)
|
|
372
|
+
.groupBy(knowledgeEntries.lifecycle)
|
|
373
|
+
.all();
|
|
374
|
+
const result = {};
|
|
375
|
+
for (const row of rows) {
|
|
376
|
+
result[row.lifecycle ?? ''] = Number(row.cnt);
|
|
377
|
+
}
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* 反向查找 relations JSON 中包含指定 nodeId 的条目
|
|
382
|
+
* ★ Phase 5b: supply structure.ts relation graph
|
|
383
|
+
*/
|
|
384
|
+
async findByRelationLike(nodeId, excludeId) {
|
|
385
|
+
const rows = this.#drizzle
|
|
386
|
+
.select({
|
|
387
|
+
id: knowledgeEntries.id,
|
|
388
|
+
title: knowledgeEntries.title,
|
|
389
|
+
relations: knowledgeEntries.relations,
|
|
390
|
+
})
|
|
391
|
+
.from(knowledgeEntries)
|
|
392
|
+
.where(and(like(knowledgeEntries.relations, `%${nodeId}%`), ne(knowledgeEntries.id, excludeId)))
|
|
393
|
+
.all();
|
|
394
|
+
return rows.map((r) => ({ id: r.id, title: r.title ?? '', relations: r.relations ?? '{}' }));
|
|
395
|
+
}
|
|
198
396
|
/** 根据语言查询 */
|
|
199
397
|
async findByLanguage(language, pagination = {}) {
|
|
200
398
|
return this.findWithPagination({ language }, pagination);
|
|
@@ -233,6 +431,306 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
|
|
|
233
431
|
throw error;
|
|
234
432
|
}
|
|
235
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* Find all entries with non-empty reasoning (for SourceRefReconciler)
|
|
436
|
+
* ★ Drizzle 类型安全 SELECT — 仅返回 id + reasoning
|
|
437
|
+
*/
|
|
438
|
+
async findAllIdAndReasoning() {
|
|
439
|
+
const rows = this.#drizzle
|
|
440
|
+
.select({
|
|
441
|
+
id: knowledgeEntries.id,
|
|
442
|
+
reasoning: knowledgeEntries.reasoning,
|
|
443
|
+
})
|
|
444
|
+
.from(knowledgeEntries)
|
|
445
|
+
.where(and(sql `${knowledgeEntries.reasoning} IS NOT NULL`, sql `${knowledgeEntries.reasoning} != '{}'`))
|
|
446
|
+
.all();
|
|
447
|
+
return rows
|
|
448
|
+
.filter((r) => r.reasoning != null)
|
|
449
|
+
.map((r) => ({ id: r.id, reasoning: r.reasoning }));
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Find sourceFile and reasoning for a single entry (for SourceRefReconciler.applyRepairs)
|
|
453
|
+
* ★ Drizzle 类型安全 SELECT — 仅返回 sourceFile + reasoning
|
|
454
|
+
*/
|
|
455
|
+
async findSourceFileAndReasoning(id) {
|
|
456
|
+
const row = this.#drizzle
|
|
457
|
+
.select({
|
|
458
|
+
sourceFile: knowledgeEntries.sourceFile,
|
|
459
|
+
reasoning: knowledgeEntries.reasoning,
|
|
460
|
+
})
|
|
461
|
+
.from(knowledgeEntries)
|
|
462
|
+
.where(eq(knowledgeEntries.id, id))
|
|
463
|
+
.limit(1)
|
|
464
|
+
.get();
|
|
465
|
+
if (!row) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
return { sourceFile: row.sourceFile ?? null, reasoning: row.reasoning ?? null };
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Update reasoning JSON field directly (for SourceRefReconciler.applyRepairs)
|
|
472
|
+
* ★ Drizzle 类型安全 UPDATE — 精确更新 reasoning + updatedAt
|
|
473
|
+
*/
|
|
474
|
+
async updateReasoning(id, reasoning, updatedAt) {
|
|
475
|
+
const result = this.#drizzle
|
|
476
|
+
.update(knowledgeEntries)
|
|
477
|
+
.set({ reasoning, updatedAt })
|
|
478
|
+
.where(eq(knowledgeEntries.id, id))
|
|
479
|
+
.run();
|
|
480
|
+
return result.changes > 0;
|
|
481
|
+
}
|
|
482
|
+
/* ─── Panorama 域查询 (Phase 5e) ─── */
|
|
483
|
+
/**
|
|
484
|
+
* 获取活跃 Recipe 的元数据 (title, category, topicHint, kind)
|
|
485
|
+
* 用于 DimensionAnalyzer 维度分类分析
|
|
486
|
+
*/
|
|
487
|
+
async findRecipeMetadata(lifecycles) {
|
|
488
|
+
const rows = this.#drizzle
|
|
489
|
+
.select({
|
|
490
|
+
title: knowledgeEntries.title,
|
|
491
|
+
category: knowledgeEntries.category,
|
|
492
|
+
topicHint: knowledgeEntries.topicHint,
|
|
493
|
+
kind: knowledgeEntries.kind,
|
|
494
|
+
})
|
|
495
|
+
.from(knowledgeEntries)
|
|
496
|
+
.where(inArray(knowledgeEntries.lifecycle, lifecycles))
|
|
497
|
+
.all();
|
|
498
|
+
return rows.map((r) => ({
|
|
499
|
+
title: r.title ?? '',
|
|
500
|
+
category: r.category ?? '',
|
|
501
|
+
topicHint: r.topicHint ?? '',
|
|
502
|
+
kind: r.kind ?? '',
|
|
503
|
+
}));
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* 按模块相关关键词搜索 Recipe (PanoramaService.#findModuleRecipes)
|
|
507
|
+
* @param lifecycles - 活跃生命周期
|
|
508
|
+
* @param moduleName - 模块名
|
|
509
|
+
* @param categories - 角色关联的分类列表
|
|
510
|
+
* @param limit - 结果上限
|
|
511
|
+
*/
|
|
512
|
+
async findModuleRecipes(lifecycles, moduleName, categories, limit = 20) {
|
|
513
|
+
const conditions = [
|
|
514
|
+
or(like(knowledgeEntries.title, `%${moduleName}%`), like(knowledgeEntries.trigger, `%${moduleName}%`), ...categories.map((cat) => eq(knowledgeEntries.category, cat))),
|
|
515
|
+
];
|
|
516
|
+
const rows = this.#drizzle
|
|
517
|
+
.select({
|
|
518
|
+
id: knowledgeEntries.id,
|
|
519
|
+
title: knowledgeEntries.title,
|
|
520
|
+
trigger: knowledgeEntries.trigger,
|
|
521
|
+
kind: knowledgeEntries.kind,
|
|
522
|
+
})
|
|
523
|
+
.from(knowledgeEntries)
|
|
524
|
+
.where(and(inArray(knowledgeEntries.lifecycle, lifecycles), ...conditions))
|
|
525
|
+
.orderBy(knowledgeEntries.lifecycle)
|
|
526
|
+
.limit(limit)
|
|
527
|
+
.all();
|
|
528
|
+
return rows.map((r) => ({
|
|
529
|
+
id: r.id ?? '',
|
|
530
|
+
title: r.title ?? '',
|
|
531
|
+
trigger: r.trigger ?? '',
|
|
532
|
+
kind: r.kind ?? '',
|
|
533
|
+
}));
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* 统计 COUNTABLE_LIFECYCLES 范围内的知识条目数 (PanoramaAggregator.#getProjectRecipeCount)
|
|
537
|
+
*/
|
|
538
|
+
async countByCountableLifecycles() {
|
|
539
|
+
const rows = this.#drizzle
|
|
540
|
+
.select({ cnt: count() })
|
|
541
|
+
.from(knowledgeEntries)
|
|
542
|
+
.where(inArray(knowledgeEntries.lifecycle, COUNTABLE_LIFECYCLES))
|
|
543
|
+
.all();
|
|
544
|
+
return Number(rows[0]?.cnt ?? 0);
|
|
545
|
+
}
|
|
546
|
+
/* ═══ Guard / Skills 用查询 ═══════════════════════════ */
|
|
547
|
+
/**
|
|
548
|
+
* Guard 规则查询 — kind='rule' OR knowledgeType='boundary-constraint' + lifecycle 过滤
|
|
549
|
+
* (GuardCheckEngine._loadCustomRules)
|
|
550
|
+
*/
|
|
551
|
+
findGuardRulesSync(lifecycles) {
|
|
552
|
+
return this.#drizzle
|
|
553
|
+
.select({
|
|
554
|
+
id: knowledgeEntries.id,
|
|
555
|
+
title: knowledgeEntries.title,
|
|
556
|
+
description: knowledgeEntries.description,
|
|
557
|
+
language: knowledgeEntries.language,
|
|
558
|
+
scope: knowledgeEntries.scope,
|
|
559
|
+
constraints: knowledgeEntries.constraints,
|
|
560
|
+
lifecycle: knowledgeEntries.lifecycle,
|
|
561
|
+
})
|
|
562
|
+
.from(knowledgeEntries)
|
|
563
|
+
.where(and(or(eq(knowledgeEntries.kind, 'rule'), eq(knowledgeEntries.knowledgeType, 'boundary-constraint')), inArray(knowledgeEntries.lifecycle, lifecycles)))
|
|
564
|
+
.all();
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Guard 命中次数递增 — stats.guardHits += count
|
|
568
|
+
* (GuardCheckEngine._recordHits)
|
|
569
|
+
*/
|
|
570
|
+
incrementGuardHitsSync(id, hits) {
|
|
571
|
+
this.#drizzle
|
|
572
|
+
.update(knowledgeEntries)
|
|
573
|
+
.set({
|
|
574
|
+
stats: sql `json_set(COALESCE(${knowledgeEntries.stats}, '{}'), '$.guardHits', COALESCE(json_extract(${knowledgeEntries.stats}, '$.guardHits'), 0) + ${hits})`,
|
|
575
|
+
updatedAt: unixNow(),
|
|
576
|
+
})
|
|
577
|
+
.where(eq(knowledgeEntries.id, id))
|
|
578
|
+
.run();
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* 活跃规则 + content 中的 coreCode / pattern 字段 + stats
|
|
582
|
+
* (ReverseGuard.#loadActiveRules)
|
|
583
|
+
*/
|
|
584
|
+
findActiveRulesWithContentSync() {
|
|
585
|
+
return this.#drizzle
|
|
586
|
+
.select({
|
|
587
|
+
id: knowledgeEntries.id,
|
|
588
|
+
title: knowledgeEntries.title,
|
|
589
|
+
coreCode: sql `json_extract(${knowledgeEntries.content}, '$.coreCode')`.as('coreCode'),
|
|
590
|
+
guardPattern: sql `json_extract(${knowledgeEntries.content}, '$.pattern')`.as('guardPattern'),
|
|
591
|
+
stats: knowledgeEntries.stats,
|
|
592
|
+
})
|
|
593
|
+
.from(knowledgeEntries)
|
|
594
|
+
.where(and(eq(knowledgeEntries.lifecycle, 'active'), eq(knowledgeEntries.kind, 'rule')))
|
|
595
|
+
.all();
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* 获取单条记录的 guardHits 数
|
|
599
|
+
* (ReverseGuard.#historicalGuardHits)
|
|
600
|
+
*/
|
|
601
|
+
getGuardHitsSync(id) {
|
|
602
|
+
const row = this.#drizzle
|
|
603
|
+
.select({
|
|
604
|
+
hits: sql `json_extract(${knowledgeEntries.stats}, '$.guardHits')`.as('hits'),
|
|
605
|
+
})
|
|
606
|
+
.from(knowledgeEntries)
|
|
607
|
+
.where(eq(knowledgeEntries.id, id))
|
|
608
|
+
.get();
|
|
609
|
+
return Number(row?.hits ?? 0);
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* 活跃规则的 id + language (CoverageAnalyzer.#loadActiveRules) — sync
|
|
613
|
+
*/
|
|
614
|
+
findActiveRuleIdsSync() {
|
|
615
|
+
return this.#drizzle
|
|
616
|
+
.select({
|
|
617
|
+
id: knowledgeEntries.id,
|
|
618
|
+
language: knowledgeEntries.language,
|
|
619
|
+
})
|
|
620
|
+
.from(knowledgeEntries)
|
|
621
|
+
.where(and(eq(knowledgeEntries.lifecycle, 'active'), eq(knowledgeEntries.kind, 'rule')))
|
|
622
|
+
.all();
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* 活跃条目按 category 分布
|
|
626
|
+
* (SkillAdvisor.#getKBDistribution)
|
|
627
|
+
*/
|
|
628
|
+
async countGroupByCategory() {
|
|
629
|
+
return this.#drizzle
|
|
630
|
+
.select({
|
|
631
|
+
category: knowledgeEntries.category,
|
|
632
|
+
cnt: count(),
|
|
633
|
+
})
|
|
634
|
+
.from(knowledgeEntries)
|
|
635
|
+
.where(and(eq(knowledgeEntries.lifecycle, 'active'), isNotNull(knowledgeEntries.category), ne(knowledgeEntries.category, '')))
|
|
636
|
+
.groupBy(knowledgeEntries.category)
|
|
637
|
+
.orderBy(desc(count()))
|
|
638
|
+
.all();
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 活跃条目按 language 分布
|
|
642
|
+
* (SkillAdvisor.#getKBDistribution)
|
|
643
|
+
*/
|
|
644
|
+
async countGroupByLanguage() {
|
|
645
|
+
return this.#drizzle
|
|
646
|
+
.select({
|
|
647
|
+
language: knowledgeEntries.language,
|
|
648
|
+
cnt: count(),
|
|
649
|
+
})
|
|
650
|
+
.from(knowledgeEntries)
|
|
651
|
+
.where(and(eq(knowledgeEntries.lifecycle, 'active'), isNotNull(knowledgeEntries.language), ne(knowledgeEntries.language, '')))
|
|
652
|
+
.groupBy(knowledgeEntries.language)
|
|
653
|
+
.orderBy(desc(count()))
|
|
654
|
+
.all();
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* 高使用率活跃 Recipe (adoptions + applications >= minUsage)
|
|
658
|
+
* (SkillAdvisor.#getKBDistribution)
|
|
659
|
+
*/
|
|
660
|
+
async findHotRecipesByUsage(minUsage, limit) {
|
|
661
|
+
return this.#drizzle
|
|
662
|
+
.select({
|
|
663
|
+
title: knowledgeEntries.title,
|
|
664
|
+
category: knowledgeEntries.category,
|
|
665
|
+
totalUsage: sql `(COALESCE(json_extract(${knowledgeEntries.stats}, '$.adoptions'), 0) + COALESCE(json_extract(${knowledgeEntries.stats}, '$.applications'), 0))`.as('totalUsage'),
|
|
666
|
+
})
|
|
667
|
+
.from(knowledgeEntries)
|
|
668
|
+
.where(and(eq(knowledgeEntries.lifecycle, 'active'), sql `(COALESCE(json_extract(${knowledgeEntries.stats}, '$.adoptions'), 0) + COALESCE(json_extract(${knowledgeEntries.stats}, '$.applications'), 0)) >= ${minUsage}`))
|
|
669
|
+
.orderBy(desc(sql `(COALESCE(json_extract(${knowledgeEntries.stats}, '$.adoptions'), 0) + COALESCE(json_extract(${knowledgeEntries.stats}, '$.applications'), 0))`))
|
|
670
|
+
.limit(limit)
|
|
671
|
+
.all();
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* 全库生命周期统计 (total / pending / deprecated)
|
|
675
|
+
* (SkillAdvisor.#getKBDistribution)
|
|
676
|
+
*/
|
|
677
|
+
async getLifecycleCounts() {
|
|
678
|
+
const row = this.#drizzle
|
|
679
|
+
.select({
|
|
680
|
+
total: count(),
|
|
681
|
+
pending: sql `SUM(CASE WHEN ${knowledgeEntries.lifecycle} = 'pending' THEN 1 ELSE 0 END)`.as('pending'),
|
|
682
|
+
deprecated: sql `SUM(CASE WHEN ${knowledgeEntries.lifecycle} = 'deprecated' THEN 1 ELSE 0 END)`.as('deprecated'),
|
|
683
|
+
})
|
|
684
|
+
.from(knowledgeEntries)
|
|
685
|
+
.get();
|
|
686
|
+
return {
|
|
687
|
+
total: Number(row?.total ?? 0),
|
|
688
|
+
pending: Number(row?.pending ?? 0),
|
|
689
|
+
deprecated: Number(row?.deprecated ?? 0),
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* 活跃 Recipe 信号 (SignalCollector.#collectRecipeSignals)
|
|
694
|
+
*/
|
|
695
|
+
async findActiveRecipeSignals(limit) {
|
|
696
|
+
return this.#drizzle
|
|
697
|
+
.select({
|
|
698
|
+
id: knowledgeEntries.id,
|
|
699
|
+
title: knowledgeEntries.title,
|
|
700
|
+
knowledgeType: knowledgeEntries.knowledgeType,
|
|
701
|
+
category: knowledgeEntries.category,
|
|
702
|
+
language: knowledgeEntries.language,
|
|
703
|
+
adoptionCount: sql `json_extract(${knowledgeEntries.stats}, '$.adoptions')`.as('adoptionCount'),
|
|
704
|
+
applicationCount: sql `json_extract(${knowledgeEntries.stats}, '$.applications')`.as('applicationCount'),
|
|
705
|
+
qualityOverall: sql `json_extract(${knowledgeEntries.quality}, '$.overall')`.as('qualityOverall'),
|
|
706
|
+
updatedAt: knowledgeEntries.updatedAt,
|
|
707
|
+
})
|
|
708
|
+
.from(knowledgeEntries)
|
|
709
|
+
.where(eq(knowledgeEntries.lifecycle, 'active'))
|
|
710
|
+
.orderBy(desc(knowledgeEntries.updatedAt))
|
|
711
|
+
.limit(limit)
|
|
712
|
+
.all();
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* 待审核 Candidate (SignalCollector.#collectCandidateSignals)
|
|
716
|
+
*/
|
|
717
|
+
async findPendingCandidates(limit) {
|
|
718
|
+
return this.#drizzle
|
|
719
|
+
.select({
|
|
720
|
+
id: knowledgeEntries.id,
|
|
721
|
+
source: knowledgeEntries.source,
|
|
722
|
+
status: knowledgeEntries.lifecycle,
|
|
723
|
+
language: knowledgeEntries.language,
|
|
724
|
+
category: knowledgeEntries.category,
|
|
725
|
+
title: knowledgeEntries.title,
|
|
726
|
+
createdAt: knowledgeEntries.createdAt,
|
|
727
|
+
})
|
|
728
|
+
.from(knowledgeEntries)
|
|
729
|
+
.where(eq(knowledgeEntries.lifecycle, 'pending'))
|
|
730
|
+
.orderBy(desc(knowledgeEntries.createdAt))
|
|
731
|
+
.limit(limit)
|
|
732
|
+
.all();
|
|
733
|
+
}
|
|
236
734
|
/* ═══ 行 ↔ 实体 映射 ═══════════════════════════════ */
|
|
237
735
|
/** DB Row → KnowledgeEntry (camelCase 列名 = 属性名,直传) */
|
|
238
736
|
_rowToEntity(row) {
|
|
@@ -257,7 +755,7 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
|
|
|
257
755
|
autoApprovable: !!row.autoApprovable,
|
|
258
756
|
includeHeaders: !!row.includeHeaders,
|
|
259
757
|
// Staging support
|
|
260
|
-
stagingDeadline: row.
|
|
758
|
+
stagingDeadline: row.stagingDeadline || null,
|
|
261
759
|
});
|
|
262
760
|
}
|
|
263
761
|
/** KnowledgeEntry → DB Row (camelCase 列名 = 属性名,直传) */
|
|
@@ -310,12 +808,109 @@ export class KnowledgeRepositoryImpl extends BaseRepository {
|
|
|
310
808
|
staging_deadline: e.stagingDeadline || null,
|
|
311
809
|
};
|
|
312
810
|
}
|
|
313
|
-
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return this
|
|
811
|
+
/* ═══════════════════════════════════════════════════════
|
|
812
|
+
* SearchEngine 用同步方法
|
|
813
|
+
* ═══════════════════════════════════════════════════════ */
|
|
814
|
+
/** 查询所有非 deprecated 条目(buildIndex 用) */
|
|
815
|
+
findNonDeprecatedSync() {
|
|
816
|
+
return this.#drizzle
|
|
817
|
+
.select({
|
|
818
|
+
id: knowledgeEntries.id,
|
|
819
|
+
title: knowledgeEntries.title,
|
|
820
|
+
description: knowledgeEntries.description,
|
|
821
|
+
language: knowledgeEntries.language,
|
|
822
|
+
category: knowledgeEntries.category,
|
|
823
|
+
knowledgeType: knowledgeEntries.knowledgeType,
|
|
824
|
+
kind: knowledgeEntries.kind,
|
|
825
|
+
content: knowledgeEntries.content,
|
|
826
|
+
lifecycle: knowledgeEntries.lifecycle,
|
|
827
|
+
tags: knowledgeEntries.tags,
|
|
828
|
+
trigger: knowledgeEntries.trigger,
|
|
829
|
+
difficulty: knowledgeEntries.difficulty,
|
|
830
|
+
quality: knowledgeEntries.quality,
|
|
831
|
+
stats: knowledgeEntries.stats,
|
|
832
|
+
updatedAt: knowledgeEntries.updatedAt,
|
|
833
|
+
createdAt: knowledgeEntries.createdAt,
|
|
834
|
+
})
|
|
835
|
+
.from(knowledgeEntries)
|
|
836
|
+
.where(ne(knowledgeEntries.lifecycle, 'deprecated'))
|
|
837
|
+
.all();
|
|
838
|
+
}
|
|
839
|
+
/** LIKE 关键词搜索(_keywordSearch 用) */
|
|
840
|
+
keywordSearchSync(pattern, limit) {
|
|
841
|
+
return this.#drizzle
|
|
842
|
+
.select({
|
|
843
|
+
id: knowledgeEntries.id,
|
|
844
|
+
title: knowledgeEntries.title,
|
|
845
|
+
description: knowledgeEntries.description,
|
|
846
|
+
language: knowledgeEntries.language,
|
|
847
|
+
category: knowledgeEntries.category,
|
|
848
|
+
knowledgeType: knowledgeEntries.knowledgeType,
|
|
849
|
+
kind: knowledgeEntries.kind,
|
|
850
|
+
lifecycle: knowledgeEntries.lifecycle,
|
|
851
|
+
content: knowledgeEntries.content,
|
|
852
|
+
trigger: knowledgeEntries.trigger,
|
|
853
|
+
headers: knowledgeEntries.headers,
|
|
854
|
+
moduleName: knowledgeEntries.moduleName,
|
|
855
|
+
})
|
|
856
|
+
.from(knowledgeEntries)
|
|
857
|
+
.where(and(ne(knowledgeEntries.lifecycle, 'deprecated'), or(like(knowledgeEntries.title, pattern), like(knowledgeEntries.description, pattern), like(knowledgeEntries.trigger, pattern), like(knowledgeEntries.content, pattern))))
|
|
858
|
+
.limit(limit)
|
|
859
|
+
.all();
|
|
860
|
+
}
|
|
861
|
+
/** 按 ID 列表查询详情(_supplementDetails 用) */
|
|
862
|
+
findByIdsDetailSync(ids) {
|
|
863
|
+
if (ids.length === 0) {
|
|
864
|
+
return [];
|
|
865
|
+
}
|
|
866
|
+
return this.#drizzle
|
|
867
|
+
.select({
|
|
868
|
+
id: knowledgeEntries.id,
|
|
869
|
+
content: knowledgeEntries.content,
|
|
870
|
+
description: knowledgeEntries.description,
|
|
871
|
+
trigger: knowledgeEntries.trigger,
|
|
872
|
+
headers: knowledgeEntries.headers,
|
|
873
|
+
moduleName: knowledgeEntries.moduleName,
|
|
874
|
+
tags: knowledgeEntries.tags,
|
|
875
|
+
language: knowledgeEntries.language,
|
|
876
|
+
category: knowledgeEntries.category,
|
|
877
|
+
updatedAt: knowledgeEntries.updatedAt,
|
|
878
|
+
createdAt: knowledgeEntries.createdAt,
|
|
879
|
+
quality: knowledgeEntries.quality,
|
|
880
|
+
stats: knowledgeEntries.stats,
|
|
881
|
+
difficulty: knowledgeEntries.difficulty,
|
|
882
|
+
whenClause: knowledgeEntries.whenClause,
|
|
883
|
+
doClause: knowledgeEntries.doClause,
|
|
884
|
+
})
|
|
885
|
+
.from(knowledgeEntries)
|
|
886
|
+
.where(inArray(knowledgeEntries.id, ids))
|
|
887
|
+
.all();
|
|
888
|
+
}
|
|
889
|
+
/** 查询指定时间之后更新的条目(refreshIndex 用) */
|
|
890
|
+
findUpdatedSinceSync(sinceIso) {
|
|
891
|
+
const sinceEpoch = Math.floor(new Date(sinceIso).getTime() / 1000);
|
|
892
|
+
return this.#drizzle
|
|
893
|
+
.select({
|
|
894
|
+
id: knowledgeEntries.id,
|
|
895
|
+
title: knowledgeEntries.title,
|
|
896
|
+
description: knowledgeEntries.description,
|
|
897
|
+
language: knowledgeEntries.language,
|
|
898
|
+
category: knowledgeEntries.category,
|
|
899
|
+
knowledgeType: knowledgeEntries.knowledgeType,
|
|
900
|
+
kind: knowledgeEntries.kind,
|
|
901
|
+
content: knowledgeEntries.content,
|
|
902
|
+
lifecycle: knowledgeEntries.lifecycle,
|
|
903
|
+
tags: knowledgeEntries.tags,
|
|
904
|
+
trigger: knowledgeEntries.trigger,
|
|
905
|
+
difficulty: knowledgeEntries.difficulty,
|
|
906
|
+
quality: knowledgeEntries.quality,
|
|
907
|
+
stats: knowledgeEntries.stats,
|
|
908
|
+
updatedAt: knowledgeEntries.updatedAt,
|
|
909
|
+
createdAt: knowledgeEntries.createdAt,
|
|
910
|
+
})
|
|
911
|
+
.from(knowledgeEntries)
|
|
912
|
+
.where(gt(knowledgeEntries.updatedAt, sinceEpoch))
|
|
913
|
+
.all();
|
|
319
914
|
}
|
|
320
915
|
}
|
|
321
916
|
export default KnowledgeRepositoryImpl;
|