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
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KnowledgeUnitOfWork — 知识实体写操作的原子协调器
|
|
3
|
+
*
|
|
4
|
+
* 策略: "文件优先 + DB 补偿"
|
|
5
|
+
*
|
|
6
|
+
* 1. 收集所有 DB 变更意图(不执行)
|
|
7
|
+
* 2. 依次执行文件操作(writeFileSync 同步写入)
|
|
8
|
+
* 3. 若任何文件操作失败 → 回滚已完成的文件操作,整体中止
|
|
9
|
+
* 4. 全部文件操作成功 → 开启 SQLite 事务,提交所有 DB 变更
|
|
10
|
+
* 5. 若 DB 事务失败 → 文件已写入,下次 SyncService 扫描自动重建 DB
|
|
11
|
+
*
|
|
12
|
+
* 为何 "文件优先" 而非 "DB 优先"?
|
|
13
|
+
* - .md 文件 = 唯一真相源(第一原则)
|
|
14
|
+
* - 文件写成功 + DB 失败 → SyncService 可从文件重建 DB ✅
|
|
15
|
+
* - DB 写成功 + 文件写失败 → DB 有记录但无对应文件
|
|
16
|
+
* → SyncService 会标记 deprecated → 数据丢失 ❌
|
|
17
|
+
* - 文件优先确保:无论哪步失败,.md 文件的存在性始终是判定真相的依据
|
|
18
|
+
*
|
|
19
|
+
* 当前代码现状(改造前):
|
|
20
|
+
* - KnowledgeService.create/update: DB 先 → file 后(不一致风险)
|
|
21
|
+
* - KnowledgeService.delete: file 先 → DB 后(已是正确顺序)
|
|
22
|
+
* - 本 UoW 统一所有操作为 file-first
|
|
23
|
+
*/
|
|
24
|
+
import type { KnowledgeEntry } from '../../domain/knowledge/KnowledgeEntry.js';
|
|
25
|
+
import type { DrizzleDB } from '../../infrastructure/database/drizzle/index.js';
|
|
26
|
+
import type { DrizzleTx } from '../base/RepositoryBase.js';
|
|
27
|
+
import type { KnowledgeFileStore } from './KnowledgeFileStore.js';
|
|
28
|
+
export interface PendingFileOp {
|
|
29
|
+
type: 'write' | 'move' | 'delete';
|
|
30
|
+
entry: KnowledgeEntry;
|
|
31
|
+
/** move 操作的旧路径(用于回滚时恢复) */
|
|
32
|
+
oldPath?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface UnitOfWorkResult {
|
|
35
|
+
/** DB 事务是否成功提交 */
|
|
36
|
+
dbCommitted: boolean;
|
|
37
|
+
/** 完成的文件操作列表 */
|
|
38
|
+
fileOpsCompleted: number;
|
|
39
|
+
}
|
|
40
|
+
export declare class FileWriteError extends Error {
|
|
41
|
+
constructor(message: string, options?: ErrorOptions);
|
|
42
|
+
}
|
|
43
|
+
export declare class KnowledgeUnitOfWork {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(drizzle: DrizzleDB, fileStore: KnowledgeFileStore);
|
|
46
|
+
/** 注册 DB 变更意图(延迟执行) */
|
|
47
|
+
registerDbChange(fn: (tx: DrizzleTx) => void): void;
|
|
48
|
+
/** 注册文件操作意图 */
|
|
49
|
+
registerFileOp(op: PendingFileOp): void;
|
|
50
|
+
/**
|
|
51
|
+
* 提交:文件操作 → DB 事务
|
|
52
|
+
*
|
|
53
|
+
* 失败模式:
|
|
54
|
+
* 1. 文件写失败:中止,回滚已写文件,不触碰 DB → 干净状态
|
|
55
|
+
* 2. 文件全成功 + DB 失败:文件已持久化 → SyncService 下次扫描自动补 DB
|
|
56
|
+
* 3. 文件全成功 + DB 成功:完美一致
|
|
57
|
+
*/
|
|
58
|
+
commit(): UnitOfWorkResult;
|
|
59
|
+
/** 回滚:清空所有挂起操作(不执行已注册但未提交的操作) */
|
|
60
|
+
rollback(): void;
|
|
61
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KnowledgeUnitOfWork — 知识实体写操作的原子协调器
|
|
3
|
+
*
|
|
4
|
+
* 策略: "文件优先 + DB 补偿"
|
|
5
|
+
*
|
|
6
|
+
* 1. 收集所有 DB 变更意图(不执行)
|
|
7
|
+
* 2. 依次执行文件操作(writeFileSync 同步写入)
|
|
8
|
+
* 3. 若任何文件操作失败 → 回滚已完成的文件操作,整体中止
|
|
9
|
+
* 4. 全部文件操作成功 → 开启 SQLite 事务,提交所有 DB 变更
|
|
10
|
+
* 5. 若 DB 事务失败 → 文件已写入,下次 SyncService 扫描自动重建 DB
|
|
11
|
+
*
|
|
12
|
+
* 为何 "文件优先" 而非 "DB 优先"?
|
|
13
|
+
* - .md 文件 = 唯一真相源(第一原则)
|
|
14
|
+
* - 文件写成功 + DB 失败 → SyncService 可从文件重建 DB ✅
|
|
15
|
+
* - DB 写成功 + 文件写失败 → DB 有记录但无对应文件
|
|
16
|
+
* → SyncService 会标记 deprecated → 数据丢失 ❌
|
|
17
|
+
* - 文件优先确保:无论哪步失败,.md 文件的存在性始终是判定真相的依据
|
|
18
|
+
*
|
|
19
|
+
* 当前代码现状(改造前):
|
|
20
|
+
* - KnowledgeService.create/update: DB 先 → file 后(不一致风险)
|
|
21
|
+
* - KnowledgeService.delete: file 先 → DB 后(已是正确顺序)
|
|
22
|
+
* - 本 UoW 统一所有操作为 file-first
|
|
23
|
+
*/
|
|
24
|
+
import Logger from '../../infrastructure/logging/Logger.js';
|
|
25
|
+
export class FileWriteError extends Error {
|
|
26
|
+
constructor(message, options) {
|
|
27
|
+
super(message, options);
|
|
28
|
+
this.name = 'FileWriteError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/* ═══ UnitOfWork 实现 ═══ */
|
|
32
|
+
export class KnowledgeUnitOfWork {
|
|
33
|
+
#drizzle;
|
|
34
|
+
#fileStore;
|
|
35
|
+
#pendingFileOps = [];
|
|
36
|
+
#dbChanges = [];
|
|
37
|
+
#completedFileOps = [];
|
|
38
|
+
#logger = Logger.getInstance();
|
|
39
|
+
constructor(drizzle, fileStore) {
|
|
40
|
+
this.#drizzle = drizzle;
|
|
41
|
+
this.#fileStore = fileStore;
|
|
42
|
+
}
|
|
43
|
+
/** 注册 DB 变更意图(延迟执行) */
|
|
44
|
+
registerDbChange(fn) {
|
|
45
|
+
this.#dbChanges.push(fn);
|
|
46
|
+
}
|
|
47
|
+
/** 注册文件操作意图 */
|
|
48
|
+
registerFileOp(op) {
|
|
49
|
+
this.#pendingFileOps.push(op);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 提交:文件操作 → DB 事务
|
|
53
|
+
*
|
|
54
|
+
* 失败模式:
|
|
55
|
+
* 1. 文件写失败:中止,回滚已写文件,不触碰 DB → 干净状态
|
|
56
|
+
* 2. 文件全成功 + DB 失败:文件已持久化 → SyncService 下次扫描自动补 DB
|
|
57
|
+
* 3. 文件全成功 + DB 成功:完美一致
|
|
58
|
+
*/
|
|
59
|
+
commit() {
|
|
60
|
+
// Phase 1: 文件操作 (must-succeed)
|
|
61
|
+
this.#completedFileOps = [];
|
|
62
|
+
for (const op of this.#pendingFileOps) {
|
|
63
|
+
try {
|
|
64
|
+
this.#executeFileOp(op);
|
|
65
|
+
this.#completedFileOps.push(op);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
// 回滚已完成的文件操作
|
|
69
|
+
this.#rollbackFileOps();
|
|
70
|
+
this.#reset();
|
|
71
|
+
throw new FileWriteError(`File operation failed: ${op.type} for ${op.entry.id}`, {
|
|
72
|
+
cause: err,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Phase 2: DB 事务(文件已安全落盘)
|
|
77
|
+
let dbCommitted = false;
|
|
78
|
+
if (this.#dbChanges.length > 0) {
|
|
79
|
+
try {
|
|
80
|
+
this.#drizzle.transaction((tx) => {
|
|
81
|
+
for (const change of this.#dbChanges) {
|
|
82
|
+
change(tx);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
dbCommitted = true;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
// DB 失败但文件已写入 → 最终一致性
|
|
89
|
+
// SyncService.reconcile() 下次运行时会从文件重建 DB 记录
|
|
90
|
+
this.#logger.warn('UoW: DB transaction failed after file success', {
|
|
91
|
+
fileOpsCompleted: this.#completedFileOps.length,
|
|
92
|
+
error: err instanceof Error ? err.message : String(err),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
dbCommitted = true; // 无 DB 变更时视为成功
|
|
98
|
+
}
|
|
99
|
+
const result = {
|
|
100
|
+
dbCommitted,
|
|
101
|
+
fileOpsCompleted: this.#completedFileOps.length,
|
|
102
|
+
};
|
|
103
|
+
this.#reset();
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
/** 回滚:清空所有挂起操作(不执行已注册但未提交的操作) */
|
|
107
|
+
rollback() {
|
|
108
|
+
this.#reset();
|
|
109
|
+
}
|
|
110
|
+
#executeFileOp(op) {
|
|
111
|
+
switch (op.type) {
|
|
112
|
+
case 'write':
|
|
113
|
+
this.#fileStore.persist(op.entry);
|
|
114
|
+
break;
|
|
115
|
+
case 'move':
|
|
116
|
+
this.#fileStore.moveOnLifecycleChange(op.entry);
|
|
117
|
+
break;
|
|
118
|
+
case 'delete':
|
|
119
|
+
this.#fileStore.remove(op.entry);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** 尽力回滚已完成的文件操作 */
|
|
124
|
+
#rollbackFileOps() {
|
|
125
|
+
for (const op of [...this.#completedFileOps].reverse()) {
|
|
126
|
+
try {
|
|
127
|
+
switch (op.type) {
|
|
128
|
+
case 'write':
|
|
129
|
+
this.#fileStore.remove(op.entry); // 回滚写入 → 删除
|
|
130
|
+
break;
|
|
131
|
+
case 'delete':
|
|
132
|
+
this.#fileStore.persist(op.entry); // 回滚删除 → 重写
|
|
133
|
+
break;
|
|
134
|
+
case 'move':
|
|
135
|
+
// move 回滚较复杂,记录日志等 SyncService 修复
|
|
136
|
+
this.#logger.warn('UoW: Cannot auto-rollback move op', {
|
|
137
|
+
entryId: op.entry.id,
|
|
138
|
+
});
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// 回滚失败不再抛出,记录日志
|
|
144
|
+
this.#logger.error('UoW: File rollback failed', {
|
|
145
|
+
type: op.type,
|
|
146
|
+
entryId: op.entry.id,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
#reset() {
|
|
152
|
+
this.#dbChanges = [];
|
|
153
|
+
this.#pendingFileOps = [];
|
|
154
|
+
this.#completedFileOps = [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MemoryRepository — Agent 语义记忆的仓储实现
|
|
3
|
+
*
|
|
4
|
+
* 从 MemoryStore 提取的数据操作,
|
|
5
|
+
* 使用 Drizzle 类型安全 API 操作 semantic_memories 表。
|
|
6
|
+
* embedding 已迁移到 JSON sidecar (MemoryEmbeddingStore)。
|
|
7
|
+
*/
|
|
8
|
+
import { semanticMemories } from '../../infrastructure/database/drizzle/schema.js';
|
|
9
|
+
import { RepositoryBase } from '../base/RepositoryBase.js';
|
|
10
|
+
export interface SemanticMemoryEntity {
|
|
11
|
+
id: string;
|
|
12
|
+
type: string;
|
|
13
|
+
content: string;
|
|
14
|
+
source: string;
|
|
15
|
+
importance: number;
|
|
16
|
+
accessCount: number;
|
|
17
|
+
lastAccessedAt: string | null;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
expiresAt: string | null;
|
|
21
|
+
relatedEntities: string[];
|
|
22
|
+
relatedMemories: string[];
|
|
23
|
+
sourceDimension: string | null;
|
|
24
|
+
sourceEvidence: string | null;
|
|
25
|
+
bootstrapSession: string | null;
|
|
26
|
+
tags: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface SemanticMemoryInsert {
|
|
29
|
+
id: string;
|
|
30
|
+
type?: string;
|
|
31
|
+
content: string;
|
|
32
|
+
source?: string;
|
|
33
|
+
importance?: number;
|
|
34
|
+
expiresAt?: string | null;
|
|
35
|
+
relatedEntities?: string[];
|
|
36
|
+
sourceDimension?: string | null;
|
|
37
|
+
sourceEvidence?: string | null;
|
|
38
|
+
bootstrapSession?: string | null;
|
|
39
|
+
tags?: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface SemanticMemoryUpdate {
|
|
42
|
+
content?: string;
|
|
43
|
+
importance?: number;
|
|
44
|
+
accessCount?: number;
|
|
45
|
+
relatedEntities?: string[];
|
|
46
|
+
relatedMemories?: string[];
|
|
47
|
+
tags?: string[];
|
|
48
|
+
}
|
|
49
|
+
export interface MemoryStats {
|
|
50
|
+
total: number;
|
|
51
|
+
byType: Record<string, number>;
|
|
52
|
+
bySource: Record<string, number>;
|
|
53
|
+
avgImportance: number;
|
|
54
|
+
}
|
|
55
|
+
export declare class MemoryRepositoryImpl extends RepositoryBase<typeof semanticMemories, SemanticMemoryEntity> {
|
|
56
|
+
#private;
|
|
57
|
+
constructor(drizzle: ConstructorParameters<typeof RepositoryBase<typeof semanticMemories, SemanticMemoryEntity>>[0]);
|
|
58
|
+
findById(id: string): Promise<SemanticMemoryEntity | null>;
|
|
59
|
+
create(data: SemanticMemoryInsert): Promise<SemanticMemoryEntity>;
|
|
60
|
+
delete(id: string): Promise<boolean>;
|
|
61
|
+
/** 动态字段更新 */
|
|
62
|
+
update(id: string, updates: SemanticMemoryUpdate): Promise<boolean>;
|
|
63
|
+
/** 更新访问计数 */
|
|
64
|
+
touchAccess(id: string): Promise<void>;
|
|
65
|
+
/** 获取所有活跃记忆 (未过期) */
|
|
66
|
+
getAllActive(filters?: {
|
|
67
|
+
source?: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
}): Promise<SemanticMemoryEntity[]>;
|
|
70
|
+
/** 获取候选记忆 (用于相似度搜索) */
|
|
71
|
+
getCandidates(type: string | null, limit?: number): Promise<SemanticMemoryEntity[]>;
|
|
72
|
+
/** 记忆总数 */
|
|
73
|
+
size(filters?: {
|
|
74
|
+
source?: string;
|
|
75
|
+
}): Promise<number>;
|
|
76
|
+
/**
|
|
77
|
+
* 执行维护: 清理过期记忆 + 自然遗忘 + 重要度衰减
|
|
78
|
+
*/
|
|
79
|
+
compact(): Promise<{
|
|
80
|
+
expired: number;
|
|
81
|
+
forgotten: number;
|
|
82
|
+
archived: number;
|
|
83
|
+
remaining: number;
|
|
84
|
+
}>;
|
|
85
|
+
/** 容量控制 */
|
|
86
|
+
enforceCapacity(maxMemories?: number): Promise<number>;
|
|
87
|
+
getStats(): Promise<MemoryStats>;
|
|
88
|
+
/** 清除所有 bootstrap 来源的记忆 */
|
|
89
|
+
clearBootstrapMemories(): Promise<number>;
|
|
90
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MemoryRepository — Agent 语义记忆的仓储实现
|
|
3
|
+
*
|
|
4
|
+
* 从 MemoryStore 提取的数据操作,
|
|
5
|
+
* 使用 Drizzle 类型安全 API 操作 semantic_memories 表。
|
|
6
|
+
* embedding 已迁移到 JSON sidecar (MemoryEmbeddingStore)。
|
|
7
|
+
*/
|
|
8
|
+
import { and, avg, count, desc, eq, isNull, or, sql } from 'drizzle-orm';
|
|
9
|
+
import { semanticMemories } from '../../infrastructure/database/drizzle/schema.js';
|
|
10
|
+
import { RepositoryBase } from '../base/RepositoryBase.js';
|
|
11
|
+
/* ═══ 常量 ═══ */
|
|
12
|
+
const MAX_MEMORIES = 500;
|
|
13
|
+
const ARCHIVE_DAYS = 30;
|
|
14
|
+
const FORGET_DAYS = 90;
|
|
15
|
+
/* ═══ Repository 实现 ═══ */
|
|
16
|
+
export class MemoryRepositoryImpl extends RepositoryBase {
|
|
17
|
+
constructor(drizzle) {
|
|
18
|
+
super(drizzle, semanticMemories);
|
|
19
|
+
}
|
|
20
|
+
/* ─── CRUD ─── */
|
|
21
|
+
async findById(id) {
|
|
22
|
+
const row = this.drizzle.select().from(this.table).where(eq(this.table.id, id)).limit(1).get();
|
|
23
|
+
return row ? this.#mapRow(row) : null;
|
|
24
|
+
}
|
|
25
|
+
async create(data) {
|
|
26
|
+
const now = new Date().toISOString();
|
|
27
|
+
this.drizzle
|
|
28
|
+
.insert(this.table)
|
|
29
|
+
.values({
|
|
30
|
+
id: data.id,
|
|
31
|
+
type: data.type ?? 'fact',
|
|
32
|
+
content: (data.content || '').trim().substring(0, 500),
|
|
33
|
+
source: data.source ?? 'bootstrap',
|
|
34
|
+
importance: Math.max(1, Math.min(10, data.importance ?? 5)),
|
|
35
|
+
accessCount: 0,
|
|
36
|
+
lastAccessedAt: now,
|
|
37
|
+
createdAt: now,
|
|
38
|
+
updatedAt: now,
|
|
39
|
+
expiresAt: data.expiresAt ?? null,
|
|
40
|
+
relatedEntities: JSON.stringify(data.relatedEntities ?? []),
|
|
41
|
+
relatedMemories: JSON.stringify([]),
|
|
42
|
+
sourceDimension: data.sourceDimension ?? null,
|
|
43
|
+
sourceEvidence: data.sourceEvidence ?? null,
|
|
44
|
+
bootstrapSession: data.bootstrapSession ?? null,
|
|
45
|
+
tags: JSON.stringify(data.tags ?? []),
|
|
46
|
+
})
|
|
47
|
+
.run();
|
|
48
|
+
return (await this.findById(data.id));
|
|
49
|
+
}
|
|
50
|
+
async delete(id) {
|
|
51
|
+
const result = this.drizzle.delete(this.table).where(eq(this.table.id, id)).run();
|
|
52
|
+
return result.changes > 0;
|
|
53
|
+
}
|
|
54
|
+
/** 动态字段更新 */
|
|
55
|
+
async update(id, updates) {
|
|
56
|
+
const existing = await this.findById(id);
|
|
57
|
+
if (!existing) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const now = new Date().toISOString();
|
|
61
|
+
const setValues = { updatedAt: now };
|
|
62
|
+
if (updates.content !== undefined) {
|
|
63
|
+
setValues.content = updates.content.substring(0, 500);
|
|
64
|
+
}
|
|
65
|
+
if (updates.importance !== undefined) {
|
|
66
|
+
setValues.importance = Math.max(1, Math.min(10, updates.importance));
|
|
67
|
+
}
|
|
68
|
+
if (updates.accessCount !== undefined) {
|
|
69
|
+
setValues.accessCount = updates.accessCount;
|
|
70
|
+
}
|
|
71
|
+
if (updates.relatedEntities !== undefined) {
|
|
72
|
+
setValues.relatedEntities = JSON.stringify(updates.relatedEntities);
|
|
73
|
+
}
|
|
74
|
+
if (updates.relatedMemories !== undefined) {
|
|
75
|
+
setValues.relatedMemories = JSON.stringify(updates.relatedMemories);
|
|
76
|
+
}
|
|
77
|
+
if (updates.tags !== undefined) {
|
|
78
|
+
setValues.tags = JSON.stringify(updates.tags);
|
|
79
|
+
}
|
|
80
|
+
this.drizzle.update(this.table).set(setValues).where(eq(this.table.id, id)).run();
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
/* ─── 访问计数 ─── */
|
|
84
|
+
/** 更新访问计数 */
|
|
85
|
+
async touchAccess(id) {
|
|
86
|
+
this.drizzle
|
|
87
|
+
.update(this.table)
|
|
88
|
+
.set({
|
|
89
|
+
accessCount: sql `${this.table.accessCount} + 1`,
|
|
90
|
+
lastAccessedAt: new Date().toISOString(),
|
|
91
|
+
})
|
|
92
|
+
.where(eq(this.table.id, id))
|
|
93
|
+
.run();
|
|
94
|
+
}
|
|
95
|
+
/* ─── 批量查询 ─── */
|
|
96
|
+
/** 获取所有活跃记忆 (未过期) */
|
|
97
|
+
async getAllActive(filters = {}) {
|
|
98
|
+
const now = new Date().toISOString();
|
|
99
|
+
const conditions = [or(isNull(this.table.expiresAt), sql `${this.table.expiresAt} > ${now}`)];
|
|
100
|
+
if (filters.source) {
|
|
101
|
+
conditions.push(eq(this.table.source, filters.source));
|
|
102
|
+
}
|
|
103
|
+
if (filters.type) {
|
|
104
|
+
conditions.push(eq(this.table.type, filters.type));
|
|
105
|
+
}
|
|
106
|
+
const rows = this.drizzle
|
|
107
|
+
.select()
|
|
108
|
+
.from(this.table)
|
|
109
|
+
.where(and(...conditions))
|
|
110
|
+
.orderBy(desc(this.table.updatedAt))
|
|
111
|
+
.all();
|
|
112
|
+
return rows.map((r) => this.#mapRow(r));
|
|
113
|
+
}
|
|
114
|
+
/** 获取候选记忆 (用于相似度搜索) */
|
|
115
|
+
async getCandidates(type, limit = 50) {
|
|
116
|
+
const now = new Date().toISOString();
|
|
117
|
+
const conditions = [or(isNull(this.table.expiresAt), sql `${this.table.expiresAt} > ${now}`)];
|
|
118
|
+
if (type) {
|
|
119
|
+
conditions.push(eq(this.table.type, type));
|
|
120
|
+
}
|
|
121
|
+
const rows = this.drizzle
|
|
122
|
+
.select()
|
|
123
|
+
.from(this.table)
|
|
124
|
+
.where(and(...conditions))
|
|
125
|
+
.orderBy(desc(this.table.updatedAt))
|
|
126
|
+
.limit(limit)
|
|
127
|
+
.all();
|
|
128
|
+
return rows.map((r) => this.#mapRow(r));
|
|
129
|
+
}
|
|
130
|
+
/** 记忆总数 */
|
|
131
|
+
async size(filters = {}) {
|
|
132
|
+
const condition = filters.source ? eq(this.table.source, filters.source) : undefined;
|
|
133
|
+
const [row] = this.drizzle.select({ cnt: count() }).from(this.table).where(condition).all();
|
|
134
|
+
return row?.cnt ?? 0;
|
|
135
|
+
}
|
|
136
|
+
/* ─── 维护 ─── */
|
|
137
|
+
/**
|
|
138
|
+
* 执行维护: 清理过期记忆 + 自然遗忘 + 重要度衰减
|
|
139
|
+
*/
|
|
140
|
+
async compact() {
|
|
141
|
+
const stats = { expired: 0, forgotten: 0, archived: 0, remaining: 0 };
|
|
142
|
+
const now = new Date().toISOString();
|
|
143
|
+
const nowMs = Date.now();
|
|
144
|
+
this.transaction(() => {
|
|
145
|
+
// 清理过期
|
|
146
|
+
const expiredResult = this.drizzle
|
|
147
|
+
.delete(this.table)
|
|
148
|
+
.where(and(sql `${this.table.expiresAt} IS NOT NULL`, sql `${this.table.expiresAt} < ${now}`))
|
|
149
|
+
.run();
|
|
150
|
+
stats.expired = expiredResult.changes;
|
|
151
|
+
// 自然遗忘: 90 天未访问 + importance < 7
|
|
152
|
+
const forgetThreshold = new Date(nowMs - FORGET_DAYS * 86400_000).toISOString();
|
|
153
|
+
const forgottenResult = this.drizzle
|
|
154
|
+
.delete(this.table)
|
|
155
|
+
.where(and(sql `${this.table.lastAccessedAt} < ${forgetThreshold}`, sql `${this.table.importance} < 7`))
|
|
156
|
+
.run();
|
|
157
|
+
stats.forgotten = forgottenResult.changes;
|
|
158
|
+
// 30 天未访问 + importance < 3 → 衰减
|
|
159
|
+
const archiveThreshold = new Date(nowMs - ARCHIVE_DAYS * 86400_000).toISOString();
|
|
160
|
+
const archiveResult = this.drizzle
|
|
161
|
+
.update(this.table)
|
|
162
|
+
.set({
|
|
163
|
+
importance: sql `MAX(1, ${this.table.importance} - 1)`,
|
|
164
|
+
})
|
|
165
|
+
.where(and(sql `${this.table.lastAccessedAt} < ${archiveThreshold}`, sql `${this.table.importance} < 3`))
|
|
166
|
+
.run();
|
|
167
|
+
stats.archived = archiveResult.changes;
|
|
168
|
+
// 剩余数量
|
|
169
|
+
const [row] = this.drizzle.select({ cnt: count() }).from(this.table).all();
|
|
170
|
+
stats.remaining = row?.cnt ?? 0;
|
|
171
|
+
});
|
|
172
|
+
return stats;
|
|
173
|
+
}
|
|
174
|
+
/** 容量控制 */
|
|
175
|
+
async enforceCapacity(maxMemories = MAX_MEMORIES) {
|
|
176
|
+
const currentSize = await this.size();
|
|
177
|
+
if (currentSize <= maxMemories) {
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
const excess = currentSize - maxMemories;
|
|
181
|
+
const result = this.drizzle
|
|
182
|
+
.delete(this.table)
|
|
183
|
+
.where(sql `${this.table.id} IN (
|
|
184
|
+
SELECT ${this.table.id} FROM ${this.table}
|
|
185
|
+
ORDER BY ${this.table.importance} ASC,
|
|
186
|
+
${this.table.accessCount} ASC,
|
|
187
|
+
${this.table.updatedAt} ASC
|
|
188
|
+
LIMIT ${excess}
|
|
189
|
+
)`)
|
|
190
|
+
.run();
|
|
191
|
+
return result.changes;
|
|
192
|
+
}
|
|
193
|
+
/* ─── 统计 ─── */
|
|
194
|
+
async getStats() {
|
|
195
|
+
const [totalRow] = this.drizzle.select({ cnt: count() }).from(this.table).all();
|
|
196
|
+
const total = totalRow?.cnt ?? 0;
|
|
197
|
+
const byTypeRows = this.drizzle
|
|
198
|
+
.select({
|
|
199
|
+
type: this.table.type,
|
|
200
|
+
cnt: count(),
|
|
201
|
+
})
|
|
202
|
+
.from(this.table)
|
|
203
|
+
.groupBy(this.table.type)
|
|
204
|
+
.all();
|
|
205
|
+
const bySourceRows = this.drizzle
|
|
206
|
+
.select({
|
|
207
|
+
source: this.table.source,
|
|
208
|
+
cnt: count(),
|
|
209
|
+
})
|
|
210
|
+
.from(this.table)
|
|
211
|
+
.groupBy(this.table.source)
|
|
212
|
+
.all();
|
|
213
|
+
const [avgRow] = this.drizzle
|
|
214
|
+
.select({ avg: avg(this.table.importance) })
|
|
215
|
+
.from(this.table)
|
|
216
|
+
.all();
|
|
217
|
+
const avgImportance = avgRow?.avg ? Math.round(Number(avgRow.avg) * 10) / 10 : 0;
|
|
218
|
+
return {
|
|
219
|
+
total,
|
|
220
|
+
byType: Object.fromEntries(byTypeRows.map((r) => [r.type, r.cnt])),
|
|
221
|
+
bySource: Object.fromEntries(bySourceRows.map((r) => [r.source, r.cnt])),
|
|
222
|
+
avgImportance,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/** 清除所有 bootstrap 来源的记忆 */
|
|
226
|
+
async clearBootstrapMemories() {
|
|
227
|
+
const result = this.drizzle.delete(this.table).where(eq(this.table.source, 'bootstrap')).run();
|
|
228
|
+
return result.changes;
|
|
229
|
+
}
|
|
230
|
+
/* ─── 内部辅助 ─── */
|
|
231
|
+
#mapRow(row) {
|
|
232
|
+
return {
|
|
233
|
+
id: row.id,
|
|
234
|
+
type: row.type,
|
|
235
|
+
content: row.content,
|
|
236
|
+
source: row.source,
|
|
237
|
+
importance: row.importance,
|
|
238
|
+
accessCount: row.accessCount,
|
|
239
|
+
lastAccessedAt: row.lastAccessedAt ?? null,
|
|
240
|
+
createdAt: row.createdAt,
|
|
241
|
+
updatedAt: row.updatedAt,
|
|
242
|
+
expiresAt: row.expiresAt ?? null,
|
|
243
|
+
relatedEntities: safeParseJSON(row.relatedEntities, []),
|
|
244
|
+
relatedMemories: safeParseJSON(row.relatedMemories, []),
|
|
245
|
+
sourceDimension: row.sourceDimension ?? null,
|
|
246
|
+
sourceEvidence: row.sourceEvidence ?? null,
|
|
247
|
+
bootstrapSession: row.bootstrapSession ?? null,
|
|
248
|
+
tags: safeParseJSON(row.tags, []),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/* ═══ 辅助函数 ═══ */
|
|
253
|
+
function safeParseJSON(str, fallback) {
|
|
254
|
+
try {
|
|
255
|
+
return str ? JSON.parse(str) : fallback;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return fallback;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchRepoAdapter — SearchEngine 用的轻量级仓储适配器
|
|
3
|
+
*
|
|
4
|
+
* 当完整的 KnowledgeRepositoryImpl / RecipeSourceRefRepositoryImpl 不可用时
|
|
5
|
+
* (例如单元测试中只传入 raw db),SearchEngine 自动使用这些适配器。
|
|
6
|
+
* 放在 lib/repository/ 下,允许使用 raw SQL(lint 白名单目录)。
|
|
7
|
+
*/
|
|
8
|
+
import type { SearchDb } from '../../service/search/SearchTypes.js';
|
|
9
|
+
/** 解包 DatabaseConnection → raw SearchDb(若已是 raw db 则直接返回) */
|
|
10
|
+
export declare function unwrapSearchDb(db: SearchDb & {
|
|
11
|
+
getDb?: () => SearchDb;
|
|
12
|
+
}): SearchDb;
|
|
13
|
+
/**
|
|
14
|
+
* 通用 db 解包:接受 raw db 或 { getDb() } wrapper,返回 raw db。
|
|
15
|
+
* 可用于 SearchDb、DatabaseLike 等不同 db 类型的构造函数。
|
|
16
|
+
*/
|
|
17
|
+
export declare function unwrapRawDb<T>(db: T | (T & {
|
|
18
|
+
getDb(): T;
|
|
19
|
+
})): T;
|
|
20
|
+
/** SearchEngine 需要的 KnowledgeRepo 最小接口 */
|
|
21
|
+
export interface SearchKnowledgeRepo {
|
|
22
|
+
findNonDeprecatedSync(): Record<string, unknown>[];
|
|
23
|
+
keywordSearchSync(pattern: string, limit: number): Record<string, unknown>[];
|
|
24
|
+
findByIdsDetailSync(ids: string[]): Record<string, unknown>[];
|
|
25
|
+
findUpdatedSinceSync(sinceIso: string): Record<string, unknown>[];
|
|
26
|
+
}
|
|
27
|
+
/** SearchEngine 需要的 SourceRefRepo 最小接口 */
|
|
28
|
+
export interface SearchSourceRefRepo {
|
|
29
|
+
findActiveByRecipeIds(ids: string[]): Array<{
|
|
30
|
+
recipeId: string;
|
|
31
|
+
sourcePath: string;
|
|
32
|
+
status: string;
|
|
33
|
+
newPath: string | null;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Raw-db 适配器:实现 SearchKnowledgeRepo 接口
|
|
38
|
+
* 仅在 KnowledgeRepositoryImpl 不可用时降级使用。
|
|
39
|
+
*/
|
|
40
|
+
export declare class RawDbKnowledgeAdapter implements SearchKnowledgeRepo {
|
|
41
|
+
#private;
|
|
42
|
+
constructor(db: SearchDb);
|
|
43
|
+
findNonDeprecatedSync(): import("../../service/search/SearchTypes.js").DbRow[];
|
|
44
|
+
keywordSearchSync(pattern: string, limit: number): import("../../service/search/SearchTypes.js").DbRow[];
|
|
45
|
+
findByIdsDetailSync(ids: string[]): import("../../service/search/SearchTypes.js").DbRow[];
|
|
46
|
+
findUpdatedSinceSync(sinceIso: string): import("../../service/search/SearchTypes.js").DbRow[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Raw-db 适配器:实现 SearchSourceRefRepo 接口
|
|
50
|
+
* 仅在 RecipeSourceRefRepositoryImpl 不可用时降级使用。
|
|
51
|
+
*/
|
|
52
|
+
export declare class RawDbSourceRefAdapter implements SearchSourceRefRepo {
|
|
53
|
+
#private;
|
|
54
|
+
constructor(db: SearchDb);
|
|
55
|
+
findActiveByRecipeIds(ids: string[]): {
|
|
56
|
+
recipeId: string;
|
|
57
|
+
sourcePath: string;
|
|
58
|
+
status: string;
|
|
59
|
+
newPath: string | null;
|
|
60
|
+
}[];
|
|
61
|
+
}
|
|
62
|
+
/** GuardCheckEngine 需要的 KnowledgeRepo 最小接口 */
|
|
63
|
+
export interface GuardKnowledgeRepo {
|
|
64
|
+
findGuardRulesSync(lifecycles: readonly string[]): Record<string, unknown>[];
|
|
65
|
+
incrementGuardHitsSync(id: string, hits: number): void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Raw-db 适配器:实现 GuardKnowledgeRepo 接口
|
|
69
|
+
* 仅在 KnowledgeRepositoryImpl 不可用时降级使用。
|
|
70
|
+
*/
|
|
71
|
+
export declare class RawDbGuardAdapter implements GuardKnowledgeRepo {
|
|
72
|
+
#private;
|
|
73
|
+
constructor(db: {
|
|
74
|
+
prepare(sql: string): {
|
|
75
|
+
all(...args: unknown[]): Record<string, unknown>[];
|
|
76
|
+
run(...args: unknown[]): unknown;
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
findGuardRulesSync(lifecycles: readonly string[]): Record<string, unknown>[];
|
|
80
|
+
incrementGuardHitsSync(id: string, hits: number): void;
|
|
81
|
+
}
|
|
82
|
+
/** 从 raw db 查询非 deprecated 的基本条目信息(SyncCoordinator 对账用) */
|
|
83
|
+
export declare function queryNonDeprecatedEntries(db: {
|
|
84
|
+
prepare(sql: string): {
|
|
85
|
+
all(): Array<Record<string, unknown>>;
|
|
86
|
+
};
|
|
87
|
+
}): Array<{
|
|
88
|
+
id: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
content?: string;
|
|
91
|
+
kind?: string;
|
|
92
|
+
}>;
|