autosnippet 3.3.7 → 3.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
- package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
- package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +7 -4
- package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
- package/dist/lib/agent/core/LoopContext.d.ts +1 -0
- package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
- package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
- package/dist/lib/agent/memory/ActiveContext.js +0 -2
- package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
- package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
- package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
- package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
- package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
- package/dist/lib/agent/memory/MemoryStore.js +196 -261
- package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
- package/dist/lib/agent/memory/PersistentMemory.js +4 -5
- package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
- package/dist/lib/agent/memory/SessionStore.js +0 -2
- package/dist/lib/agent/tools/ast-graph.js +21 -19
- package/dist/lib/agent/tools/infrastructure.js +3 -2
- package/dist/lib/agent/tools/project-access.d.ts +2 -2
- package/dist/lib/agent/tools/project-access.js +5 -4
- package/dist/lib/bootstrap.js +2 -1
- package/dist/lib/cli/AiScanService.js +4 -17
- package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
- package/dist/lib/cli/KnowledgeSyncService.js +23 -51
- package/dist/lib/core/ast/ProjectGraph.js +5 -27
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +0 -2
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
- package/dist/lib/domain/dimension/DimensionSop.js +44 -33
- package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
- package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
- package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
- package/dist/lib/domain/knowledge/index.d.ts +2 -1
- package/dist/lib/domain/knowledge/index.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +33 -16
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +7 -3
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +13 -16
- package/dist/lib/external/mcp/handlers/guard.js +15 -24
- package/dist/lib/external/mcp/handlers/panorama.js +9 -9
- package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
- package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
- package/dist/lib/external/mcp/handlers/search.js +3 -1
- package/dist/lib/external/mcp/handlers/skill.js +4 -4
- package/dist/lib/external/mcp/handlers/structure.js +8 -12
- package/dist/lib/external/mcp/handlers/system.js +10 -34
- package/dist/lib/http/routes/ai.js +11 -13
- package/dist/lib/http/routes/guardReport.js +3 -5
- package/dist/lib/http/routes/panorama.js +12 -12
- package/dist/lib/http/routes/recipes.js +59 -8
- package/dist/lib/http/routes/remote.js +3 -13
- package/dist/lib/http/routes/search.js +11 -8
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
- package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
- package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
- package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
- package/dist/lib/injection/ServiceContainer.js +7 -4
- package/dist/lib/injection/ServiceMap.d.ts +20 -0
- package/dist/lib/injection/modules/AppModule.js +2 -1
- package/dist/lib/injection/modules/GuardModule.js +5 -5
- package/dist/lib/injection/modules/InfraModule.js +60 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
- package/dist/lib/injection/modules/PanoramaModule.js +16 -10
- package/dist/lib/injection/modules/VectorModule.js +3 -0
- package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
- package/dist/lib/repository/audit/AuditRepository.js +272 -0
- package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
- package/dist/lib/repository/base/RepositoryBase.js +32 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
- package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
- package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
- package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
- package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
- package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
- package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
- package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
- package/dist/lib/repository/memory/MemoryRepository.js +260 -0
- package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
- package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
- package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
- package/dist/lib/repository/session/SessionRepository.js +110 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
- package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
- package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
- package/dist/lib/service/cleanup/CleanupService.js +8 -4
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
- package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
- package/dist/lib/service/evolution/ContentPatcher.js +48 -19
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
- package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
- package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
- package/dist/lib/service/evolution/DecayDetector.js +63 -57
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
- package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
- package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
- package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
- package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
- package/dist/lib/service/evolution/StagingManager.js +37 -95
- package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
- package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
- package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
- package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
- package/dist/lib/service/guard/ReverseGuard.js +21 -31
- package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
- package/dist/lib/service/guard/ViolationsStore.js +75 -69
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +39 -63
- package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -512
- package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
- package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
- package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
- package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
- package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
- package/dist/lib/service/knowledge/KnowledgeService.js +76 -38
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
- package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +5 -3
- package/dist/lib/service/panorama/CouplingAnalyzer.js +102 -39
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
- package/dist/lib/service/panorama/DimensionAnalyzer.js +72 -25
- package/dist/lib/service/panorama/LayerInferrer.js +1 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +7 -6
- package/dist/lib/service/panorama/ModuleDiscoverer.js +174 -82
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +10 -3
- package/dist/lib/service/panorama/PanoramaAggregator.js +67 -79
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
- package/dist/lib/service/panorama/PanoramaScanner.js +32 -31
- package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
- package/dist/lib/service/panorama/PanoramaService.js +41 -66
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +3 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +8 -5
- package/dist/lib/service/panorama/RoleRefiner.js +52 -283
- package/dist/lib/service/panorama/TechStackProfiler.js +7 -119
- package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
- package/dist/lib/service/quality/QualityScorer.js +157 -83
- package/dist/lib/service/search/SearchEngine.d.ts +1 -0
- package/dist/lib/service/search/SearchEngine.js +32 -37
- package/dist/lib/service/signal/HitRecorder.js +5 -5
- package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
- package/dist/lib/service/skills/SignalCollector.d.ts +5 -8
- package/dist/lib/service/skills/SignalCollector.js +28 -55
- package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
- package/dist/lib/service/skills/SkillAdvisor.js +30 -79
- package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
- package/dist/lib/service/vector/SyncCoordinator.js +25 -3
- package/dist/lib/service/vector/VectorService.d.ts +2 -0
- package/dist/lib/service/vector/VectorService.js +3 -0
- package/dist/lib/service/wiki/WikiGenerator.js +1 -1
- package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
- package/dist/lib/shared/LanguageProfiles.js +939 -0
- package/dist/lib/shared/LanguageService.d.ts +6 -0
- package/dist/lib/shared/LanguageService.js +16 -0
- package/dist/lib/shared/constants.d.ts +19 -19
- package/dist/lib/shared/constants.js +10 -10
- package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
- package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
- package/dist/lib/types/project-snapshot-builder.js +0 -1
- package/dist/lib/types/project-snapshot.d.ts +0 -1
- package/dist/lib/types/project-snapshot.js +0 -1
- package/dist/lib/types/snapshot-views.d.ts +0 -2
- package/dist/lib/types/snapshot-views.js +0 -1
- package/package.json +2 -1
- package/dashboard/dist/assets/icons-FHns2ypa.js +0 -1
- package/dashboard/dist/assets/index-BRJv5Y3r.js +0 -135
- package/dashboard/dist/assets/index-DzoB7kxK.css +0 -1
- package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
- package/dist/lib/repository/base/BaseRepository.js +0 -226
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ProposalRepository — evolution_proposals 表 CRUD
|
|
2
|
+
* ProposalRepository — evolution_proposals 表 CRUD (Drizzle ORM)
|
|
3
3
|
*
|
|
4
4
|
* 操作 evolution_proposals 表,存储进化提案(merge/supersede/enhance/deprecate/
|
|
5
5
|
* reorganize/contradiction/correction)。
|
|
@@ -8,8 +8,14 @@
|
|
|
8
8
|
* - 去重:同 target + 同 type 不允许多个 observing 状态的 Proposal
|
|
9
9
|
* - Rate Limit:同一 target 不允许同时存在多个相同类型的 observing Proposal
|
|
10
10
|
* - JSON 字段(evidence/related_recipe_ids)序列化/反序列化
|
|
11
|
+
*
|
|
12
|
+
* Drizzle 迁移策略 (Phase 5a):
|
|
13
|
+
* - 全部 raw SQL → Drizzle 类型安全 API
|
|
14
|
+
* - 构造器接收 DrizzleDB(不再需要 raw Database)
|
|
11
15
|
*/
|
|
12
16
|
import { randomBytes } from 'node:crypto';
|
|
17
|
+
import { and, count, desc, eq, inArray, lte } from 'drizzle-orm';
|
|
18
|
+
import { evolutionProposals } from '../../infrastructure/database/drizzle/schema.js';
|
|
13
19
|
/* ────────────────────── Constants ────────────────────── */
|
|
14
20
|
/** 默认观察窗口:7 天 */
|
|
15
21
|
const DEFAULT_OBSERVATION_WINDOW = 7 * 24 * 60 * 60 * 1000;
|
|
@@ -35,9 +41,9 @@ const AUTO_OBSERVE_THRESHOLDS = {
|
|
|
35
41
|
};
|
|
36
42
|
/* ────────────────────── Class ────────────────────── */
|
|
37
43
|
export class ProposalRepository {
|
|
38
|
-
#
|
|
39
|
-
constructor(
|
|
40
|
-
this.#
|
|
44
|
+
#drizzle;
|
|
45
|
+
constructor(drizzle) {
|
|
46
|
+
this.#drizzle = drizzle;
|
|
41
47
|
}
|
|
42
48
|
/* ═══════════════════ Create ═══════════════════ */
|
|
43
49
|
/**
|
|
@@ -73,55 +79,66 @@ export class ProposalRepository {
|
|
|
73
79
|
resolvedBy: null,
|
|
74
80
|
resolution: null,
|
|
75
81
|
};
|
|
76
|
-
this.#
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
this.#drizzle
|
|
83
|
+
.insert(evolutionProposals)
|
|
84
|
+
.values({
|
|
85
|
+
id: record.id,
|
|
86
|
+
type: record.type,
|
|
87
|
+
targetRecipeId: record.targetRecipeId,
|
|
88
|
+
relatedRecipeIds: JSON.stringify(record.relatedRecipeIds),
|
|
89
|
+
confidence: record.confidence,
|
|
90
|
+
source: record.source,
|
|
91
|
+
description: record.description,
|
|
92
|
+
evidence: JSON.stringify(record.evidence),
|
|
93
|
+
status: record.status,
|
|
94
|
+
proposedAt: record.proposedAt,
|
|
95
|
+
expiresAt: record.expiresAt,
|
|
96
|
+
})
|
|
97
|
+
.run();
|
|
81
98
|
return record;
|
|
82
99
|
}
|
|
83
100
|
/* ═══════════════════ Read ═══════════════════ */
|
|
84
101
|
/** 按 ID 查询 */
|
|
85
102
|
findById(id) {
|
|
86
|
-
const row = this.#
|
|
103
|
+
const row = this.#drizzle
|
|
104
|
+
.select()
|
|
105
|
+
.from(evolutionProposals)
|
|
106
|
+
.where(eq(evolutionProposals.id, id))
|
|
107
|
+
.limit(1)
|
|
108
|
+
.get();
|
|
87
109
|
return row ? ProposalRepository.#mapRow(row) : null;
|
|
88
110
|
}
|
|
89
111
|
/** 按条件查询 */
|
|
90
112
|
find(filter = {}) {
|
|
91
113
|
const conditions = [];
|
|
92
|
-
const params = [];
|
|
93
114
|
if (filter.status) {
|
|
94
115
|
if (Array.isArray(filter.status)) {
|
|
95
|
-
|
|
96
|
-
conditions.push(`status IN (${placeholders})`);
|
|
97
|
-
params.push(...filter.status);
|
|
116
|
+
conditions.push(inArray(evolutionProposals.status, filter.status));
|
|
98
117
|
}
|
|
99
118
|
else {
|
|
100
|
-
conditions.push(
|
|
101
|
-
params.push(filter.status);
|
|
119
|
+
conditions.push(eq(evolutionProposals.status, filter.status));
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
if (filter.type) {
|
|
105
|
-
conditions.push(
|
|
106
|
-
params.push(filter.type);
|
|
123
|
+
conditions.push(eq(evolutionProposals.type, filter.type));
|
|
107
124
|
}
|
|
108
125
|
if (filter.targetRecipeId) {
|
|
109
|
-
conditions.push(
|
|
110
|
-
params.push(filter.targetRecipeId);
|
|
126
|
+
conditions.push(eq(evolutionProposals.targetRecipeId, filter.targetRecipeId));
|
|
111
127
|
}
|
|
112
128
|
if (filter.source) {
|
|
113
|
-
conditions.push(
|
|
114
|
-
params.push(filter.source);
|
|
129
|
+
conditions.push(eq(evolutionProposals.source, filter.source));
|
|
115
130
|
}
|
|
116
131
|
if (filter.expiredBefore) {
|
|
117
|
-
conditions.push(
|
|
118
|
-
params.push(filter.expiredBefore);
|
|
132
|
+
conditions.push(lte(evolutionProposals.expiresAt, filter.expiredBefore));
|
|
119
133
|
}
|
|
120
|
-
const
|
|
121
|
-
const rows = this.#
|
|
122
|
-
.
|
|
123
|
-
.
|
|
124
|
-
|
|
134
|
+
const condition = conditions.length > 0 ? and(...conditions) : undefined;
|
|
135
|
+
const rows = this.#drizzle
|
|
136
|
+
.select()
|
|
137
|
+
.from(evolutionProposals)
|
|
138
|
+
.where(condition)
|
|
139
|
+
.orderBy(desc(evolutionProposals.proposedAt))
|
|
140
|
+
.all();
|
|
141
|
+
return rows.map((r) => ProposalRepository.#mapRow(r));
|
|
125
142
|
}
|
|
126
143
|
/** 查询已到期的 observing 状态 Proposal */
|
|
127
144
|
findExpiredObserving() {
|
|
@@ -152,44 +169,81 @@ export class ProposalRepository {
|
|
|
152
169
|
return false;
|
|
153
170
|
}
|
|
154
171
|
const expiresAt = now + (OBSERVATION_WINDOWS[proposal.type] ?? DEFAULT_OBSERVATION_WINDOW);
|
|
155
|
-
const result = this.#
|
|
156
|
-
.
|
|
157
|
-
.
|
|
172
|
+
const result = this.#drizzle
|
|
173
|
+
.update(evolutionProposals)
|
|
174
|
+
.set({ status: 'observing', expiresAt })
|
|
175
|
+
.where(and(eq(evolutionProposals.id, id), eq(evolutionProposals.status, 'pending')))
|
|
176
|
+
.run();
|
|
158
177
|
return result.changes > 0;
|
|
159
178
|
}
|
|
160
179
|
/** 标记 Proposal 为已执行 */
|
|
161
180
|
markExecuted(id, resolution, resolvedBy = 'auto') {
|
|
162
|
-
const result = this.#
|
|
163
|
-
.
|
|
164
|
-
.
|
|
181
|
+
const result = this.#drizzle
|
|
182
|
+
.update(evolutionProposals)
|
|
183
|
+
.set({
|
|
184
|
+
status: 'executed',
|
|
185
|
+
resolvedAt: Date.now(),
|
|
186
|
+
resolvedBy,
|
|
187
|
+
resolution,
|
|
188
|
+
})
|
|
189
|
+
.where(and(eq(evolutionProposals.id, id), eq(evolutionProposals.status, 'observing')))
|
|
190
|
+
.run();
|
|
165
191
|
return result.changes > 0;
|
|
166
192
|
}
|
|
167
193
|
/** 标记 Proposal 为已拒绝 */
|
|
168
194
|
markRejected(id, resolution, resolvedBy = 'auto') {
|
|
169
|
-
const result = this.#
|
|
170
|
-
.
|
|
171
|
-
.
|
|
195
|
+
const result = this.#drizzle
|
|
196
|
+
.update(evolutionProposals)
|
|
197
|
+
.set({
|
|
198
|
+
status: 'rejected',
|
|
199
|
+
resolvedAt: Date.now(),
|
|
200
|
+
resolvedBy,
|
|
201
|
+
resolution,
|
|
202
|
+
})
|
|
203
|
+
.where(and(eq(evolutionProposals.id, id), inArray(evolutionProposals.status, ['pending', 'observing'])))
|
|
204
|
+
.run();
|
|
172
205
|
return result.changes > 0;
|
|
173
206
|
}
|
|
174
207
|
/** 标记 Proposal 为过期 */
|
|
175
208
|
markExpired(id) {
|
|
176
|
-
const result = this.#
|
|
177
|
-
.
|
|
178
|
-
.
|
|
209
|
+
const result = this.#drizzle
|
|
210
|
+
.update(evolutionProposals)
|
|
211
|
+
.set({
|
|
212
|
+
status: 'expired',
|
|
213
|
+
resolvedAt: Date.now(),
|
|
214
|
+
})
|
|
215
|
+
.where(and(eq(evolutionProposals.id, id), inArray(evolutionProposals.status, ['pending', 'observing'])))
|
|
216
|
+
.run();
|
|
179
217
|
return result.changes > 0;
|
|
180
218
|
}
|
|
181
219
|
/** 更新 evidence(用于追加观察期指标快照) */
|
|
182
220
|
updateEvidence(id, evidence) {
|
|
183
|
-
const result = this.#
|
|
184
|
-
.
|
|
185
|
-
.
|
|
221
|
+
const result = this.#drizzle
|
|
222
|
+
.update(evolutionProposals)
|
|
223
|
+
.set({ evidence: JSON.stringify(evidence) })
|
|
224
|
+
.where(eq(evolutionProposals.id, id))
|
|
225
|
+
.run();
|
|
186
226
|
return result.changes > 0;
|
|
187
227
|
}
|
|
228
|
+
/* ═══════════════════ Delete ═══════════════════ */
|
|
229
|
+
/** 按 target Recipe ID 删除所有 Proposal(用于知识删除时清理关联提案) */
|
|
230
|
+
deleteByTargetRecipeId(targetRecipeId) {
|
|
231
|
+
const result = this.#drizzle
|
|
232
|
+
.delete(evolutionProposals)
|
|
233
|
+
.where(eq(evolutionProposals.targetRecipeId, targetRecipeId))
|
|
234
|
+
.run();
|
|
235
|
+
return result.changes;
|
|
236
|
+
}
|
|
188
237
|
/* ═══════════════════ Stats ═══════════════════ */
|
|
189
238
|
/** 统计各状态的 Proposal 数量 */
|
|
190
239
|
stats() {
|
|
191
|
-
const rows = this.#
|
|
192
|
-
.
|
|
240
|
+
const rows = this.#drizzle
|
|
241
|
+
.select({
|
|
242
|
+
status: evolutionProposals.status,
|
|
243
|
+
count: count(),
|
|
244
|
+
})
|
|
245
|
+
.from(evolutionProposals)
|
|
246
|
+
.groupBy(evolutionProposals.status)
|
|
193
247
|
.all();
|
|
194
248
|
const result = {
|
|
195
249
|
pending: 0,
|
|
@@ -206,9 +260,12 @@ export class ProposalRepository {
|
|
|
206
260
|
/* ═══════════════════ Private ═══════════════════ */
|
|
207
261
|
/** 去重检查:同 target + 同 type 是否已有 pending/observing Proposal */
|
|
208
262
|
#hasDuplicate(targetRecipeId, type) {
|
|
209
|
-
const row = this.#
|
|
210
|
-
.
|
|
211
|
-
.
|
|
263
|
+
const row = this.#drizzle
|
|
264
|
+
.select({ id: evolutionProposals.id })
|
|
265
|
+
.from(evolutionProposals)
|
|
266
|
+
.where(and(eq(evolutionProposals.targetRecipeId, targetRecipeId), eq(evolutionProposals.type, type), inArray(evolutionProposals.status, ['pending', 'observing'])))
|
|
267
|
+
.limit(1)
|
|
268
|
+
.get();
|
|
212
269
|
return row !== undefined;
|
|
213
270
|
}
|
|
214
271
|
/** 根据 type + confidence 判断初始状态 */
|
|
@@ -221,22 +278,22 @@ export class ProposalRepository {
|
|
|
221
278
|
const rand = randomBytes(4).toString('hex');
|
|
222
279
|
return `ep-${timestamp}-${rand}`;
|
|
223
280
|
}
|
|
224
|
-
/**
|
|
281
|
+
/** Drizzle Row → ProposalRecord */
|
|
225
282
|
static #mapRow(row) {
|
|
226
283
|
return {
|
|
227
284
|
id: row.id,
|
|
228
285
|
type: row.type,
|
|
229
|
-
targetRecipeId: row.
|
|
230
|
-
relatedRecipeIds: safeJsonParse(row.
|
|
286
|
+
targetRecipeId: row.targetRecipeId,
|
|
287
|
+
relatedRecipeIds: safeJsonParse(row.relatedRecipeIds, []),
|
|
231
288
|
confidence: row.confidence,
|
|
232
289
|
source: row.source,
|
|
233
|
-
description: row.description,
|
|
290
|
+
description: row.description ?? '',
|
|
234
291
|
evidence: safeJsonParse(row.evidence, []),
|
|
235
292
|
status: row.status,
|
|
236
|
-
proposedAt: row.
|
|
237
|
-
expiresAt: row.
|
|
238
|
-
resolvedAt: row.
|
|
239
|
-
resolvedBy: row.
|
|
293
|
+
proposedAt: row.proposedAt,
|
|
294
|
+
expiresAt: row.expiresAt,
|
|
295
|
+
resolvedAt: row.resolvedAt ?? null,
|
|
296
|
+
resolvedBy: row.resolvedBy ?? null,
|
|
240
297
|
resolution: row.resolution ?? null,
|
|
241
298
|
};
|
|
242
299
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardViolationRepository — Guard 违反记录的仓储实现
|
|
3
|
+
*
|
|
4
|
+
* 从 ViolationsStore 提取的数据操作,
|
|
5
|
+
* 使用 Drizzle 类型安全 API 操作 guard_violations 表。
|
|
6
|
+
*/
|
|
7
|
+
import { guardViolations } from '../../infrastructure/database/drizzle/schema.js';
|
|
8
|
+
import { RepositoryBase } from '../base/RepositoryBase.js';
|
|
9
|
+
export interface ViolationRecord {
|
|
10
|
+
ruleId?: string;
|
|
11
|
+
severity?: string;
|
|
12
|
+
message?: string;
|
|
13
|
+
line?: number;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface GuardViolationEntity {
|
|
17
|
+
id: string;
|
|
18
|
+
filePath: string;
|
|
19
|
+
triggeredAt: string;
|
|
20
|
+
violationCount: number;
|
|
21
|
+
summary: string;
|
|
22
|
+
violations: ViolationRecord[];
|
|
23
|
+
createdAt: number;
|
|
24
|
+
}
|
|
25
|
+
export interface GuardViolationInsert {
|
|
26
|
+
id: string;
|
|
27
|
+
filePath: string;
|
|
28
|
+
triggeredAt: string;
|
|
29
|
+
violationCount: number;
|
|
30
|
+
summary?: string;
|
|
31
|
+
violations: ViolationRecord[];
|
|
32
|
+
createdAt: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ViolationStats {
|
|
35
|
+
totalRuns: number;
|
|
36
|
+
totalViolations: number;
|
|
37
|
+
averageViolationsPerRun: string | number;
|
|
38
|
+
lastRunAt: string | null;
|
|
39
|
+
}
|
|
40
|
+
export interface ViolationStatByRule {
|
|
41
|
+
ruleId: string | null;
|
|
42
|
+
severity: string | null;
|
|
43
|
+
count: number;
|
|
44
|
+
}
|
|
45
|
+
export interface PaginatedViolations {
|
|
46
|
+
data: GuardViolationEntity[];
|
|
47
|
+
pagination: {
|
|
48
|
+
page: number;
|
|
49
|
+
limit: number;
|
|
50
|
+
total: number;
|
|
51
|
+
pages: number;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export declare class GuardViolationRepositoryImpl extends RepositoryBase<typeof guardViolations, GuardViolationEntity> {
|
|
55
|
+
#private;
|
|
56
|
+
/** 最大保留条数 */
|
|
57
|
+
static readonly MAX_RUNS = 200;
|
|
58
|
+
constructor(drizzle: ConstructorParameters<typeof RepositoryBase<typeof guardViolations, GuardViolationEntity>>[0]);
|
|
59
|
+
findById(id: string): Promise<GuardViolationEntity | null>;
|
|
60
|
+
create(data: GuardViolationInsert): Promise<GuardViolationEntity>;
|
|
61
|
+
delete(id: string): Promise<boolean>;
|
|
62
|
+
/** 获取指定文件的最近一条记录 (用于去重比较) */
|
|
63
|
+
getLastByFile(filePath: string): Promise<{
|
|
64
|
+
id: string;
|
|
65
|
+
violationsJson: string;
|
|
66
|
+
} | null>;
|
|
67
|
+
/** 刷新已有记录的时间戳 (去重命中时) */
|
|
68
|
+
refreshTimestamp(id: string): Promise<void>;
|
|
69
|
+
/** 获取所有运行记录 (最旧在前) */
|
|
70
|
+
getRuns(): Promise<GuardViolationEntity[]>;
|
|
71
|
+
/** 按文件路径查询 */
|
|
72
|
+
getRunsByFile(filePath: string): Promise<GuardViolationEntity[]>;
|
|
73
|
+
/** 获取最近 N 条记录 */
|
|
74
|
+
getRecentRuns(n?: number): Promise<GuardViolationEntity[]>;
|
|
75
|
+
/** 分页查询 */
|
|
76
|
+
list(filters?: {
|
|
77
|
+
file?: string;
|
|
78
|
+
}, options?: {
|
|
79
|
+
page?: number;
|
|
80
|
+
limit?: number;
|
|
81
|
+
}): Promise<PaginatedViolations>;
|
|
82
|
+
/** 获取统计汇总 */
|
|
83
|
+
getStats(): Promise<ViolationStats>;
|
|
84
|
+
/**
|
|
85
|
+
* 按规则 ID 聚合统计
|
|
86
|
+
* 利用 SQLite json_each 展开 violations_json 数组
|
|
87
|
+
*
|
|
88
|
+
* json_each 是 SQLite 专有函数,Drizzle 无 typed API (ORM limitation)
|
|
89
|
+
*/
|
|
90
|
+
getStatsByRule(): Promise<ViolationStatByRule[]>;
|
|
91
|
+
/** 截断超限记录,保留最新 maxRuns 条 */
|
|
92
|
+
enforceCapacity(maxRuns?: number): Promise<number>;
|
|
93
|
+
/** 清空所有记录 */
|
|
94
|
+
clearAll(): Promise<void>;
|
|
95
|
+
/** 清除指定文件的记录 */
|
|
96
|
+
clearByFile(filePath: string): Promise<number>;
|
|
97
|
+
/**
|
|
98
|
+
* 最近的 violation JSON 列表 (CoverageAnalyzer.#getRecentViolations)
|
|
99
|
+
*/
|
|
100
|
+
findRecentViolationsJson(limit: number): Array<{
|
|
101
|
+
filePath: string;
|
|
102
|
+
violationsJson: string;
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardViolationRepository — Guard 违反记录的仓储实现
|
|
3
|
+
*
|
|
4
|
+
* 从 ViolationsStore 提取的数据操作,
|
|
5
|
+
* 使用 Drizzle 类型安全 API 操作 guard_violations 表。
|
|
6
|
+
*/
|
|
7
|
+
import { asc, count, desc, eq, sql } from 'drizzle-orm';
|
|
8
|
+
import { guardViolations } from '../../infrastructure/database/drizzle/schema.js';
|
|
9
|
+
import { RepositoryBase } from '../base/RepositoryBase.js';
|
|
10
|
+
/* ═══ Repository 实现 ═══ */
|
|
11
|
+
export class GuardViolationRepositoryImpl extends RepositoryBase {
|
|
12
|
+
/** 最大保留条数 */
|
|
13
|
+
static MAX_RUNS = 200;
|
|
14
|
+
constructor(drizzle) {
|
|
15
|
+
super(drizzle, guardViolations);
|
|
16
|
+
}
|
|
17
|
+
/* ─── CRUD ─── */
|
|
18
|
+
async findById(id) {
|
|
19
|
+
const row = this.drizzle.select().from(this.table).where(eq(this.table.id, id)).limit(1).get();
|
|
20
|
+
return row ? this.#mapRow(row) : null;
|
|
21
|
+
}
|
|
22
|
+
async create(data) {
|
|
23
|
+
this.drizzle
|
|
24
|
+
.insert(this.table)
|
|
25
|
+
.values({
|
|
26
|
+
id: data.id,
|
|
27
|
+
filePath: data.filePath,
|
|
28
|
+
triggeredAt: data.triggeredAt,
|
|
29
|
+
violationCount: data.violationCount,
|
|
30
|
+
summary: data.summary ?? '',
|
|
31
|
+
violationsJson: JSON.stringify(data.violations),
|
|
32
|
+
createdAt: data.createdAt,
|
|
33
|
+
})
|
|
34
|
+
.run();
|
|
35
|
+
return (await this.findById(data.id));
|
|
36
|
+
}
|
|
37
|
+
async delete(id) {
|
|
38
|
+
const result = this.drizzle.delete(this.table).where(eq(this.table.id, id)).run();
|
|
39
|
+
return result.changes > 0;
|
|
40
|
+
}
|
|
41
|
+
/* ─── 去重查询 ─── */
|
|
42
|
+
/** 获取指定文件的最近一条记录 (用于去重比较) */
|
|
43
|
+
async getLastByFile(filePath) {
|
|
44
|
+
const row = this.drizzle
|
|
45
|
+
.select({
|
|
46
|
+
id: this.table.id,
|
|
47
|
+
violationsJson: this.table.violationsJson,
|
|
48
|
+
})
|
|
49
|
+
.from(this.table)
|
|
50
|
+
.where(eq(this.table.filePath, filePath))
|
|
51
|
+
.orderBy(desc(this.table.createdAt))
|
|
52
|
+
.limit(1)
|
|
53
|
+
.get();
|
|
54
|
+
return row ? { id: row.id, violationsJson: row.violationsJson ?? '[]' } : null;
|
|
55
|
+
}
|
|
56
|
+
/** 刷新已有记录的时间戳 (去重命中时) */
|
|
57
|
+
async refreshTimestamp(id) {
|
|
58
|
+
this.drizzle
|
|
59
|
+
.update(this.table)
|
|
60
|
+
.set({
|
|
61
|
+
triggeredAt: new Date().toISOString(),
|
|
62
|
+
createdAt: Math.floor(Date.now() / 1000),
|
|
63
|
+
})
|
|
64
|
+
.where(eq(this.table.id, id))
|
|
65
|
+
.run();
|
|
66
|
+
}
|
|
67
|
+
/* ─── 查询 ─── */
|
|
68
|
+
/** 获取所有运行记录 (最旧在前) */
|
|
69
|
+
async getRuns() {
|
|
70
|
+
const rows = this.drizzle.select().from(this.table).orderBy(asc(this.table.createdAt)).all();
|
|
71
|
+
return rows.map((r) => this.#mapRow(r));
|
|
72
|
+
}
|
|
73
|
+
/** 按文件路径查询 */
|
|
74
|
+
async getRunsByFile(filePath) {
|
|
75
|
+
const rows = this.drizzle
|
|
76
|
+
.select()
|
|
77
|
+
.from(this.table)
|
|
78
|
+
.where(eq(this.table.filePath, filePath))
|
|
79
|
+
.orderBy(asc(this.table.createdAt))
|
|
80
|
+
.all();
|
|
81
|
+
return rows.map((r) => this.#mapRow(r));
|
|
82
|
+
}
|
|
83
|
+
/** 获取最近 N 条记录 */
|
|
84
|
+
async getRecentRuns(n = 20) {
|
|
85
|
+
const rows = this.drizzle
|
|
86
|
+
.select()
|
|
87
|
+
.from(this.table)
|
|
88
|
+
.orderBy(desc(this.table.createdAt), sql `rowid DESC`)
|
|
89
|
+
.limit(n)
|
|
90
|
+
.all();
|
|
91
|
+
return rows.reverse().map((r) => this.#mapRow(r));
|
|
92
|
+
}
|
|
93
|
+
/** 分页查询 */
|
|
94
|
+
async list(filters = {}, options = {}) {
|
|
95
|
+
const { page = 1, limit = 20 } = options;
|
|
96
|
+
const offset = (page - 1) * limit;
|
|
97
|
+
const condition = filters.file ? eq(this.table.filePath, filters.file) : undefined;
|
|
98
|
+
const rows = this.drizzle
|
|
99
|
+
.select()
|
|
100
|
+
.from(this.table)
|
|
101
|
+
.where(condition)
|
|
102
|
+
.orderBy(desc(this.table.createdAt))
|
|
103
|
+
.limit(limit)
|
|
104
|
+
.offset(offset)
|
|
105
|
+
.all();
|
|
106
|
+
const [totalRow] = this.drizzle
|
|
107
|
+
.select({ cnt: count() })
|
|
108
|
+
.from(this.table)
|
|
109
|
+
.where(condition)
|
|
110
|
+
.all();
|
|
111
|
+
const total = totalRow?.cnt ?? 0;
|
|
112
|
+
return {
|
|
113
|
+
data: rows.map((r) => this.#mapRow(r)),
|
|
114
|
+
pagination: { page, limit, total, pages: Math.ceil(total / limit) },
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/* ─── 统计 ─── */
|
|
118
|
+
/** 获取统计汇总 */
|
|
119
|
+
async getStats() {
|
|
120
|
+
const [row] = this.drizzle
|
|
121
|
+
.select({
|
|
122
|
+
totalRuns: count(),
|
|
123
|
+
totalViolations: sql `COALESCE(SUM(${this.table.violationCount}), 0)`,
|
|
124
|
+
lastRunAt: sql `MAX(${this.table.triggeredAt})`,
|
|
125
|
+
})
|
|
126
|
+
.from(this.table)
|
|
127
|
+
.all();
|
|
128
|
+
const totalRuns = row?.totalRuns ?? 0;
|
|
129
|
+
const totalViolations = row?.totalViolations ?? 0;
|
|
130
|
+
return {
|
|
131
|
+
totalRuns,
|
|
132
|
+
totalViolations,
|
|
133
|
+
averageViolationsPerRun: totalRuns > 0 ? (totalViolations / totalRuns).toFixed(2) : 0,
|
|
134
|
+
lastRunAt: row?.lastRunAt ?? null,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 按规则 ID 聚合统计
|
|
139
|
+
* 利用 SQLite json_each 展开 violations_json 数组
|
|
140
|
+
*
|
|
141
|
+
* json_each 是 SQLite 专有函数,Drizzle 无 typed API (ORM limitation)
|
|
142
|
+
*/
|
|
143
|
+
async getStatsByRule() {
|
|
144
|
+
try {
|
|
145
|
+
const rows = this.drizzle.all(sql `
|
|
146
|
+
SELECT
|
|
147
|
+
json_extract(j.value, '$.ruleId') AS ruleId,
|
|
148
|
+
json_extract(j.value, '$.severity') AS severity,
|
|
149
|
+
COUNT(*) AS count
|
|
150
|
+
FROM ${this.table} gv, json_each(gv.violations_json) j
|
|
151
|
+
WHERE json_extract(j.value, '$.ruleId') IS NOT NULL
|
|
152
|
+
GROUP BY ruleId, severity
|
|
153
|
+
ORDER BY count DESC
|
|
154
|
+
`);
|
|
155
|
+
return rows;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/* ─── 容量控制 ─── */
|
|
162
|
+
/** 截断超限记录,保留最新 maxRuns 条 */
|
|
163
|
+
async enforceCapacity(maxRuns = GuardViolationRepositoryImpl.MAX_RUNS) {
|
|
164
|
+
const result = this.drizzle
|
|
165
|
+
.delete(this.table)
|
|
166
|
+
.where(sql `${this.table.id} NOT IN (
|
|
167
|
+
SELECT ${this.table.id} FROM ${this.table}
|
|
168
|
+
ORDER BY ${this.table.createdAt} DESC
|
|
169
|
+
LIMIT ${maxRuns}
|
|
170
|
+
)`)
|
|
171
|
+
.run();
|
|
172
|
+
return result.changes;
|
|
173
|
+
}
|
|
174
|
+
/** 清空所有记录 */
|
|
175
|
+
async clearAll() {
|
|
176
|
+
this.drizzle.delete(this.table).run();
|
|
177
|
+
}
|
|
178
|
+
/** 清除指定文件的记录 */
|
|
179
|
+
async clearByFile(filePath) {
|
|
180
|
+
const result = this.drizzle.delete(this.table).where(eq(this.table.filePath, filePath)).run();
|
|
181
|
+
return result.changes;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 最近的 violation JSON 列表 (CoverageAnalyzer.#getRecentViolations)
|
|
185
|
+
*/
|
|
186
|
+
findRecentViolationsJson(limit) {
|
|
187
|
+
return this.drizzle
|
|
188
|
+
.select({
|
|
189
|
+
filePath: this.table.filePath,
|
|
190
|
+
violationsJson: this.table.violationsJson,
|
|
191
|
+
})
|
|
192
|
+
.from(this.table)
|
|
193
|
+
.orderBy(desc(this.table.createdAt))
|
|
194
|
+
.limit(limit)
|
|
195
|
+
.all();
|
|
196
|
+
}
|
|
197
|
+
/* ─── 内部辅助 ─── */
|
|
198
|
+
#mapRow(row) {
|
|
199
|
+
return {
|
|
200
|
+
id: row.id,
|
|
201
|
+
filePath: row.filePath,
|
|
202
|
+
triggeredAt: row.triggeredAt,
|
|
203
|
+
violationCount: row.violationCount ?? 0,
|
|
204
|
+
summary: row.summary ?? '',
|
|
205
|
+
violations: safeParseJSON(row.violationsJson, []),
|
|
206
|
+
createdAt: row.createdAt,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function safeParseJSON(str, fallback) {
|
|
211
|
+
try {
|
|
212
|
+
return str ? JSON.parse(str) : fallback;
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return fallback;
|
|
216
|
+
}
|
|
217
|
+
}
|