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
@@ -19,6 +19,7 @@
19
19
  import { randomUUID } from 'node:crypto';
20
20
  import { isValidTransition } from '../../domain/knowledge/Lifecycle.js';
21
21
  import Logger from '../../infrastructure/logging/Logger.js';
22
+ /* ────────────────────── Types ────────────────────── */
22
23
  /* ────────────────────── Constants ────────────────────── */
23
24
  /** 中间态超时配置(毫秒) */
24
25
  const TIMEOUT_MS = {
@@ -50,11 +51,15 @@ const ENTRY_META_KEYS = {
50
51
  };
51
52
  /* ────────────────────── Class ────────────────────── */
52
53
  export class RecipeLifecycleSupervisor {
53
- #db;
54
+ #knowledgeRepo;
55
+ #proposalRepo;
56
+ #lifecycleEventRepo;
54
57
  #signalBus;
55
58
  #logger = Logger.getInstance();
56
- constructor(db, options = {}) {
57
- this.#db = db;
59
+ constructor(knowledgeRepo, options = {}) {
60
+ this.#knowledgeRepo = knowledgeRepo;
61
+ this.#proposalRepo = options.proposalRepo ?? null;
62
+ this.#lifecycleEventRepo = options.lifecycleEventRepo ?? null;
58
63
  this.#signalBus = options.signalBus ?? null;
59
64
  }
60
65
  /* ═══════════════════ Core Transition ═══════════════════ */
@@ -69,11 +74,11 @@ export class RecipeLifecycleSupervisor {
69
74
  * 6. 记录 TransitionEvent
70
75
  * 7. 发射信号
71
76
  */
72
- transition(request) {
77
+ async transition(request) {
73
78
  const { recipeId, targetState, trigger, evidence, proposalId, operatorId } = request;
74
79
  const opId = operatorId ?? 'system';
75
80
  // 1. 获取当前状态
76
- const current = this.#getRecipeState(recipeId);
81
+ const current = await this.#getRecipeState(recipeId);
77
82
  if (!current) {
78
83
  return {
79
84
  success: false,
@@ -94,14 +99,12 @@ export class RecipeLifecycleSupervisor {
94
99
  };
95
100
  }
96
101
  // 3. Exit Action
97
- this.#executeExitAction(recipeId, fromState);
102
+ await this.#executeExitAction(recipeId, fromState);
98
103
  // 4. 更新 lifecycle
99
104
  const now = Date.now();
100
- this.#db
101
- .prepare(`UPDATE knowledge_entries SET lifecycle = ?, updatedAt = ? WHERE id = ?`)
102
- .run(targetState, now, recipeId);
105
+ await this.#knowledgeRepo.updateLifecycle(recipeId, targetState);
103
106
  // 5. Entry Action
104
- this.#executeEntryAction(recipeId, targetState, now, proposalId);
107
+ await this.#executeEntryAction(recipeId, targetState, now, proposalId);
105
108
  // 6. 记录 TransitionEvent
106
109
  const event = this.#recordEvent({
107
110
  recipeId,
@@ -126,7 +129,7 @@ export class RecipeLifecycleSupervisor {
126
129
  * - evolving > 7d → active(回退)
127
130
  * - decaying > 30d → deprecated
128
131
  */
129
- checkTimeouts() {
132
+ async checkTimeouts() {
130
133
  const result = { timedOut: [], checked: 0 };
131
134
  const now = Date.now();
132
135
  for (const [state, timeoutMs] of Object.entries(TIMEOUT_MS)) {
@@ -134,19 +137,16 @@ export class RecipeLifecycleSupervisor {
134
137
  continue;
135
138
  }
136
139
  const targetState = TIMEOUT_TARGET[state];
137
- const rows = this.#db
138
- .prepare(`SELECT id, stats FROM knowledge_entries WHERE lifecycle = ?`)
139
- .all(state);
140
- result.checked += rows.length;
141
- for (const row of rows) {
142
- const stats = safeJsonParse(row.stats, {});
140
+ const entries = await this.#knowledgeRepo.findAllByLifecycles([state]);
141
+ result.checked += entries.length;
142
+ for (const entry of entries) {
143
+ const stats = (entry.stats ?? {});
143
144
  const entryKey = ENTRY_META_KEYS[state];
144
145
  const enteredAt = (entryKey ? stats[entryKey] : null);
145
- // updatedAt 作为 fallback
146
- const stateAge = enteredAt ? now - enteredAt : this.#getRecipeAge(row.id, now);
146
+ const stateAge = enteredAt ? now - enteredAt : await this.#getRecipeAge(entry.id, now);
147
147
  if (stateAge > timeoutMs) {
148
- const transitionResult = this.transition({
149
- recipeId: row.id,
148
+ const transitionResult = await this.transition({
149
+ recipeId: entry.id,
150
150
  targetState,
151
151
  trigger: 'timeout-recovery',
152
152
  evidence: {
@@ -155,7 +155,7 @@ export class RecipeLifecycleSupervisor {
155
155
  });
156
156
  if (transitionResult.success) {
157
157
  result.timedOut.push({
158
- recipeId: row.id,
158
+ recipeId: entry.id,
159
159
  fromState: state,
160
160
  toState: targetState,
161
161
  age: stateAge,
@@ -175,15 +175,10 @@ export class RecipeLifecycleSupervisor {
175
175
  */
176
176
  getTransitionHistory(recipeId, limit = 50) {
177
177
  try {
178
- const rows = this.#db
179
- .prepare(`SELECT id, recipe_id, from_state, to_state, trigger, operator_id,
180
- evidence_json, proposal_id, created_at
181
- FROM lifecycle_transition_events
182
- WHERE recipe_id = ?
183
- ORDER BY created_at DESC
184
- LIMIT ?`)
185
- .all(recipeId, limit);
186
- return rows.map((row) => this.#rowToEvent(row));
178
+ if (!this.#lifecycleEventRepo) {
179
+ return [];
180
+ }
181
+ return this.#lifecycleEventRepo.getHistory(recipeId, limit);
187
182
  }
188
183
  catch {
189
184
  // 表可能不存在(migration 未运行)
@@ -193,16 +188,14 @@ export class RecipeLifecycleSupervisor {
193
188
  /**
194
189
  * 获取全局状态健康摘要
195
190
  */
196
- getHealthSummary() {
191
+ async getHealthSummary() {
197
192
  const now = Date.now();
198
- // 状态分布
199
- const stateDistribution = this.#getStateDistribution();
200
- // 中间态卡死检测
193
+ const stateDistribution = await this.#getStateDistribution();
201
194
  const intermediateStates = {
202
- stuckEvolving: this.#getStuckInfo('evolving', STUCK_THRESHOLD_MS.evolving, now),
203
- stuckDecaying: this.#getStuckInfo('decaying', STUCK_THRESHOLD_MS.decaying, now),
204
- stuckStaging: this.#getStuckInfo('staging', STUCK_THRESHOLD_MS.staging, now),
205
- stuckPending: this.#getStuckInfo('pending', STUCK_THRESHOLD_MS.pending, now),
195
+ stuckEvolving: await this.#getStuckInfo('evolving', STUCK_THRESHOLD_MS.evolving, now),
196
+ stuckDecaying: await this.#getStuckInfo('decaying', STUCK_THRESHOLD_MS.decaying, now),
197
+ stuckStaging: await this.#getStuckInfo('staging', STUCK_THRESHOLD_MS.staging, now),
198
+ stuckPending: await this.#getStuckInfo('pending', STUCK_THRESHOLD_MS.pending, now),
206
199
  };
207
200
  // 最近转移统计
208
201
  const recentTransitions = this.#getRecentTransitionStats(now);
@@ -211,21 +204,18 @@ export class RecipeLifecycleSupervisor {
211
204
  return { stateDistribution, intermediateStates, recentTransitions, proposalMetrics };
212
205
  }
213
206
  /* ═══════════════════ Entry/Exit Actions ═══════════════════ */
214
- #executeEntryAction(recipeId, state, now, proposalId) {
207
+ async #executeEntryAction(recipeId, state, now, proposalId) {
215
208
  const metaKey = ENTRY_META_KEYS[state];
216
209
  if (!metaKey) {
217
210
  return;
218
211
  }
219
- const statsRow = this.#db
220
- .prepare(`SELECT stats FROM knowledge_entries WHERE id = ?`)
221
- .get(recipeId);
222
- const stats = safeJsonParse(statsRow?.stats, {});
212
+ const entry = await this.#knowledgeRepo.findById(recipeId);
213
+ const stats = (entry?.stats ?? {});
223
214
  stats[metaKey] = now;
224
215
  if (state === 'evolving' && proposalId) {
225
216
  stats.evolvingProposalId = proposalId;
226
217
  }
227
218
  if (state === 'active') {
228
- // 清除中间态元数据
229
219
  delete stats.evolvingStartedAt;
230
220
  delete stats.evolvingProposalId;
231
221
  delete stats.decayStartedAt;
@@ -233,23 +223,15 @@ export class RecipeLifecycleSupervisor {
233
223
  if (state === 'deprecated') {
234
224
  stats.deprecatedAt = now;
235
225
  }
236
- this.#db
237
- .prepare(`UPDATE knowledge_entries SET stats = ? WHERE id = ?`)
238
- .run(JSON.stringify(stats), recipeId);
226
+ await this.#knowledgeRepo.update(recipeId, { stats });
239
227
  }
240
- #executeExitAction(recipeId, state) {
228
+ async #executeExitAction(recipeId, state) {
241
229
  if (state === 'active') {
242
- // 记录 lastActiveAt
243
- const statsRow = this.#db
244
- .prepare(`SELECT stats FROM knowledge_entries WHERE id = ?`)
245
- .get(recipeId);
246
- const stats = safeJsonParse(statsRow?.stats, {});
230
+ const entry = await this.#knowledgeRepo.findById(recipeId);
231
+ const stats = (entry?.stats ?? {});
247
232
  stats.lastActiveAt = Date.now();
248
- this.#db
249
- .prepare(`UPDATE knowledge_entries SET stats = ? WHERE id = ?`)
250
- .run(JSON.stringify(stats), recipeId);
233
+ await this.#knowledgeRepo.update(recipeId, { stats });
251
234
  }
252
- // staging exit: 清除 staging 元数据(由 StagingManager 自行处理)
253
235
  }
254
236
  /* ═══════════════════ Event Recording ═══════════════════ */
255
237
  #recordEvent(params) {
@@ -266,11 +248,21 @@ export class RecipeLifecycleSupervisor {
266
248
  createdAt: params.createdAt,
267
249
  };
268
250
  try {
269
- this.#db
270
- .prepare(`INSERT INTO lifecycle_transition_events
271
- (id, recipe_id, from_state, to_state, trigger, operator_id, evidence_json, proposal_id, created_at)
272
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
273
- .run(id, params.recipeId, params.fromState, params.toState, params.trigger, params.operatorId, params.evidence ? JSON.stringify(params.evidence) : null, params.proposalId, params.createdAt);
251
+ if (!this.#lifecycleEventRepo) {
252
+ this.#logger.warn(`[Supervisor] No lifecycleEventRepo available, cannot record transition event`);
253
+ return event;
254
+ }
255
+ this.#lifecycleEventRepo.record({
256
+ id,
257
+ recipeId: params.recipeId,
258
+ fromState: params.fromState,
259
+ toState: params.toState,
260
+ trigger: params.trigger,
261
+ operatorId: params.operatorId,
262
+ evidence: params.evidence,
263
+ proposalId: params.proposalId,
264
+ createdAt: params.createdAt,
265
+ });
274
266
  }
275
267
  catch {
276
268
  // lifecycle_transition_events 表可能不存在(降级容忍)
@@ -279,7 +271,7 @@ export class RecipeLifecycleSupervisor {
279
271
  return event;
280
272
  }
281
273
  /* ═══════════════════ Health Queries ═══════════════════ */
282
- #getStateDistribution() {
274
+ async #getStateDistribution() {
283
275
  const dist = {
284
276
  pending: 0,
285
277
  staging: 0,
@@ -289,11 +281,9 @@ export class RecipeLifecycleSupervisor {
289
281
  deprecated: 0,
290
282
  };
291
283
  try {
292
- const rows = this.#db
293
- .prepare(`SELECT lifecycle, COUNT(*) as cnt FROM knowledge_entries GROUP BY lifecycle`)
294
- .all();
295
- for (const row of rows) {
296
- dist[row.lifecycle] = row.cnt;
284
+ const grouped = await this.#knowledgeRepo.countGroupByLifecycle();
285
+ for (const [lifecycle, cnt] of Object.entries(grouped)) {
286
+ dist[lifecycle] = cnt;
297
287
  }
298
288
  }
299
289
  catch {
@@ -301,18 +291,16 @@ export class RecipeLifecycleSupervisor {
301
291
  }
302
292
  return dist;
303
293
  }
304
- #getStuckInfo(state, thresholdMs, now) {
294
+ async #getStuckInfo(state, thresholdMs, now) {
305
295
  try {
306
- const rows = this.#db
307
- .prepare(`SELECT id, stats, updatedAt FROM knowledge_entries WHERE lifecycle = ?`)
308
- .all(state);
296
+ const entries = await this.#knowledgeRepo.findAllByLifecycles([state]);
309
297
  let count = 0;
310
298
  let oldestAge = 0;
311
- for (const row of rows) {
312
- const stats = safeJsonParse(row.stats, {});
299
+ for (const entry of entries) {
300
+ const stats = (entry.stats ?? {});
313
301
  const metaKey = ENTRY_META_KEYS[state];
314
302
  const enteredAt = (metaKey ? stats[metaKey] : null);
315
- const age = enteredAt ? now - enteredAt : now - (row.updatedAt || now);
303
+ const age = enteredAt ? now - enteredAt : now - (entry.updatedAt || now);
316
304
  if (age > thresholdMs) {
317
305
  count++;
318
306
  if (age > oldestAge) {
@@ -328,25 +316,13 @@ export class RecipeLifecycleSupervisor {
328
316
  }
329
317
  #getRecentTransitionStats(now) {
330
318
  try {
331
- const last24hCount = this.#db
332
- .prepare(`SELECT COUNT(*) as cnt FROM lifecycle_transition_events WHERE created_at > ?`)
333
- .get(now - 24 * 60 * 60 * 1000)?.cnt ?? 0;
334
- const last7dCount = this.#db
335
- .prepare(`SELECT COUNT(*) as cnt FROM lifecycle_transition_events WHERE created_at > ?`)
336
- .get(now - 7 * 24 * 60 * 60 * 1000)?.cnt ?? 0;
337
- const triggerRows = this.#db
338
- .prepare(`SELECT trigger, COUNT(*) as cnt
339
- FROM lifecycle_transition_events
340
- WHERE created_at > ?
341
- GROUP BY trigger
342
- ORDER BY cnt DESC
343
- LIMIT 5`)
344
- .all(now - 7 * 24 * 60 * 60 * 1000);
345
- return {
346
- last24h: last24hCount,
347
- last7d: last7dCount,
348
- topTriggers: triggerRows.map((r) => ({ trigger: r.trigger, count: r.cnt })),
349
- };
319
+ if (!this.#lifecycleEventRepo) {
320
+ return { last24h: 0, last7d: 0, topTriggers: [] };
321
+ }
322
+ const last24hCount = this.#lifecycleEventRepo.countSince(now - 24 * 60 * 60 * 1000);
323
+ const last7dCount = this.#lifecycleEventRepo.countSince(now - 7 * 24 * 60 * 60 * 1000);
324
+ const topTriggers = this.#lifecycleEventRepo.topTriggersSince(now - 7 * 24 * 60 * 60 * 1000, 5);
325
+ return { last24h: last24hCount, last7d: last7dCount, topTriggers };
350
326
  }
351
327
  catch {
352
328
  return { last24h: 0, last7d: 0, topTriggers: [] };
@@ -354,33 +330,25 @@ export class RecipeLifecycleSupervisor {
354
330
  }
355
331
  #getProposalMetrics() {
356
332
  try {
357
- const statusCounts = this.#db
358
- .prepare(`SELECT status, COUNT(*) as cnt FROM evolution_proposals GROUP BY status`)
359
- .all();
360
- const map = {};
361
- for (const row of statusCounts) {
362
- map[row.status] = row.cnt;
363
- }
364
- const pending = map.pending ?? 0;
365
- const observing = map.observing ?? 0;
366
- const executed = map.executed ?? 0;
367
- const rejected = map.rejected ?? 0;
368
- const expired = map.expired ?? 0;
333
+ const statusMap = this.#proposalRepo
334
+ ? this.#proposalRepo.stats()
335
+ : {};
336
+ const pending = statusMap.pending ?? 0;
337
+ const observing = statusMap.observing ?? 0;
338
+ const executed = statusMap.executed ?? 0;
339
+ const rejected = statusMap.rejected ?? 0;
340
+ const expired = statusMap.expired ?? 0;
369
341
  const total = executed + rejected + expired;
370
- // contentPatchRate: 有 patch 的事件 / 总 proposal-execution 事件
371
342
  let contentPatchRate = 0;
372
343
  try {
373
- const patchEvents = this.#db
374
- .prepare(`SELECT COUNT(*) as cnt FROM lifecycle_transition_events
375
- WHERE trigger = 'content-patch-complete'`)
376
- .get();
377
- const execEvents = this.#db
378
- .prepare(`SELECT COUNT(*) as cnt FROM lifecycle_transition_events
379
- WHERE trigger = 'proposal-execution' OR trigger = 'proposal-attach'`)
380
- .get();
381
- const patchCount = patchEvents?.cnt ?? 0;
382
- const execCount = execEvents?.cnt ?? 0;
383
- contentPatchRate = execCount > 0 ? patchCount / execCount : 0;
344
+ if (this.#lifecycleEventRepo) {
345
+ const patchCount = this.#lifecycleEventRepo.countByTrigger('content-patch-complete');
346
+ const execCount = this.#lifecycleEventRepo.countByTriggers([
347
+ 'proposal-execution',
348
+ 'proposal-attach',
349
+ ]);
350
+ contentPatchRate = execCount > 0 ? patchCount / execCount : 0;
351
+ }
384
352
  }
385
353
  catch {
386
354
  // table may not exist yet
@@ -389,7 +357,7 @@ export class RecipeLifecycleSupervisor {
389
357
  pendingCount: pending,
390
358
  observingCount: observing,
391
359
  executionRate: total > 0 ? executed / total : 0,
392
- avgObservationDays: 0, // TODO: calculate from resolved proposals
360
+ avgObservationDays: 0,
393
361
  contentPatchRate,
394
362
  };
395
363
  }
@@ -404,30 +372,13 @@ export class RecipeLifecycleSupervisor {
404
372
  }
405
373
  }
406
374
  /* ═══════════════════ DB Helpers ═══════════════════ */
407
- #getRecipeState(recipeId) {
408
- const row = this.#db
409
- .prepare(`SELECT lifecycle FROM knowledge_entries WHERE id = ?`)
410
- .get(recipeId);
411
- return row ?? null;
412
- }
413
- #getRecipeAge(recipeId, now) {
414
- const row = this.#db
415
- .prepare(`SELECT updatedAt FROM knowledge_entries WHERE id = ?`)
416
- .get(recipeId);
417
- return row ? now - row.updatedAt : 0;
375
+ async #getRecipeState(recipeId) {
376
+ const entry = await this.#knowledgeRepo.findById(recipeId);
377
+ return entry ? { lifecycle: entry.lifecycle } : null;
418
378
  }
419
- #rowToEvent(row) {
420
- return {
421
- id: row.id,
422
- recipeId: row.recipe_id,
423
- fromState: row.from_state,
424
- toState: row.to_state,
425
- trigger: row.trigger,
426
- evidence: row.evidence_json ? safeJsonParse(row.evidence_json, null) : null,
427
- proposalId: row.proposal_id ?? null,
428
- operatorId: row.operator_id,
429
- createdAt: row.created_at,
430
- };
379
+ async #getRecipeAge(recipeId, now) {
380
+ const entry = await this.#knowledgeRepo.findById(recipeId);
381
+ return entry ? now - (entry.updatedAt || now) : 0;
431
382
  }
432
383
  /* ═══════════════════ Signal ═══════════════════ */
433
384
  #emitSignal(recipeId, fromState, toState, trigger) {
@@ -444,15 +395,3 @@ export class RecipeLifecycleSupervisor {
444
395
  });
445
396
  }
446
397
  }
447
- /* ────────────────────── Util ────────────────────── */
448
- function safeJsonParse(json, fallback) {
449
- if (!json) {
450
- return fallback;
451
- }
452
- try {
453
- return JSON.parse(json);
454
- }
455
- catch {
456
- return fallback;
457
- }
458
- }
@@ -18,6 +18,8 @@
18
18
  *
19
19
  * @module service/evolution/RecipeRelevanceAuditor
20
20
  */
21
+ import type { ProposalRepository } from '../../repository/evolution/ProposalRepository.js';
22
+ import type KnowledgeRepositoryImpl from '../../repository/knowledge/KnowledgeRepository.impl.js';
21
23
  /** Logger 接口 */
22
24
  interface AuditorLogger {
23
25
  info(msg: string, meta?: Record<string, unknown>): void;
@@ -78,7 +80,8 @@ export interface RelevanceAuditSummary {
78
80
  export declare class RecipeRelevanceAuditor {
79
81
  #private;
80
82
  constructor(opts: {
81
- db: unknown;
83
+ knowledgeRepo: KnowledgeRepositoryImpl;
84
+ proposalRepo?: ProposalRepository;
82
85
  logger?: AuditorLogger;
83
86
  });
84
87
  /**
@@ -59,11 +59,12 @@ const GRACE_PERIOD_DECAY = 7 * 24 * 60 * 60 * 1000; // 7d
59
59
  const GRACE_PERIOD_SEVERE = 3 * 24 * 60 * 60 * 1000; // 3d
60
60
  // ── RecipeRelevanceAuditor ──────────────────────────────────
61
61
  export class RecipeRelevanceAuditor {
62
- #db;
62
+ #knowledgeRepo;
63
+ #proposalRepo;
63
64
  #logger;
64
65
  constructor(opts) {
65
- const dbRaw = opts.db;
66
- this.#db = typeof dbRaw?.getDb === 'function' ? dbRaw.getDb() : opts.db;
66
+ this.#knowledgeRepo = opts.knowledgeRepo;
67
+ this.#proposalRepo = opts.proposalRepo ?? null;
67
68
  this.#logger = opts.logger || { info() { }, warn() { } };
68
69
  }
69
70
  /**
@@ -90,11 +91,11 @@ export class RecipeRelevanceAuditor {
90
91
  depModules.add(edge.to.toLowerCase());
91
92
  }
92
93
  for (const recipe of recipes) {
93
- const fullRecipe = this.#loadFullRecipe(recipe.id);
94
+ const fullRecipe = await this.#loadFullRecipe(recipe.id);
94
95
  if (!fullRecipe) {
95
96
  continue;
96
97
  }
97
- const result = this.#computeRelevanceScore(fullRecipe, {
98
+ const result = await this.#computeRelevanceScore(fullRecipe, {
98
99
  fileSet,
99
100
  entityNames,
100
101
  depModules,
@@ -105,7 +106,7 @@ export class RecipeRelevanceAuditor {
105
106
  summary.results.push(result);
106
107
  // 执行衰退状态转换
107
108
  if (result.verdict === 'dead' || result.verdict === 'severe' || result.verdict === 'decay') {
108
- const executed = this.#executeDecay(result);
109
+ const executed = await this.#executeDecay(result);
109
110
  if (result.verdict === 'dead') {
110
111
  summary.immediateDeprecated += executed ? 1 : 0;
111
112
  }
@@ -126,21 +127,28 @@ export class RecipeRelevanceAuditor {
126
127
  }
127
128
  // ─── 内部方法 ─────────────────────────────────────────
128
129
  /** 从 DB 加载完整 Recipe 数据 */
129
- #loadFullRecipe(id) {
130
+ async #loadFullRecipe(id) {
130
131
  try {
131
- const row = this.#db
132
- .prepare(`SELECT id, title, trigger, category,
133
- content, doClause, coreCode
134
- FROM knowledge_entries WHERE id = ?`)
135
- .get(id);
136
- return row || null;
132
+ const entry = await this.#knowledgeRepo.findById(id);
133
+ if (!entry) {
134
+ return null;
135
+ }
136
+ return {
137
+ id: entry.id,
138
+ title: entry.title,
139
+ trigger: entry.trigger ?? '',
140
+ category: entry.category ?? '',
141
+ content: JSON.stringify(entry.content?.toJSON?.() ?? entry.content ?? {}),
142
+ doClause: entry.doClause ?? null,
143
+ coreCode: entry.coreCode ?? null,
144
+ };
137
145
  }
138
146
  catch {
139
147
  return null;
140
148
  }
141
149
  }
142
150
  /** 计算单个 Recipe 的 relevanceScore */
143
- #computeRelevanceScore(recipe, ctx) {
151
+ async #computeRelevanceScore(recipe, ctx) {
144
152
  const category = recipe.category || '';
145
153
  const weights = {
146
154
  ...DEFAULT_WEIGHTS,
@@ -173,7 +181,7 @@ export class RecipeRelevanceAuditor {
173
181
  }
174
182
  }
175
183
  // 4. 源代码文件存活率(来自 reasoning.sources + content.codeChanges)
176
- const codeFiles = this.#extractCodeFiles(recipe);
184
+ const codeFiles = await this.#extractCodeFiles(recipe);
177
185
  let codeFilesExist = 1.0;
178
186
  if (codeFiles.length > 0) {
179
187
  const existCount = codeFiles.filter((f) => ctx.fileSet.has(f.toLowerCase())).length;
@@ -362,7 +370,7 @@ export class RecipeRelevanceAuditor {
362
370
  return [...new Set(modules)];
363
371
  }
364
372
  /** 从 Recipe 中提取 codeChanges 引用的文件路径 */
365
- #extractCodeFiles(recipe) {
373
+ async #extractCodeFiles(recipe) {
366
374
  const files = [];
367
375
  try {
368
376
  const content = JSON.parse(recipe.content || '{}');
@@ -374,18 +382,15 @@ export class RecipeRelevanceAuditor {
374
382
  }
375
383
  }
376
384
  }
377
- // reasoning.sources 在 content 外层,由下方独立查询处理
378
385
  }
379
386
  catch {
380
387
  /* invalid JSON */
381
388
  }
382
- // 也从 recipesourceFile 来源引用
389
+ // reasoning.sources entry reasoning 属性中
383
390
  try {
384
- const row = this.#db
385
- .prepare(`SELECT reasoning FROM knowledge_entries WHERE id = ?`)
386
- .get(recipe.id);
387
- if (row?.reasoning) {
388
- const reasoning = JSON.parse(row.reasoning);
391
+ const entry = await this.#knowledgeRepo.findById(recipe.id);
392
+ if (entry?.reasoning) {
393
+ const reasoning = (typeof entry.reasoning === 'object' ? entry.reasoning : {});
389
394
  if (Array.isArray(reasoning.sources)) {
390
395
  for (const src of reasoning.sources) {
391
396
  if (typeof src === 'string') {
@@ -402,22 +407,18 @@ export class RecipeRelevanceAuditor {
402
407
  }
403
408
  }
404
409
  catch {
405
- /* invalid JSON */
410
+ /* entry not found */
406
411
  }
407
412
  return [...new Set(files)];
408
413
  }
409
414
  /** 执行衰退状态转换 */
410
- #executeDecay(result) {
415
+ async #executeDecay(result) {
411
416
  try {
412
417
  const now = Date.now();
413
418
  switch (result.verdict) {
414
419
  case 'dead': {
415
- // 直接 deprecated,无需观察
416
- this.#db
417
- .prepare(`UPDATE knowledge_entries SET lifecycle = 'deprecated', updatedAt = ? WHERE id = ?`)
418
- .run(now, result.recipeId);
419
- // 记录已执行的 proposal(审计追溯)
420
- this.#createProposal({
420
+ await this.#knowledgeRepo.updateLifecycle(result.recipeId, 'deprecated');
421
+ await this.#createProposal({
421
422
  targetRecipeId: result.recipeId,
422
423
  type: 'deprecate',
423
424
  source: 'rescan-relevance-audit',
@@ -430,11 +431,8 @@ export class RecipeRelevanceAuditor {
430
431
  return true;
431
432
  }
432
433
  case 'severe': {
433
- // 加速衰退:3 天观察窗口
434
- this.#db
435
- .prepare(`UPDATE knowledge_entries SET lifecycle = 'decaying', updatedAt = ? WHERE id = ?`)
436
- .run(now, result.recipeId);
437
- this.#createProposal({
434
+ await this.#knowledgeRepo.updateLifecycle(result.recipeId, 'decaying');
435
+ await this.#createProposal({
438
436
  targetRecipeId: result.recipeId,
439
437
  type: 'deprecate',
440
438
  source: 'rescan-relevance-audit',
@@ -447,11 +445,8 @@ export class RecipeRelevanceAuditor {
447
445
  return true;
448
446
  }
449
447
  case 'decay': {
450
- // 加速衰退:7 天观察窗口
451
- this.#db
452
- .prepare(`UPDATE knowledge_entries SET lifecycle = 'decaying', updatedAt = ? WHERE id = ?`)
453
- .run(now, result.recipeId);
454
- this.#createProposal({
448
+ await this.#knowledgeRepo.updateLifecycle(result.recipeId, 'decaying');
449
+ await this.#createProposal({
455
450
  targetRecipeId: result.recipeId,
456
451
  type: 'deprecate',
457
452
  source: 'rescan-relevance-audit',
@@ -474,15 +469,21 @@ export class RecipeRelevanceAuditor {
474
469
  }
475
470
  }
476
471
  /** 创建 evolution proposal */
477
- #createProposal(input) {
472
+ async #createProposal(input) {
478
473
  try {
479
- const id = `ep-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
480
- this.#db
481
- .prepare(`INSERT INTO evolution_proposals
482
- (id, type, target_recipe_id, related_recipe_ids, confidence, source,
483
- description, evidence, status, proposed_at, expires_at)
484
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
485
- .run(id, input.type, input.targetRecipeId, '[]', 0.95, input.source, input.description, JSON.stringify([input.evidence]), input.status, Date.now(), input.expiresAt);
474
+ if (this.#proposalRepo) {
475
+ this.#proposalRepo.create({
476
+ type: input.type,
477
+ targetRecipeId: input.targetRecipeId,
478
+ relatedRecipeIds: [],
479
+ confidence: 0.95,
480
+ source: input.source,
481
+ description: input.description,
482
+ evidence: [input.evidence],
483
+ status: input.status,
484
+ expiresAt: input.expiresAt,
485
+ });
486
+ }
486
487
  }
487
488
  catch (err) {
488
489
  const msg = err instanceof Error ? err.message : String(err);