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
@@ -5,13 +5,13 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>AutoSnippet Dashboard</title>
8
- <script type="module" crossorigin src="/assets/index-BRJv5Y3r.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-DV8biUkH.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/yaml-qRaU8Ldn.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendor-BZEJEVBn.js">
11
- <link rel="modulepreload" crossorigin href="/assets/icons-FHns2ypa.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/icons-BMNb0V6L.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/axios-42ANG6Sg.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/framer-motion-CZfOSYpP.js">
14
- <link rel="stylesheet" crossorigin href="/assets/index-DzoB7kxK.css">
14
+ <link rel="stylesheet" crossorigin href="/assets/index-DHJ1Dj7u.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
package/dist/bin/cli.js CHANGED
@@ -755,7 +755,7 @@ program
755
755
  const panoramaService = container.get('panoramaService');
756
756
  await panoramaService.ensureData();
757
757
  if (opts.gaps) {
758
- const gaps = panoramaService.getGaps();
758
+ const gaps = await panoramaService.getGaps();
759
759
  if (opts.json) {
760
760
  cli.log(JSON.stringify(gaps, null, 2));
761
761
  }
@@ -773,7 +773,7 @@ program
773
773
  return;
774
774
  }
775
775
  if (opts.health) {
776
- const health = panoramaService.getHealth();
776
+ const health = await panoramaService.getHealth();
777
777
  if (opts.json) {
778
778
  cli.log(JSON.stringify(health, null, 2));
779
779
  }
@@ -790,7 +790,7 @@ program
790
790
  return;
791
791
  }
792
792
  // 默认: 全景概览
793
- const overview = panoramaService.getOverview();
793
+ const overview = await panoramaService.getOverview();
794
794
  if (opts.json) {
795
795
  cli.log(JSON.stringify(overview, null, 2));
796
796
  }
@@ -914,9 +914,12 @@ program
914
914
  const { getRealtimeService } = await import('../lib/infrastructure/realtime/RealtimeService.js');
915
915
  const db = container.get('database');
916
916
  const agentFactory = container.get('agentFactory');
917
+ const knowledgeRepo = container.get('knowledgeRepository');
918
+ const auditRepo = container.get('auditRepository');
917
919
  const signalCollector = new SignalCollector({
918
920
  projectRoot,
919
- database: db,
921
+ knowledgeRepo: knowledgeRepo,
922
+ auditRepo: auditRepo,
920
923
  agentFactory,
921
924
  container,
922
925
  mode: process.env.ASD_SIGNAL_MODE || 'auto',
@@ -1,5 +1,7 @@
1
1
  /** ChatAgentPrompts — Agent 提示词构建和文本处理方法 */
2
2
  import fs from 'node:fs';
3
+ import { and, count, eq, inArray } from 'drizzle-orm';
4
+ import { knowledgeEntries } from '../../infrastructure/database/drizzle/schema.js';
3
5
  /**
4
6
  * 构建原生函数调用模式的系统提示词
5
7
  *
@@ -82,31 +84,65 @@ submit_knowledge 的 code 字段必须是「项目特写」— 将技术的基
82
84
  */
83
85
  export async function buildProjectBriefing({ container }) {
84
86
  try {
85
- const db = container?.get?.('database');
86
- if (!db) {
87
+ const dbService = container?.get?.('database');
88
+ const drizzle = dbService?.getDrizzle?.();
89
+ if (!drizzle) {
87
90
  return '';
88
91
  }
89
- // knowledgeType kind 映射:
90
- // rule: code-standard, code-style, best-practice, boundary-constraint
91
- // pattern: code-pattern, architecture, solution
92
- // fact: code-relation, inheritance, call-chain, data-flow, module-dependency
93
- // V3: knowledge_entries 统一表(candidates 已合并,lifecycle 替代 status)
94
- const stats = db
95
- .prepare(`
96
- SELECT
97
- (SELECT COUNT(*) FROM knowledge_entries WHERE lifecycle = 'active') as recipeCount,
98
- (SELECT COUNT(*) FROM knowledge_entries WHERE lifecycle = 'active' AND knowledgeType IN ('code-standard','code-style','best-practice','boundary-constraint')) as ruleCount,
99
- (SELECT COUNT(*) FROM knowledge_entries WHERE lifecycle = 'active' AND knowledgeType IN ('code-pattern','architecture','solution')) as patternCount,
100
- (SELECT COUNT(*) FROM knowledge_entries WHERE lifecycle = 'active' AND knowledgeType IN ('code-relation','inheritance','call-chain','data-flow','module-dependency')) as factCount,
101
- (SELECT COUNT(*) FROM knowledge_entries WHERE lifecycle = 'active' AND knowledgeType = 'boundary-constraint') as guardRuleCount,
102
- (SELECT COUNT(*) FROM knowledge_entries WHERE lifecycle = 'pending') as pendingCandidates,
103
- (SELECT COUNT(*) FROM knowledge_entries) as totalCandidates
104
- `)
105
- .get();
106
- if (!stats || stats.recipeCount === 0) {
92
+ const ruleTypes = ['code-standard', 'code-style', 'best-practice', 'boundary-constraint'];
93
+ const patternTypes = ['code-pattern', 'architecture', 'solution'];
94
+ const factTypes = [
95
+ 'code-relation',
96
+ 'inheritance',
97
+ 'call-chain',
98
+ 'data-flow',
99
+ 'module-dependency',
100
+ ];
101
+ const activeCondition = eq(knowledgeEntries.lifecycle, 'active');
102
+ const [recipeCount] = drizzle
103
+ .select({ value: count() })
104
+ .from(knowledgeEntries)
105
+ .where(activeCondition)
106
+ .all();
107
+ const [ruleCount] = drizzle
108
+ .select({ value: count() })
109
+ .from(knowledgeEntries)
110
+ .where(and(activeCondition, inArray(knowledgeEntries.knowledgeType, ruleTypes)))
111
+ .all();
112
+ const [patternCount] = drizzle
113
+ .select({ value: count() })
114
+ .from(knowledgeEntries)
115
+ .where(and(activeCondition, inArray(knowledgeEntries.knowledgeType, patternTypes)))
116
+ .all();
117
+ const [factCount] = drizzle
118
+ .select({ value: count() })
119
+ .from(knowledgeEntries)
120
+ .where(and(activeCondition, inArray(knowledgeEntries.knowledgeType, factTypes)))
121
+ .all();
122
+ const [guardRuleCount] = drizzle
123
+ .select({ value: count() })
124
+ .from(knowledgeEntries)
125
+ .where(and(activeCondition, eq(knowledgeEntries.knowledgeType, 'boundary-constraint')))
126
+ .all();
127
+ const [pendingCandidates] = drizzle
128
+ .select({ value: count() })
129
+ .from(knowledgeEntries)
130
+ .where(eq(knowledgeEntries.lifecycle, 'pending'))
131
+ .all();
132
+ const [totalCandidates] = drizzle.select({ value: count() }).from(knowledgeEntries).all();
133
+ const stats = {
134
+ recipeCount: recipeCount?.value ?? 0,
135
+ ruleCount: ruleCount?.value ?? 0,
136
+ patternCount: patternCount?.value ?? 0,
137
+ factCount: factCount?.value ?? 0,
138
+ guardRuleCount: guardRuleCount?.value ?? 0,
139
+ pendingCandidates: pendingCandidates?.value ?? 0,
140
+ totalCandidates: totalCandidates?.value ?? 0,
141
+ };
142
+ if (stats.recipeCount === 0) {
107
143
  return '\n## 项目状态\n⚠️ 知识库为空。建议先执行冷启动(bootstrap_knowledge)。\n';
108
144
  }
109
- let section = `\n## 项目状态\n- 知识库: ${stats.recipeCount} 条 Recipe(${stats.ruleCount || 0} rule / ${stats.patternCount || 0} pattern / ${stats.factCount || 0} fact)\n- Guard 规则: ${stats.guardRuleCount || 0} 条\n- 候选: ${stats.pendingCandidates} 条待审 / ${stats.totalCandidates} 条总计\n`;
145
+ let section = `\n## 项目状态\n- 知识库: ${stats.recipeCount} 条 Recipe(${stats.ruleCount} rule / ${stats.patternCount} pattern / ${stats.factCount} fact)\n- Guard 规则: ${stats.guardRuleCount} 条\n- 候选: ${stats.pendingCandidates} 条待审 / ${stats.totalCandidates} 条总计\n`;
110
146
  if (stats.pendingCandidates > 10) {
111
147
  section += `\n⚠️ 有 ${stats.pendingCandidates} 条候选积压,建议执行批量审核。\n`;
112
148
  }
@@ -29,6 +29,7 @@ interface TokenUsage {
29
29
  interface SharedState {
30
30
  submittedTitles?: Set<string>;
31
31
  submittedPatterns?: Set<string>;
32
+ submittedTriggers?: Set<string>;
32
33
  submitToolName?: string;
33
34
  _dimensionMeta?: {
34
35
  id?: string;
@@ -229,12 +229,25 @@ export const submitDedup = {
229
229
  const isError = typeof result === 'object' && (resultObj?.error || resultObj?.status === 'error');
230
230
  if (!isRejected && !isError && sharedState.submittedTitles) {
231
231
  const normalizedTitle = title.toLowerCase().trim();
232
+ // ── trigger 去重 (防止不同 title 相同 trigger 的跨维度重复) ──
233
+ const trigger = String(call.args?.trigger || '')
234
+ .toLowerCase()
235
+ .trim();
236
+ if (trigger && sharedState.submittedTriggers?.has(trigger)) {
237
+ meta.dedupMessage = `⚠ 重复 trigger: "${trigger}" 已被其他候选占用。`;
238
+ ctx.runtime.logger.info(`[ToolPipeline] 🔁 duplicate trigger: "${trigger}"`);
239
+ return;
240
+ }
232
241
  if (sharedState.submittedTitles.has(normalizedTitle)) {
233
242
  meta.dedupMessage = `⚠ 重复提交: "${title}" 已存在。`;
234
243
  ctx.runtime.logger.info(`[ToolPipeline] 🔁 duplicate: "${title}"`);
235
244
  }
236
245
  else {
237
246
  sharedState.submittedTitles.add(normalizedTitle);
247
+ // trigger 去重注册
248
+ if (trigger && sharedState.submittedTriggers) {
249
+ sharedState.submittedTriggers.add(trigger);
250
+ }
238
251
  // 模式指纹去重
239
252
  const contentObj = call.args?.content;
240
253
  const pattern = String(contentObj?.pattern || '');
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * ActiveContext — 合并 WorkingMemory + ReasoningTrace 为统一的会话工作记忆
3
3
  *
4
- * 设计来源: docs/copilot/memory-system-redesign.md §4.3, §6.2
5
- *
6
4
  * 三个内部子区:
7
5
  * 1. Scratchpad — Agent 通过 note_finding 主动标记的发现 (不可压缩)
8
6
  * 2. ObservationLog — 每轮 ReAct 记录 (合并原 RT.rounds + WM.observations,滑动窗口压缩)
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * ActiveContext — 合并 WorkingMemory + ReasoningTrace 为统一的会话工作记忆
3
3
  *
4
- * 设计来源: docs/copilot/memory-system-redesign.md §4.3, §6.2
5
- *
6
4
  * 三个内部子区:
7
5
  * 1. Scratchpad — Agent 通过 note_finding 主动标记的发现 (不可压缩)
8
6
  * 2. ObservationLog — 每轮 ReAct 记录 (合并原 RT.rounds + WM.observations,滑动窗口压缩)
@@ -0,0 +1,49 @@
1
+ /**
2
+ * MemoryEmbeddingStore — 向量嵌入的 JSON sidecar 存储
3
+ *
4
+ * 将 Agent Memory 的向量嵌入从 SQLite BLOB 迁移到独立 JSON 文件,
5
+ * 与 Knowledge 侧 HNSW `.asvec` 的设计理念对齐:
6
+ * **结构化数据存 SQLite,向量存独立文件。**
7
+ *
8
+ * 设计:
9
+ * - 内存 Map<id, number[]> 缓存,启动时一次性加载
10
+ * - 写入时更新内存 + debounced flush 到 JSON
11
+ * - 崩溃丢失可通过 embedAllMemories() backfill 恢复
12
+ *
13
+ * 文件位置: .autosnippet/context/memory_embeddings.json
14
+ *
15
+ * @module MemoryEmbeddingStore
16
+ */
17
+ export declare class MemoryEmbeddingStore {
18
+ #private;
19
+ /**
20
+ * @param projectRoot 项目根目录
21
+ * @param opts.filePath 覆盖默认文件路径 (测试用)
22
+ */
23
+ constructor(projectRoot: string, opts?: {
24
+ filePath?: string;
25
+ });
26
+ /** 获取单条 embedding */
27
+ get(id: string): number[] | null;
28
+ /** 设置单条 embedding */
29
+ set(id: string, embedding: number[]): void;
30
+ /** 批量设置 embeddings */
31
+ batchSet(entries: Array<{
32
+ id: string;
33
+ embedding: number[];
34
+ }>): number;
35
+ /** 删除单条 embedding */
36
+ delete(id: string): boolean;
37
+ /** 检查是否有 embedding */
38
+ has(id: string): boolean;
39
+ /** 返回所有缺少 embedding 的 ID (给定候选 ID 列表) */
40
+ getMissingIds(candidateIds: string[]): string[];
41
+ /** 缓存大小 */
42
+ get size(): number;
43
+ /** 清除所有 embeddings (用于重建) */
44
+ clear(): void;
45
+ /** 立即刷写到磁盘 (shutdown / 测试用) */
46
+ flushSync(): void;
47
+ /** GC: 移除不在给定 ID 集合中的 embeddings */
48
+ gc(activeIds: Set<string>): number;
49
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * MemoryEmbeddingStore — 向量嵌入的 JSON sidecar 存储
3
+ *
4
+ * 将 Agent Memory 的向量嵌入从 SQLite BLOB 迁移到独立 JSON 文件,
5
+ * 与 Knowledge 侧 HNSW `.asvec` 的设计理念对齐:
6
+ * **结构化数据存 SQLite,向量存独立文件。**
7
+ *
8
+ * 设计:
9
+ * - 内存 Map<id, number[]> 缓存,启动时一次性加载
10
+ * - 写入时更新内存 + debounced flush 到 JSON
11
+ * - 崩溃丢失可通过 embedAllMemories() backfill 恢复
12
+ *
13
+ * 文件位置: .autosnippet/context/memory_embeddings.json
14
+ *
15
+ * @module MemoryEmbeddingStore
16
+ */
17
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
18
+ import { dirname, join } from 'node:path';
19
+ /** debounce flush 延迟 (ms) */
20
+ const FLUSH_DELAY_MS = 2000;
21
+ export class MemoryEmbeddingStore {
22
+ /** 内存缓存: id → embedding vector */
23
+ #cache = new Map();
24
+ /** JSON 文件路径 */
25
+ #filePath;
26
+ /** debounce timer */
27
+ #flushTimer = null;
28
+ /** dirty flag */
29
+ #dirty = false;
30
+ /**
31
+ * @param projectRoot 项目根目录
32
+ * @param opts.filePath 覆盖默认文件路径 (测试用)
33
+ */
34
+ constructor(projectRoot, opts) {
35
+ this.#filePath =
36
+ opts?.filePath ?? join(projectRoot, '.autosnippet', 'context', 'memory_embeddings.json');
37
+ this.#load();
38
+ }
39
+ /** 获取单条 embedding */
40
+ get(id) {
41
+ return this.#cache.get(id) ?? null;
42
+ }
43
+ /** 设置单条 embedding */
44
+ set(id, embedding) {
45
+ this.#cache.set(id, embedding);
46
+ this.#scheduleDirtyFlush();
47
+ }
48
+ /** 批量设置 embeddings */
49
+ batchSet(entries) {
50
+ let count = 0;
51
+ for (const { id, embedding } of entries) {
52
+ this.#cache.set(id, embedding);
53
+ count++;
54
+ }
55
+ if (count > 0) {
56
+ this.#scheduleDirtyFlush();
57
+ }
58
+ return count;
59
+ }
60
+ /** 删除单条 embedding */
61
+ delete(id) {
62
+ const existed = this.#cache.delete(id);
63
+ if (existed) {
64
+ this.#scheduleDirtyFlush();
65
+ }
66
+ return existed;
67
+ }
68
+ /** 检查是否有 embedding */
69
+ has(id) {
70
+ return this.#cache.has(id);
71
+ }
72
+ /** 返回所有缺少 embedding 的 ID (给定候选 ID 列表) */
73
+ getMissingIds(candidateIds) {
74
+ return candidateIds.filter((id) => !this.#cache.has(id));
75
+ }
76
+ /** 缓存大小 */
77
+ get size() {
78
+ return this.#cache.size;
79
+ }
80
+ /** 清除所有 embeddings (用于重建) */
81
+ clear() {
82
+ this.#cache.clear();
83
+ this.#scheduleDirtyFlush();
84
+ }
85
+ /** 立即刷写到磁盘 (shutdown / 测试用) */
86
+ flushSync() {
87
+ if (this.#flushTimer) {
88
+ clearTimeout(this.#flushTimer);
89
+ this.#flushTimer = null;
90
+ }
91
+ if (!this.#dirty) {
92
+ return;
93
+ }
94
+ this.#writeFile();
95
+ this.#dirty = false;
96
+ }
97
+ /** GC: 移除不在给定 ID 集合中的 embeddings */
98
+ gc(activeIds) {
99
+ let removed = 0;
100
+ for (const id of this.#cache.keys()) {
101
+ if (!activeIds.has(id)) {
102
+ this.#cache.delete(id);
103
+ removed++;
104
+ }
105
+ }
106
+ if (removed > 0) {
107
+ this.#scheduleDirtyFlush();
108
+ }
109
+ return removed;
110
+ }
111
+ // ═══════════════════════════════════════════════════════════
112
+ // Private
113
+ // ═══════════════════════════════════════════════════════════
114
+ #load() {
115
+ try {
116
+ if (existsSync(this.#filePath)) {
117
+ const raw = readFileSync(this.#filePath, 'utf-8');
118
+ const data = JSON.parse(raw);
119
+ for (const [id, vec] of Object.entries(data)) {
120
+ if (Array.isArray(vec)) {
121
+ this.#cache.set(id, vec);
122
+ }
123
+ }
124
+ }
125
+ }
126
+ catch {
127
+ // 文件不存在或解析失败 → 空缓存,后续 backfill 会重建
128
+ }
129
+ }
130
+ #writeFile() {
131
+ try {
132
+ const dir = dirname(this.#filePath);
133
+ if (!existsSync(dir)) {
134
+ mkdirSync(dir, { recursive: true });
135
+ }
136
+ const obj = {};
137
+ for (const [id, vec] of this.#cache) {
138
+ obj[id] = vec;
139
+ }
140
+ writeFileSync(this.#filePath, JSON.stringify(obj), 'utf-8');
141
+ }
142
+ catch {
143
+ // 写入失败不阻塞运行时;下次 flush 或 backfill 会重试
144
+ }
145
+ }
146
+ #scheduleDirtyFlush() {
147
+ this.#dirty = true;
148
+ if (this.#flushTimer) {
149
+ return; // 已有 pending timer
150
+ }
151
+ this.#flushTimer = setTimeout(() => {
152
+ this.#flushTimer = null;
153
+ if (this.#dirty) {
154
+ this.#writeFile();
155
+ this.#dirty = false;
156
+ }
157
+ }, FLUSH_DELAY_MS);
158
+ }
159
+ }
@@ -10,6 +10,7 @@
10
10
  *
11
11
  * @module MemoryRetriever
12
12
  */
13
+ import type { MemoryEmbeddingStore } from './MemoryEmbeddingStore.js';
13
14
  import type { DeserializedMemory } from './MemoryStore.js';
14
15
  import { MemoryStore } from './MemoryStore.js';
15
16
  /** 带评分的记忆检索结果 */
@@ -49,6 +50,7 @@ export declare class MemoryRetriever {
49
50
  /** @param [opts.embeddingFn] 向量嵌入函数 (异步) */
50
51
  constructor(store: MemoryStore, opts?: {
51
52
  embeddingFn?: EmbeddingFn;
53
+ embeddingStore?: MemoryEmbeddingStore;
52
54
  });
53
55
  /**
54
56
  * 综合检索: recency × importance × relevance
@@ -25,10 +25,13 @@ export class MemoryRetriever {
25
25
  #store;
26
26
  /** 向量嵌入函数 */
27
27
  #embeddingFn;
28
+ /** 向量嵌入存储 (JSON sidecar) */
29
+ #embeddingStore;
28
30
  /** @param [opts.embeddingFn] 向量嵌入函数 (异步) */
29
31
  constructor(store, opts = {}) {
30
32
  this.#store = store;
31
33
  this.#embeddingFn = typeof opts.embeddingFn === 'function' ? opts.embeddingFn : null;
34
+ this.#embeddingStore = opts.embeddingStore ?? null;
32
35
  }
33
36
  // ═══════════════════════════════════════════════════════════
34
37
  // 综合检索
@@ -71,14 +74,15 @@ export class MemoryRetriever {
71
74
  const importance = (m.importance || 5) / 10;
72
75
  // Relevance: 词汇相关性 (lexical)
73
76
  const lexicalRelevance = MemoryRetriever.#computeRelevance(lowerQuery, queryTokens, m.content);
74
- // 向量相关性: 对有 embedding 的记忆计算余弦相似度
77
+ // 向量相关性: embeddingStore 查找 embedding 做余弦相似度
75
78
  const deserialized = MemoryStore.deserialize(m);
76
79
  let vectorRelevance = 0;
77
- if (queryVec && deserialized.embedding) {
78
- vectorRelevance = Math.max(0, cosineSimilarity(queryVec, deserialized.embedding));
80
+ const storedEmbedding = this.#embeddingStore?.get(m.id) ?? null;
81
+ if (queryVec && storedEmbedding) {
82
+ vectorRelevance = Math.max(0, cosineSimilarity(queryVec, storedEmbedding));
79
83
  }
80
84
  // 混合相关性: 有向量时 0.6 * vector + 0.4 * lexical,否则纯 lexical
81
- const relevance = queryVec && deserialized.embedding
85
+ const relevance = queryVec && storedEmbedding
82
86
  ? 0.6 * vectorRelevance + 0.4 * lexicalRelevance
83
87
  : lexicalRelevance;
84
88
  const score = WEIGHT_RECENCY * recency + WEIGHT_IMPORTANCE * importance + WEIGHT_RELEVANCE * relevance;
@@ -199,18 +203,28 @@ export class MemoryRetriever {
199
203
  * @returns 成功嵌入的记忆数
200
204
  */
201
205
  async embedAllMemories(batchSize = 20) {
202
- if (!this.#embeddingFn) {
206
+ if (!this.#embeddingFn || !this.#embeddingStore) {
203
207
  return 0;
204
208
  }
205
- const missing = this.#store.getWithoutEmbedding(batchSize);
206
- if (missing.length === 0) {
209
+ // MemoryStore 获取所有活跃记忆 ID,找出 embeddingStore 中缺失的
210
+ const allActive = this.#store.getAllActive();
211
+ const allIds = allActive.map((m) => m.id);
212
+ const missingIds = this.#embeddingStore.getMissingIds(allIds);
213
+ if (missingIds.length === 0) {
207
214
  return 0;
208
215
  }
216
+ // 取前 batchSize 条
217
+ const batch = missingIds.slice(0, batchSize);
218
+ const contentMap = new Map(allActive.map((m) => [m.id, m.content]));
209
219
  const entries = [];
210
- for (const item of missing) {
220
+ for (const id of batch) {
221
+ const content = contentMap.get(id);
222
+ if (!content) {
223
+ continue;
224
+ }
211
225
  try {
212
- const vec = await this.#embeddingFn(item.content);
213
- entries.push({ id: item.id, embedding: vec });
226
+ const vec = await this.#embeddingFn(content);
227
+ entries.push({ id, embedding: vec });
214
228
  }
215
229
  catch {
216
230
  // 单条失败不阻塞
@@ -219,7 +233,7 @@ export class MemoryRetriever {
219
233
  if (entries.length === 0) {
220
234
  return 0;
221
235
  }
222
- return this.#store.batchUpdateEmbeddings(entries);
236
+ return this.#embeddingStore.batchSet(entries);
223
237
  }
224
238
  /**
225
239
  * 使用嵌入函数计算语义相关性 (余弦相似度)
@@ -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,8 +11,9 @@
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
@@ -34,7 +33,7 @@ export interface SqliteStatement {
34
33
  get(...params: unknown[]): Record<string, unknown> | undefined;
35
34
  all(...params: unknown[]): Record<string, unknown>[];
36
35
  }
37
- /** 数据库行 (raw row from SQLite) */
36
+ /** 数据库行 (raw row from SQLite — 保持向后兼容) */
38
37
  export interface MemoryRow {
39
38
  id: string;
40
39
  type: string;
@@ -52,8 +51,6 @@ export interface MemoryRow {
52
51
  source_evidence: string | null;
53
52
  bootstrap_session: string | null;
54
53
  tags: string;
55
- /** 向量嵌入 (Float32Array BLOB) */
56
- embedding: Buffer | null;
57
54
  /** findSimilar 附加字段 */
58
55
  similarity?: number;
59
56
  related_memories_raw?: string;
@@ -76,8 +73,6 @@ export interface DeserializedMemory {
76
73
  sourceEvidence: string | null;
77
74
  bootstrapSession: string | null;
78
75
  tags: string[];
79
- /** 向量嵌入 (Float32Array) */
80
- embedding: number[] | null;
81
76
  }
82
77
  /** 添加记忆时的输入 */
83
78
  export interface MemoryInput {
@@ -91,8 +86,6 @@ export interface MemoryInput {
91
86
  sourceEvidence?: string | null;
92
87
  bootstrapSession?: string | null;
93
88
  tags?: string[];
94
- /** 向量嵌入 */
95
- embedding?: number[] | null;
96
89
  }
97
90
  /** 更新记忆时的字段 */
98
91
  export interface MemoryUpdates {
@@ -102,8 +95,6 @@ export interface MemoryUpdates {
102
95
  relatedEntities?: string[];
103
96
  relatedMemories?: string[];
104
97
  tags?: string[];
105
- /** 向量嵌入 */
106
- embedding?: number[] | null;
107
98
  }
108
99
  export declare class MemoryStore {
109
100
  #private;
@@ -119,7 +110,9 @@ export declare class MemoryStore {
119
110
  id: string;
120
111
  action: string;
121
112
  };
122
- /** 更新已有记忆 */
113
+ /**
114
+ * 更新已有记忆
115
+ */
123
116
  update(id: string, updates: MemoryUpdates): boolean;
124
117
  /** 删除一条记忆 */
125
118
  delete(id: string): boolean;
@@ -184,30 +177,4 @@ export declare class MemoryStore {
184
177
  /** 反序列化数据库行为域对象 */
185
178
  static deserialize(row: MemoryRow): DeserializedMemory;
186
179
  static safeParseJSON<T>(str: string | null | undefined, fallback: T): T;
187
- /**
188
- * 更新单条记忆的向量嵌入
189
- * @param id 记忆 ID
190
- * @param embedding 向量数组
191
- */
192
- updateEmbedding(id: string, embedding: number[]): boolean;
193
- /**
194
- * 批量更新向量嵌入
195
- * @param entries Array of { id, embedding }
196
- */
197
- batchUpdateEmbeddings(entries: Array<{
198
- id: string;
199
- embedding: number[];
200
- }>): number;
201
- /**
202
- * 获取缺少向量嵌入的记忆 ID 和内容
203
- * @param limit 最大返回数
204
- */
205
- getWithoutEmbedding(limit?: number): Array<{
206
- id: string;
207
- content: string;
208
- }>;
209
- /** 将 number[] 序列化为 Buffer (Float32Array → BLOB) */
210
- static serializeEmbedding(embedding: number[]): Buffer;
211
- /** 将 Buffer (BLOB) 反序列化为 number[] */
212
- static deserializeEmbedding(blob: Buffer): number[];
213
180
  }