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.
Files changed (211) hide show
  1. package/README.md +1 -0
  2. package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
  3. package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
  4. package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
  5. package/dashboard/dist/index.html +3 -3
  6. package/dist/bin/cli.js +7 -4
  7. package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
  8. package/dist/lib/agent/core/LoopContext.d.ts +1 -0
  9. package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
  10. package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
  11. package/dist/lib/agent/memory/ActiveContext.js +0 -2
  12. package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
  13. package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
  14. package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
  15. package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
  16. package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
  17. package/dist/lib/agent/memory/MemoryStore.js +196 -261
  18. package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
  19. package/dist/lib/agent/memory/PersistentMemory.js +4 -5
  20. package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
  21. package/dist/lib/agent/memory/SessionStore.js +0 -2
  22. package/dist/lib/agent/tools/ast-graph.js +21 -19
  23. package/dist/lib/agent/tools/infrastructure.js +3 -2
  24. package/dist/lib/agent/tools/project-access.d.ts +2 -2
  25. package/dist/lib/agent/tools/project-access.js +5 -4
  26. package/dist/lib/bootstrap.js +2 -1
  27. package/dist/lib/cli/AiScanService.js +4 -17
  28. package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
  29. package/dist/lib/cli/KnowledgeSyncService.js +23 -51
  30. package/dist/lib/core/ast/ProjectGraph.js +5 -27
  31. package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +0 -2
  32. package/dist/lib/core/discovery/CustomConfigDiscoverer.js +0 -2
  33. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
  34. package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
  35. package/dist/lib/domain/dimension/DimensionSop.js +44 -33
  36. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
  37. package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
  38. package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
  39. package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
  40. package/dist/lib/domain/knowledge/index.d.ts +2 -1
  41. package/dist/lib/domain/knowledge/index.js +1 -1
  42. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
  43. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
  44. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +33 -16
  45. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
  46. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
  47. package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -1
  48. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +7 -3
  49. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
  50. package/dist/lib/external/mcp/handlers/evolve-external.js +13 -16
  51. package/dist/lib/external/mcp/handlers/guard.js +15 -24
  52. package/dist/lib/external/mcp/handlers/panorama.js +9 -9
  53. package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
  54. package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
  55. package/dist/lib/external/mcp/handlers/search.js +3 -1
  56. package/dist/lib/external/mcp/handlers/skill.js +4 -4
  57. package/dist/lib/external/mcp/handlers/structure.js +8 -12
  58. package/dist/lib/external/mcp/handlers/system.js +10 -34
  59. package/dist/lib/http/routes/ai.js +11 -13
  60. package/dist/lib/http/routes/guardReport.js +3 -5
  61. package/dist/lib/http/routes/panorama.js +12 -12
  62. package/dist/lib/http/routes/recipes.js +59 -8
  63. package/dist/lib/http/routes/remote.js +3 -13
  64. package/dist/lib/http/routes/search.js +11 -8
  65. package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
  66. package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
  67. package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
  68. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
  69. package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
  70. package/dist/lib/injection/ServiceContainer.js +7 -4
  71. package/dist/lib/injection/ServiceMap.d.ts +20 -0
  72. package/dist/lib/injection/modules/AppModule.js +2 -1
  73. package/dist/lib/injection/modules/GuardModule.js +5 -5
  74. package/dist/lib/injection/modules/InfraModule.js +60 -0
  75. package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
  76. package/dist/lib/injection/modules/PanoramaModule.js +16 -10
  77. package/dist/lib/injection/modules/VectorModule.js +3 -0
  78. package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
  79. package/dist/lib/repository/audit/AuditRepository.js +272 -0
  80. package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
  81. package/dist/lib/repository/base/RepositoryBase.js +32 -0
  82. package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
  83. package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
  84. package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
  85. package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
  86. package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
  87. package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
  88. package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
  89. package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
  90. package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
  91. package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
  92. package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
  93. package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
  94. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
  95. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
  96. package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
  97. package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
  98. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
  99. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
  100. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
  101. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
  102. package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
  103. package/dist/lib/repository/memory/MemoryRepository.js +260 -0
  104. package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
  105. package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
  106. package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
  107. package/dist/lib/repository/session/SessionRepository.js +110 -0
  108. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
  109. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
  110. package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
  111. package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
  112. package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
  113. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
  114. package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
  115. package/dist/lib/service/cleanup/CleanupService.js +8 -4
  116. package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
  117. package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
  118. package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
  119. package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
  120. package/dist/lib/service/evolution/ContentPatcher.js +48 -19
  121. package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
  122. package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
  123. package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
  124. package/dist/lib/service/evolution/DecayDetector.js +63 -57
  125. package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
  126. package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
  127. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
  128. package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
  129. package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
  130. package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
  131. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
  132. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
  133. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
  134. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
  135. package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
  136. package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
  137. package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
  138. package/dist/lib/service/evolution/StagingManager.js +37 -95
  139. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
  140. package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
  141. package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
  142. package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
  143. package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
  144. package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
  145. package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
  146. package/dist/lib/service/guard/ReverseGuard.js +21 -31
  147. package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
  148. package/dist/lib/service/guard/ViolationsStore.js +75 -69
  149. package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +39 -63
  150. package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -512
  151. package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
  152. package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
  153. package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
  154. package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
  155. package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
  156. package/dist/lib/service/knowledge/KnowledgeService.js +76 -38
  157. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
  158. package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
  159. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
  160. package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
  161. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +5 -3
  162. package/dist/lib/service/panorama/CouplingAnalyzer.js +102 -39
  163. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
  164. package/dist/lib/service/panorama/DimensionAnalyzer.js +72 -25
  165. package/dist/lib/service/panorama/LayerInferrer.js +1 -1
  166. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +7 -6
  167. package/dist/lib/service/panorama/ModuleDiscoverer.js +174 -82
  168. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +10 -3
  169. package/dist/lib/service/panorama/PanoramaAggregator.js +67 -79
  170. package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
  171. package/dist/lib/service/panorama/PanoramaScanner.js +32 -31
  172. package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
  173. package/dist/lib/service/panorama/PanoramaService.js +41 -66
  174. package/dist/lib/service/panorama/PanoramaTypes.d.ts +3 -0
  175. package/dist/lib/service/panorama/RoleRefiner.d.ts +8 -5
  176. package/dist/lib/service/panorama/RoleRefiner.js +52 -283
  177. package/dist/lib/service/panorama/TechStackProfiler.js +7 -119
  178. package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
  179. package/dist/lib/service/quality/QualityScorer.js +157 -83
  180. package/dist/lib/service/search/SearchEngine.d.ts +1 -0
  181. package/dist/lib/service/search/SearchEngine.js +32 -37
  182. package/dist/lib/service/signal/HitRecorder.js +5 -5
  183. package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
  184. package/dist/lib/service/skills/SignalCollector.d.ts +5 -8
  185. package/dist/lib/service/skills/SignalCollector.js +28 -55
  186. package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
  187. package/dist/lib/service/skills/SkillAdvisor.js +30 -79
  188. package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
  189. package/dist/lib/service/vector/SyncCoordinator.js +25 -3
  190. package/dist/lib/service/vector/VectorService.d.ts +2 -0
  191. package/dist/lib/service/vector/VectorService.js +3 -0
  192. package/dist/lib/service/wiki/WikiGenerator.js +1 -1
  193. package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
  194. package/dist/lib/shared/LanguageProfiles.js +939 -0
  195. package/dist/lib/shared/LanguageService.d.ts +6 -0
  196. package/dist/lib/shared/LanguageService.js +16 -0
  197. package/dist/lib/shared/constants.d.ts +19 -19
  198. package/dist/lib/shared/constants.js +10 -10
  199. package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
  200. package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
  201. package/dist/lib/types/project-snapshot-builder.js +0 -1
  202. package/dist/lib/types/project-snapshot.d.ts +0 -1
  203. package/dist/lib/types/project-snapshot.js +0 -1
  204. package/dist/lib/types/snapshot-views.d.ts +0 -2
  205. package/dist/lib/types/snapshot-views.js +0 -1
  206. package/package.json +2 -1
  207. package/dashboard/dist/assets/icons-FHns2ypa.js +0 -1
  208. package/dashboard/dist/assets/index-BRJv5Y3r.js +0 -135
  209. package/dashboard/dist/assets/index-DzoB7kxK.css +0 -1
  210. package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
  211. package/dist/lib/repository/base/BaseRepository.js +0 -226
@@ -1,10 +1,8 @@
1
1
  /**
2
- * MemoryStore — 持久化记忆 SQLite 存储层
2
+ * MemoryStore — 持久化记忆 SQLite 存储层(Drizzle 类型安全版)
3
3
  *
4
4
  * 从 PersistentMemory.js 提取的 CRUD + SQL 基础设施。
5
5
  * 负责:
6
- * - 表结构确保 (#ensureTable)
7
- * - SQL 预编译 (#prepareStatements)
8
6
  * - 基本 CRUD: add, update, delete, get
9
7
  * - 批量查询: getAllActive, size, getStats
10
8
  * - 访问计数: touchAccess
@@ -13,13 +11,18 @@
13
11
  * - 统计: getStats, clearBootstrapMemories
14
12
  *
15
13
  * 设计原则:
16
- * - 拥有 #db #stmts,其他组件通过 MemoryStore 访问数据
17
- * - update() 使用动态 SQL 但通过 named parameters 防注入
14
+ * - 大部分操作通过 Drizzle 类型安全 API
15
+ * - update() 使用 Drizzle 类型安全 partial update
16
+ * - embedding 已迁移至 MemoryEmbeddingStore (JSON sidecar)
18
17
  * - 数据序列化/反序列化统一在此层处理
19
18
  *
20
19
  * @module MemoryStore
21
20
  */
22
21
  import { randomUUID } from 'node:crypto';
22
+ import { and, avg, count, desc, eq, isNull, lt, or, sql } from 'drizzle-orm';
23
+ import { drizzle } from 'drizzle-orm/better-sqlite3';
24
+ import * as schema from '#infra/database/drizzle/schema.js';
25
+ import { semanticMemories } from '#infra/database/drizzle/schema.js';
23
26
  import { jaccardSimilarity, tokenizeForSimilarity } from '#shared/similarity.js';
24
27
  // ─── 常量 ──────────────────────────────────────────────
25
28
  /** 最大记忆条数 (防止无限膨胀) */
@@ -29,20 +32,40 @@ const ARCHIVE_DAYS = 30;
29
32
  const FORGET_DAYS = 90;
30
33
  export class MemoryStore {
31
34
  #db;
32
- /** 预编译 SQL Statements */
33
- #stmts = null;
34
- /** 动态 update SQL 缓存 */
35
- #updateStmtCache = new Map();
35
+ #drizzle;
36
36
  /** @param db better-sqlite3 实例 (raw) */
37
37
  constructor(db) {
38
38
  this.#db = db;
39
+ this.#drizzle = drizzle(db, { schema });
39
40
  this.#ensureTable();
40
- this.#prepareStatements();
41
41
  }
42
42
  /** 获取原始 db 引用 (for transaction) */
43
43
  get db() {
44
44
  return this.#db;
45
45
  }
46
+ /** 确保表存在 (兼容 :memory: 测试 DB) */
47
+ #ensureTable() {
48
+ this.#db.exec(`
49
+ CREATE TABLE IF NOT EXISTS semantic_memories (
50
+ id TEXT PRIMARY KEY,
51
+ type TEXT NOT NULL DEFAULT 'fact',
52
+ content TEXT NOT NULL DEFAULT '',
53
+ source TEXT NOT NULL DEFAULT 'bootstrap',
54
+ importance REAL NOT NULL DEFAULT 5.0,
55
+ access_count INTEGER NOT NULL DEFAULT 0,
56
+ last_accessed_at TEXT,
57
+ created_at TEXT NOT NULL,
58
+ updated_at TEXT NOT NULL,
59
+ expires_at TEXT,
60
+ related_entities TEXT DEFAULT '[]',
61
+ related_memories TEXT DEFAULT '[]',
62
+ source_dimension TEXT,
63
+ source_evidence TEXT,
64
+ bootstrap_session TEXT,
65
+ tags TEXT DEFAULT '[]'
66
+ )
67
+ `);
68
+ }
46
69
  // ═══════════════════════════════════════════════════════════
47
70
  // 基本 CRUD
48
71
  // ═══════════════════════════════════════════════════════════
@@ -58,85 +81,81 @@ export class MemoryStore {
58
81
  const expiresAt = memory.ttlDays
59
82
  ? new Date(Date.now() + memory.ttlDays * 86400_000).toISOString()
60
83
  : null;
61
- this.#stmts.insert.run({
84
+ this.#drizzle
85
+ .insert(semanticMemories)
86
+ .values({
62
87
  id,
63
88
  type: memory.type || 'fact',
64
89
  content,
65
90
  source: memory.source || 'bootstrap',
66
91
  importance,
67
- access_count: 0,
68
- last_accessed_at: now,
69
- created_at: now,
70
- updated_at: now,
71
- expires_at: expiresAt,
72
- related_entities: JSON.stringify(memory.relatedEntities || []),
73
- related_memories: JSON.stringify([]),
74
- source_dimension: memory.sourceDimension || null,
75
- source_evidence: memory.sourceEvidence || null,
76
- bootstrap_session: memory.bootstrapSession || null,
92
+ accessCount: 0,
93
+ lastAccessedAt: now,
94
+ createdAt: now,
95
+ updatedAt: now,
96
+ expiresAt,
97
+ relatedEntities: JSON.stringify(memory.relatedEntities || []),
98
+ relatedMemories: JSON.stringify([]),
99
+ sourceDimension: memory.sourceDimension || null,
100
+ sourceEvidence: memory.sourceEvidence || null,
101
+ bootstrapSession: memory.bootstrapSession || null,
77
102
  tags: JSON.stringify(memory.tags || []),
78
- embedding: memory.embedding ? MemoryStore.serializeEmbedding(memory.embedding) : null,
79
- });
103
+ })
104
+ .run();
80
105
  return { id, action: 'ADD' };
81
106
  }
82
- /** 更新已有记忆 */
107
+ /**
108
+ * 更新已有记忆
109
+ */
83
110
  update(id, updates) {
84
- const existing = this.#stmts.getById.get(id);
111
+ const existing = this.#drizzle
112
+ .select({ id: semanticMemories.id })
113
+ .from(semanticMemories)
114
+ .where(eq(semanticMemories.id, id))
115
+ .get();
85
116
  if (!existing) {
86
117
  return false;
87
118
  }
88
119
  const now = new Date().toISOString();
89
- const fields = [];
90
- const params = { id };
120
+ const setFields = {};
91
121
  if (updates.content !== undefined) {
92
- fields.push('content = @content');
93
- params.content = updates.content.substring(0, 500);
122
+ setFields.content = updates.content.substring(0, 500);
94
123
  }
95
124
  if (updates.importance !== undefined) {
96
- fields.push('importance = @importance');
97
- params.importance = Math.max(1, Math.min(10, updates.importance));
125
+ setFields.importance = Math.max(1, Math.min(10, updates.importance));
98
126
  }
99
127
  if (updates.accessCount !== undefined) {
100
- fields.push('access_count = @access_count');
101
- params.access_count = updates.accessCount;
128
+ setFields.accessCount = updates.accessCount;
102
129
  }
103
130
  if (updates.relatedEntities !== undefined) {
104
- fields.push('related_entities = @related_entities');
105
- params.related_entities = JSON.stringify(updates.relatedEntities);
131
+ setFields.relatedEntities = JSON.stringify(updates.relatedEntities);
106
132
  }
107
133
  if (updates.relatedMemories !== undefined) {
108
- fields.push('related_memories = @related_memories');
109
- params.related_memories = JSON.stringify(updates.relatedMemories);
134
+ setFields.relatedMemories = JSON.stringify(updates.relatedMemories);
110
135
  }
111
136
  if (updates.tags !== undefined) {
112
- fields.push('tags = @tags');
113
- params.tags = JSON.stringify(updates.tags);
137
+ setFields.tags = JSON.stringify(updates.tags);
114
138
  }
115
- if (fields.length === 0) {
139
+ if (Object.keys(setFields).length === 0) {
116
140
  return false;
117
141
  }
118
- fields.push('updated_at = @updated_at');
119
- params.updated_at = now;
120
- // 使用缓存的 prepared statement,避免每次 update 都 prepare 新 SQL
121
- const cacheKey = fields.join(',');
122
- let stmt = this.#updateStmtCache.get(cacheKey);
123
- if (!stmt) {
124
- const sql = `UPDATE semantic_memories SET ${fields.join(', ')} WHERE id = @id`;
125
- stmt = this.#db.prepare(sql);
126
- this.#updateStmtCache.set(cacheKey, stmt);
127
- }
128
- stmt.run(params);
142
+ setFields.updatedAt = now;
143
+ this.#drizzle.update(semanticMemories).set(setFields).where(eq(semanticMemories.id, id)).run();
129
144
  return true;
130
145
  }
131
146
  /** 删除一条记忆 */
132
147
  delete(id) {
133
- const result = this.#stmts.deleteById.run(id);
134
- return result.changes > 0;
148
+ const result = this.#drizzle.delete(semanticMemories).where(eq(semanticMemories.id, id)).run();
149
+ return (result.changes ?? 0) > 0;
135
150
  }
136
151
  /** 按 ID 获取 */
137
152
  get(id) {
138
- const row = this.#stmts.getById.get(id);
139
- return row ? MemoryStore.deserialize(row) : null;
153
+ const row = this.#drizzle
154
+ .select()
155
+ .from(semanticMemories)
156
+ .where(eq(semanticMemories.id, id))
157
+ .get();
158
+ return row ? MemoryStore.deserialize(MemoryStore.#toRow(row)) : null;
140
159
  }
141
160
  // ═══════════════════════════════════════════════════════════
142
161
  // 批量查询
@@ -147,32 +166,50 @@ export class MemoryStore {
147
166
  */
148
167
  getAllActive({ source, type } = {}) {
149
168
  const now = new Date().toISOString();
150
- if (source && type) {
151
- return this.#stmts.getAllActiveBySourceAndType.all({
152
- now,
153
- source,
154
- type,
155
- });
156
- }
169
+ const notExpired = or(isNull(semanticMemories.expiresAt), sql `${semanticMemories.expiresAt} > ${now}`);
170
+ const conditions = [notExpired];
157
171
  if (source) {
158
- return this.#stmts.getAllActiveBySource.all({ now, source });
172
+ conditions.push(eq(semanticMemories.source, source));
159
173
  }
160
174
  if (type) {
161
- return this.#stmts.getAllActiveByType.all({ now, type });
175
+ conditions.push(eq(semanticMemories.type, type));
162
176
  }
163
- return this.#stmts.getAllActive.all({ now });
177
+ const rows = this.#drizzle
178
+ .select()
179
+ .from(semanticMemories)
180
+ .where(and(...conditions))
181
+ .orderBy(desc(semanticMemories.updatedAt))
182
+ .all();
183
+ return rows.map(MemoryStore.#toRow);
164
184
  }
165
185
  /** 获取候选记忆 (用于相似度搜索) */
166
186
  getCandidates(type) {
167
187
  const now = new Date().toISOString();
168
- return (type
169
- ? this.#stmts.getByContent.all({ type, now })
170
- : this.#stmts.getAll.all({ now }));
188
+ const notExpired = or(isNull(semanticMemories.expiresAt), sql `${semanticMemories.expiresAt} > ${now}`);
189
+ const conditions = [notExpired];
190
+ if (type) {
191
+ conditions.push(eq(semanticMemories.type, type));
192
+ }
193
+ const rows = this.#drizzle
194
+ .select()
195
+ .from(semanticMemories)
196
+ .where(and(...conditions))
197
+ .orderBy(desc(semanticMemories.updatedAt))
198
+ .limit(50)
199
+ .all();
200
+ return rows.map(MemoryStore.#toRow);
171
201
  }
172
202
  /** 更新访问计数 */
173
203
  touchAccess(id) {
174
204
  try {
175
- this.#stmts.touchAccess.run({ id, now: new Date().toISOString() });
205
+ this.#drizzle
206
+ .update(semanticMemories)
207
+ .set({
208
+ accessCount: sql `${semanticMemories.accessCount} + 1`,
209
+ lastAccessedAt: new Date().toISOString(),
210
+ })
211
+ .where(eq(semanticMemories.id, id))
212
+ .run();
176
213
  }
177
214
  catch {
178
215
  /* non-critical */
@@ -180,12 +217,13 @@ export class MemoryStore {
180
217
  }
181
218
  /** 记忆总数 */
182
219
  size({ source } = {}) {
183
- if (source) {
184
- return (this.#db
185
- .prepare('SELECT COUNT(*) as cnt FROM semantic_memories WHERE source = ?')
186
- .get(source)?.cnt || 0);
187
- }
188
- return (this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0);
220
+ const condition = source ? eq(semanticMemories.source, source) : undefined;
221
+ const [row] = this.#drizzle
222
+ .select({ cnt: count() })
223
+ .from(semanticMemories)
224
+ .where(condition)
225
+ .all();
226
+ return row?.cnt ?? 0;
189
227
  }
190
228
  // ═══════════════════════════════════════════════════════════
191
229
  // 维护
@@ -198,54 +236,79 @@ export class MemoryStore {
198
236
  const now = new Date().toISOString();
199
237
  const nowMs = Date.now();
200
238
  const stats = { expired: 0, forgotten: 0, archived: 0, remaining: 0 };
201
- const runCompact = this.#db.transaction(() => {
202
- const expiredResult = this.#db
203
- .prepare('DELETE FROM semantic_memories WHERE expires_at IS NOT NULL AND expires_at < ?')
204
- .run(now);
205
- stats.expired = expiredResult.changes;
239
+ this.#drizzle.transaction((tx) => {
240
+ // 清除已过期
241
+ const expiredResult = tx
242
+ .delete(semanticMemories)
243
+ .where(and(sql `${semanticMemories.expiresAt} IS NOT NULL`, lt(semanticMemories.expiresAt, now)))
244
+ .run();
245
+ stats.expired = expiredResult.changes ?? 0;
246
+ // 遗忘:长期未访问且不重要的
206
247
  const forgetThreshold = new Date(nowMs - FORGET_DAYS * 86400_000).toISOString();
207
- const forgottenResult = this.#db
208
- .prepare('DELETE FROM semantic_memories WHERE last_accessed_at < ? AND importance < 7')
209
- .run(forgetThreshold);
210
- stats.forgotten = forgottenResult.changes;
248
+ const forgottenResult = tx
249
+ .delete(semanticMemories)
250
+ .where(and(lt(semanticMemories.lastAccessedAt, forgetThreshold), lt(semanticMemories.importance, 7)))
251
+ .run();
252
+ stats.forgotten = forgottenResult.changes ?? 0;
253
+ // 归档:降低重要性
211
254
  const archiveThreshold = new Date(nowMs - ARCHIVE_DAYS * 86400_000).toISOString();
212
- const archiveResult = this.#db
213
- .prepare('UPDATE semantic_memories SET importance = MAX(1, importance - 1) WHERE last_accessed_at < ? AND importance < 3')
214
- .run(archiveThreshold);
215
- stats.archived = archiveResult.changes;
216
- stats.remaining =
217
- this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
255
+ const archiveResult = tx
256
+ .update(semanticMemories)
257
+ .set({
258
+ importance: sql `MAX(1, ${semanticMemories.importance} - 1)`,
259
+ })
260
+ .where(and(lt(semanticMemories.lastAccessedAt, archiveThreshold), lt(semanticMemories.importance, 3)))
261
+ .run();
262
+ stats.archived = archiveResult.changes ?? 0;
263
+ const [remainRow] = tx.select({ cnt: count() }).from(semanticMemories).all();
264
+ stats.remaining = remainRow?.cnt ?? 0;
218
265
  });
219
- runCompact();
220
266
  return stats;
221
267
  }
222
268
  /** 容量控制 */
223
269
  enforceCapacity() {
224
- const count = this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
225
- if (count <= MAX_MEMORIES) {
270
+ const [row] = this.#drizzle.select({ cnt: count() }).from(semanticMemories).all();
271
+ const total = row?.cnt ?? 0;
272
+ if (total <= MAX_MEMORIES) {
226
273
  return;
227
274
  }
228
- const excess = count - MAX_MEMORIES;
229
- this.#db
230
- .prepare(`
231
- DELETE FROM semantic_memories WHERE id IN (
232
- SELECT id FROM semantic_memories
233
- ORDER BY importance ASC, access_count ASC, updated_at ASC
234
- LIMIT ?
235
- )
236
- `)
237
- .run(excess);
275
+ const excess = total - MAX_MEMORIES;
276
+ this.#drizzle
277
+ .delete(semanticMemories)
278
+ .where(sql `${semanticMemories.id} IN (
279
+ SELECT ${semanticMemories.id} FROM ${semanticMemories}
280
+ ORDER BY ${semanticMemories.importance} ASC, ${semanticMemories.accessCount} ASC, ${semanticMemories.updatedAt} ASC
281
+ LIMIT ${excess}
282
+ )`)
283
+ .run();
238
284
  }
239
285
  /** 获取统计信息 */
240
286
  getStats() {
241
- const total = this.#db.prepare('SELECT COUNT(*) as cnt FROM semantic_memories').get()?.cnt || 0;
242
- const byType = this.#db
243
- .prepare('SELECT type, COUNT(*) as cnt FROM semantic_memories GROUP BY type')
287
+ const [totalRow] = this.#drizzle.select({ cnt: count() }).from(semanticMemories).all();
288
+ const total = totalRow?.cnt ?? 0;
289
+ const byType = this.#drizzle
290
+ .select({
291
+ type: semanticMemories.type,
292
+ cnt: count(),
293
+ })
294
+ .from(semanticMemories)
295
+ .groupBy(semanticMemories.type)
244
296
  .all();
245
- const bySource = this.#db
246
- .prepare('SELECT source, COUNT(*) as cnt FROM semantic_memories GROUP BY source')
297
+ const bySource = this.#drizzle
298
+ .select({
299
+ source: semanticMemories.source,
300
+ cnt: count(),
301
+ })
302
+ .from(semanticMemories)
303
+ .groupBy(semanticMemories.source)
304
+ .all();
305
+ const [avgRow] = this.#drizzle
306
+ .select({
307
+ avg: avg(semanticMemories.importance),
308
+ })
309
+ .from(semanticMemories)
247
310
  .all();
248
- const avgImportance = this.#db.prepare('SELECT AVG(importance) as avg FROM semantic_memories').get()?.avg || 0;
311
+ const avgImportance = avgRow?.avg ? Number(avgRow.avg) : 0;
249
312
  return {
250
313
  total,
251
314
  byType: Object.fromEntries(byType.map((r) => [r.type, r.cnt])),
@@ -255,10 +318,11 @@ export class MemoryStore {
255
318
  }
256
319
  /** 清除所有 bootstrap 来源的记忆 */
257
320
  clearBootstrapMemories() {
258
- const result = this.#db
259
- .prepare("DELETE FROM semantic_memories WHERE source = 'bootstrap'")
321
+ const result = this.#drizzle
322
+ .delete(semanticMemories)
323
+ .where(eq(semanticMemories.source, 'bootstrap'))
260
324
  .run();
261
- return result.changes;
325
+ return result.changes ?? 0;
262
326
  }
263
327
  // ═══════════════════════════════════════════════════════════
264
328
  // 相似度搜索
@@ -326,7 +390,6 @@ export class MemoryStore {
326
390
  sourceEvidence: row.source_evidence,
327
391
  bootstrapSession: row.bootstrap_session,
328
392
  tags: MemoryStore.safeParseJSON(row.tags, []),
329
- embedding: row.embedding ? MemoryStore.deserializeEmbedding(row.embedding) : null,
330
393
  };
331
394
  }
332
395
  static safeParseJSON(str, fallback) {
@@ -338,155 +401,27 @@ export class MemoryStore {
338
401
  }
339
402
  }
340
403
  // ═══════════════════════════════════════════════════════════
341
- // 向量嵌入存储
404
+ // Private: Drizzle → MemoryRow 映射
342
405
  // ═══════════════════════════════════════════════════════════
343
- /**
344
- * 更新单条记忆的向量嵌入
345
- * @param id 记忆 ID
346
- * @param embedding 向量数组
347
- */
348
- updateEmbedding(id, embedding) {
349
- const blob = MemoryStore.serializeEmbedding(embedding);
350
- const result = this.#db
351
- .prepare('UPDATE semantic_memories SET embedding = ? WHERE id = ?')
352
- .run(blob, id);
353
- return result.changes > 0;
354
- }
355
- /**
356
- * 批量更新向量嵌入
357
- * @param entries Array of { id, embedding }
358
- */
359
- batchUpdateEmbeddings(entries) {
360
- let updated = 0;
361
- const stmt = this.#db.prepare('UPDATE semantic_memories SET embedding = ? WHERE id = ?');
362
- const runBatch = this.#db.transaction(() => {
363
- for (const entry of entries) {
364
- const blob = MemoryStore.serializeEmbedding(entry.embedding);
365
- const result = stmt.run(blob, entry.id);
366
- updated += result.changes;
367
- }
368
- });
369
- runBatch();
370
- return updated;
371
- }
372
- /**
373
- * 获取缺少向量嵌入的记忆 ID 和内容
374
- * @param limit 最大返回数
375
- */
376
- getWithoutEmbedding(limit = 50) {
377
- return this.#db
378
- .prepare('SELECT id, content FROM semantic_memories WHERE embedding IS NULL ORDER BY updated_at DESC LIMIT ?')
379
- .all(limit);
380
- }
381
- /** 将 number[] 序列化为 Buffer (Float32Array → BLOB) */
382
- static serializeEmbedding(embedding) {
383
- const float32 = new Float32Array(embedding);
384
- return Buffer.from(float32.buffer, float32.byteOffset, float32.byteLength);
385
- }
386
- /** 将 Buffer (BLOB) 反序列化为 number[] */
387
- static deserializeEmbedding(blob) {
388
- const float32 = new Float32Array(blob.buffer, blob.byteOffset, blob.byteLength / Float32Array.BYTES_PER_ELEMENT);
389
- return Array.from(float32);
390
- }
391
- // ═══════════════════════════════════════════════════════════
392
- // Private: DB 基础设施
393
- // ═══════════════════════════════════════════════════════════
394
- #ensureTable() {
395
- const exists = this.#db
396
- .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='semantic_memories'")
397
- .get();
398
- if (!exists) {
399
- this.#db.exec(`
400
- CREATE TABLE IF NOT EXISTS semantic_memories (
401
- id TEXT PRIMARY KEY,
402
- type TEXT NOT NULL DEFAULT 'fact',
403
- content TEXT NOT NULL DEFAULT '',
404
- source TEXT NOT NULL DEFAULT 'bootstrap',
405
- importance REAL NOT NULL DEFAULT 5.0,
406
- access_count INTEGER NOT NULL DEFAULT 0,
407
- last_accessed_at TEXT,
408
- created_at TEXT NOT NULL,
409
- updated_at TEXT NOT NULL,
410
- expires_at TEXT,
411
- related_entities TEXT DEFAULT '[]',
412
- related_memories TEXT DEFAULT '[]',
413
- source_dimension TEXT,
414
- source_evidence TEXT,
415
- bootstrap_session TEXT,
416
- tags TEXT DEFAULT '[]',
417
- embedding BLOB
418
- )
419
- `);
420
- }
421
- else {
422
- // 迁移: 为已有表添加 embedding 列
423
- try {
424
- this.#db.prepare('SELECT embedding FROM semantic_memories LIMIT 1').get();
425
- }
426
- catch {
427
- this.#db.exec('ALTER TABLE semantic_memories ADD COLUMN embedding BLOB');
428
- }
429
- }
430
- }
431
- #prepareStatements() {
432
- this.#stmts = {
433
- insert: this.#db.prepare(`
434
- INSERT INTO semantic_memories
435
- (id, type, content, source, importance, access_count,
436
- last_accessed_at, created_at, updated_at, expires_at,
437
- related_entities, related_memories,
438
- source_dimension, source_evidence, bootstrap_session, tags, embedding)
439
- VALUES
440
- (@id, @type, @content, @source, @importance, @access_count,
441
- @last_accessed_at, @created_at, @updated_at, @expires_at,
442
- @related_entities, @related_memories,
443
- @source_dimension, @source_evidence, @bootstrap_session, @tags, @embedding)
444
- `),
445
- getById: this.#db.prepare('SELECT * FROM semantic_memories WHERE id = ?'),
446
- deleteById: this.#db.prepare('DELETE FROM semantic_memories WHERE id = ?'),
447
- touchAccess: this.#db.prepare(`
448
- UPDATE semantic_memories
449
- SET access_count = access_count + 1,
450
- last_accessed_at = @now
451
- WHERE id = @id
452
- `),
453
- getAllActive: this.#db.prepare(`
454
- SELECT * FROM semantic_memories
455
- WHERE (expires_at IS NULL OR expires_at > @now)
456
- ORDER BY updated_at DESC
457
- `),
458
- getAllActiveBySource: this.#db.prepare(`
459
- SELECT * FROM semantic_memories
460
- WHERE (expires_at IS NULL OR expires_at > @now)
461
- AND source = @source
462
- ORDER BY updated_at DESC
463
- `),
464
- getAllActiveByType: this.#db.prepare(`
465
- SELECT * FROM semantic_memories
466
- WHERE (expires_at IS NULL OR expires_at > @now)
467
- AND type = @type
468
- ORDER BY updated_at DESC
469
- `),
470
- getAllActiveBySourceAndType: this.#db.prepare(`
471
- SELECT * FROM semantic_memories
472
- WHERE (expires_at IS NULL OR expires_at > @now)
473
- AND source = @source
474
- AND type = @type
475
- ORDER BY updated_at DESC
476
- `),
477
- getByContent: this.#db.prepare(`
478
- SELECT * FROM semantic_memories
479
- WHERE type = @type
480
- AND (expires_at IS NULL OR expires_at > @now)
481
- ORDER BY updated_at DESC
482
- LIMIT 50
483
- `),
484
- getAll: this.#db.prepare(`
485
- SELECT * FROM semantic_memories
486
- WHERE (expires_at IS NULL OR expires_at > @now)
487
- ORDER BY updated_at DESC
488
- LIMIT 50
489
- `),
406
+ /** Drizzle camelCase row → MemoryRow snake_case (保持向后兼容) */
407
+ static #toRow(row) {
408
+ return {
409
+ id: row.id,
410
+ type: row.type,
411
+ content: row.content,
412
+ source: row.source,
413
+ importance: row.importance,
414
+ access_count: row.accessCount,
415
+ last_accessed_at: row.lastAccessedAt,
416
+ created_at: row.createdAt,
417
+ updated_at: row.updatedAt,
418
+ expires_at: row.expiresAt,
419
+ related_entities: row.relatedEntities ?? '[]',
420
+ related_memories: row.relatedMemories ?? '[]',
421
+ source_dimension: row.sourceDimension,
422
+ source_evidence: row.sourceEvidence,
423
+ bootstrap_session: row.bootstrapSession,
424
+ tags: row.tags ?? '[]',
490
425
  };
491
426
  }
492
427
  }
@@ -21,12 +21,14 @@
21
21
  * @module PersistentMemory
22
22
  */
23
23
  import type { CandidateMemory, ConsolidateOptions, ConsolidateStats } from './MemoryConsolidator.js';
24
+ import type { MemoryEmbeddingStore } from './MemoryEmbeddingStore.js';
24
25
  import type { AppendEntry, EmbeddingFn, LoadOptions, PromptSectionOptions, RetrieveOptions, ScoredMemory } from './MemoryRetriever.js';
25
26
  import type { DeserializedMemory, MemoryInput, MemoryUpdates, SqliteDatabase } from './MemoryStore.js';
26
27
  /** PersistentMemory 构造选项 */
27
28
  export interface PersistentMemoryOptions {
28
29
  logger?: MemoryLogger | null;
29
30
  embeddingFn?: EmbeddingFn;
31
+ embeddingStore?: MemoryEmbeddingStore;
30
32
  }
31
33
  /** Logger 接口 */
32
34
  interface MemoryLogger {
@@ -20,6 +20,7 @@
20
20
  *
21
21
  * @module PersistentMemory
22
22
  */
23
+ import { unwrapRawDb } from '../../repository/search/SearchRepoAdapter.js';
23
24
  import { MemoryConsolidator } from './MemoryConsolidator.js';
24
25
  import { MemoryRetriever } from './MemoryRetriever.js';
25
26
  import { MemoryStore } from './MemoryStore.js';
@@ -30,17 +31,15 @@ export class PersistentMemory {
30
31
  #logger;
31
32
  /** @param db better-sqlite3 实例 */
32
33
  constructor(db, opts = {}) {
33
- const { logger, embeddingFn } = typeof opts === 'object' && opts !== null ? opts : {};
34
+ const { logger, embeddingFn, embeddingStore } = typeof opts === 'object' && opts !== null ? opts : {};
34
35
  if (!db) {
35
36
  throw new Error('PersistentMemory requires a database instance');
36
37
  }
37
- const rawDb = typeof db?.getDb === 'function'
38
- ? db.getDb()
39
- : db;
38
+ const rawDb = unwrapRawDb(db);
40
39
  this.#logger = logger || null;
41
40
  // 组装子模块
42
41
  this.#store = new MemoryStore(rawDb);
43
- this.#retriever = new MemoryRetriever(this.#store, { embeddingFn });
42
+ this.#retriever = new MemoryRetriever(this.#store, { embeddingFn, embeddingStore });
44
43
  this.#consolidator = new MemoryConsolidator(this.#store, { logger: this.#logger });
45
44
  }
46
45
  // ═══════════════════════════════════════════════════════════
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * SessionStore — Bootstrap 会话级存储 (合并 EpisodicMemory + ToolResultCache)
3
3
  *
4
- * 设计来源: docs/copilot/memory-system-redesign.md §4.4, §6.3
5
- *
6
4
  * 内部子系统:
7
5
  * 1. DimensionReports — 跨维度分析报告 + 结构化证据 + 交叉引用 (from EpisodicMemory)
8
6
  * 2. ReadOnlyCache — 只读工具结果缓存 (from ToolResultCache, 排除副作用工具 B3 fix)
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * SessionStore — Bootstrap 会话级存储 (合并 EpisodicMemory + ToolResultCache)
3
3
  *
4
- * 设计来源: docs/copilot/memory-system-redesign.md §4.4, §6.3
5
- *
6
4
  * 内部子系统:
7
5
  * 1. DimensionReports — 跨维度分析报告 + 结构化证据 + 交叉引用 (from EpisodicMemory)
8
6
  * 2. ReadOnlyCache — 只读工具结果缓存 (from ToolResultCache, 排除副作用工具 B3 fix)