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
|
@@ -14,9 +14,11 @@ import { ConflictError, NotFoundError, ValidationError } from '../../shared/erro
|
|
|
14
14
|
*/
|
|
15
15
|
export class KnowledgeService {
|
|
16
16
|
_confidenceRouter;
|
|
17
|
+
_edgeRepo;
|
|
17
18
|
_eventBus;
|
|
18
19
|
_fileWriter;
|
|
19
20
|
_knowledgeGraphService;
|
|
21
|
+
_proposalRepo;
|
|
20
22
|
_qualityScorer;
|
|
21
23
|
_skillHooks;
|
|
22
24
|
auditLogger;
|
|
@@ -33,6 +35,8 @@ export class KnowledgeService {
|
|
|
33
35
|
this._confidenceRouter = options.confidenceRouter || null;
|
|
34
36
|
this._qualityScorer = options.qualityScorer || null;
|
|
35
37
|
this._eventBus = options.eventBus || null;
|
|
38
|
+
this._edgeRepo = options.edgeRepo || null;
|
|
39
|
+
this._proposalRepo = options.proposalRepo || null;
|
|
36
40
|
this.logger = Logger.getInstance();
|
|
37
41
|
}
|
|
38
42
|
/* ═══ CRUD ══════════════════════════════════════════════ */
|
|
@@ -93,13 +97,17 @@ export class KnowledgeService {
|
|
|
93
97
|
// 注意: staging 条目由 StagingManager.checkAndPromote() 在到期后自动转为 active。
|
|
94
98
|
// autoApprovable 标记保留,供前端显示「推荐批准」徽章。
|
|
95
99
|
// CursorDelivery 已支持高置信度 staging/pending 条目的交付。
|
|
100
|
+
// ── file-first: 先落盘 .md,再写 DB(文件=真相源) ──
|
|
101
|
+
// fileWriter.persist() 会设置 entry.sourceFile,
|
|
102
|
+
// 后续 repository.create() 自动包含 sourceFile 字段,无需异步回写。
|
|
103
|
+
if (this._fileWriter) {
|
|
104
|
+
this._fileWriter.persist(entry);
|
|
105
|
+
}
|
|
96
106
|
const saved = await this.repository.create(entry);
|
|
97
107
|
// 同步 relations → knowledge_edges
|
|
98
108
|
this._syncRelationsToGraph(saved.id, saved.relations);
|
|
99
109
|
// 自动发现同域条目建立 related 边(best effort, 不阻塞)
|
|
100
110
|
this._autoDiscoverRelations(saved.id, saved).catch((err) => this.logger.warn('_autoDiscoverRelations error', { id: saved.id, error: err.message }));
|
|
101
|
-
// 落盘 .md 文件
|
|
102
|
-
this._persistToFile(saved);
|
|
103
111
|
// 审计日志
|
|
104
112
|
await this._audit('create_knowledge', saved.id, context.userId, {
|
|
105
113
|
title: saved.title,
|
|
@@ -237,13 +245,20 @@ export class KnowledgeService {
|
|
|
237
245
|
throw new ValidationError('No updatable fields provided');
|
|
238
246
|
}
|
|
239
247
|
dbUpdates.updatedAt = Math.floor(Date.now() / 1000);
|
|
248
|
+
// ── file-first: 先落盘 .md,再写 DB(文件=真相源) ──
|
|
249
|
+
if (this._fileWriter) {
|
|
250
|
+
Object.assign(_entry, dbUpdates);
|
|
251
|
+
this._fileWriter.persist(_entry);
|
|
252
|
+
// fileWriter 可能更新 sourceFile,同步到 dbUpdates
|
|
253
|
+
if (_entry.sourceFile) {
|
|
254
|
+
dbUpdates.sourceFile = _entry.sourceFile;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
240
257
|
const updated = await this.repository.update(id, dbUpdates);
|
|
241
258
|
// 若 relations 变更,同步到 knowledge_edges
|
|
242
259
|
if (dbUpdates.relations) {
|
|
243
260
|
this._syncRelationsToGraph(id, data.relations);
|
|
244
261
|
}
|
|
245
|
-
// 落盘
|
|
246
|
-
this._persistToFile(updated);
|
|
247
262
|
await this._audit('update_knowledge', id, context.userId, {
|
|
248
263
|
fields: Object.keys(dbUpdates),
|
|
249
264
|
});
|
|
@@ -523,8 +538,8 @@ export class KnowledgeService {
|
|
|
523
538
|
// 更新 Quality 值对象;同步计算 authority(0‑5)
|
|
524
539
|
const qualityJson = {
|
|
525
540
|
completeness: result.dimensions.completeness,
|
|
526
|
-
adaptation: result.dimensions.
|
|
527
|
-
documentation: result.dimensions.
|
|
541
|
+
adaptation: result.dimensions.deliveryReady,
|
|
542
|
+
documentation: result.dimensions.contentDepth,
|
|
528
543
|
overall: result.score,
|
|
529
544
|
grade: result.grade,
|
|
530
545
|
};
|
|
@@ -542,6 +557,18 @@ export class KnowledgeService {
|
|
|
542
557
|
});
|
|
543
558
|
}
|
|
544
559
|
await this.repository.update(id, updatePayload);
|
|
560
|
+
// ── .md 文件同步: quality 更新后重新落盘,保持文件=真相源 ──
|
|
561
|
+
if (this._fileWriter) {
|
|
562
|
+
try {
|
|
563
|
+
const updated = await this.repository.findById(id);
|
|
564
|
+
if (updated) {
|
|
565
|
+
this._fileWriter.persist(updated);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
/* best effort — 不阻塞质量更新流程 */
|
|
570
|
+
}
|
|
571
|
+
}
|
|
545
572
|
if (context.userId) {
|
|
546
573
|
await this._audit('update_knowledge_quality', id, context.userId, {
|
|
547
574
|
score: result.score,
|
|
@@ -605,19 +632,11 @@ export class KnowledgeService {
|
|
|
605
632
|
if (entry.autoApprovable !== undefined) {
|
|
606
633
|
dbUpdates.autoApprovable = entry.autoApprovable ? 1 : 0;
|
|
607
634
|
}
|
|
608
|
-
|
|
609
|
-
// 文件位置迁移(candidate ↔ recipe 目录)
|
|
635
|
+
// ── file-first: 先迁移 .md 文件,再更新 DB lifecycle(文件=真相源) ──
|
|
610
636
|
if (this._fileWriter) {
|
|
611
|
-
|
|
612
|
-
this._fileWriter.moveOnLifecycleChange(updated);
|
|
613
|
-
}
|
|
614
|
-
catch (err) {
|
|
615
|
-
this.logger.warn('moveOnLifecycleChange failed (non-blocking)', {
|
|
616
|
-
id,
|
|
617
|
-
error: err instanceof Error ? err.message : String(err),
|
|
618
|
-
});
|
|
619
|
-
}
|
|
637
|
+
this._fileWriter.moveOnLifecycleChange(entry);
|
|
620
638
|
}
|
|
639
|
+
const updated = await this.repository.update(id, dbUpdates);
|
|
621
640
|
await this._audit(`${method}_knowledge`, id, context.userId, {
|
|
622
641
|
from: prevLifecycle,
|
|
623
642
|
to: entry.lifecycle,
|
|
@@ -672,24 +691,43 @@ export class KnowledgeService {
|
|
|
672
691
|
}
|
|
673
692
|
/**
|
|
674
693
|
* 为 QualityScorer 适配输入
|
|
675
|
-
* QualityScorer
|
|
694
|
+
* QualityScorer v2 needs: title, trigger, description, language, category,
|
|
695
|
+
* doClause, dontClause, whenClause, coreCode, usageGuide,
|
|
696
|
+
* contentMarkdown, contentRationale, reasoningWhyStandard, reasoningSources,
|
|
697
|
+
* reasoningConfidence, source, headers, tags, views, clicks, rating
|
|
676
698
|
*/
|
|
677
699
|
_adaptForScorer(entry) {
|
|
678
|
-
// 从 Stats 值对象提取 engagement
|
|
700
|
+
// 从 Stats 值对象提取 engagement 指标
|
|
679
701
|
const stats = entry.stats && typeof entry.stats === 'object'
|
|
680
702
|
? entry.stats
|
|
681
703
|
: {};
|
|
704
|
+
// 从 Content 值对象提取深度字段
|
|
705
|
+
const content = entry.content && typeof entry.content === 'object'
|
|
706
|
+
? entry.content
|
|
707
|
+
: {};
|
|
708
|
+
// 从 Reasoning 值对象提取溯源字段
|
|
709
|
+
const reasoning = entry.reasoning && typeof entry.reasoning === 'object'
|
|
710
|
+
? entry.reasoning
|
|
711
|
+
: {};
|
|
682
712
|
return {
|
|
683
713
|
title: entry.title,
|
|
684
714
|
trigger: entry.trigger,
|
|
685
|
-
|
|
715
|
+
description: entry.description || '',
|
|
686
716
|
language: entry.language,
|
|
687
717
|
category: entry.category,
|
|
688
|
-
|
|
689
|
-
|
|
718
|
+
doClause: entry.doClause || '',
|
|
719
|
+
dontClause: entry.dontClause || '',
|
|
720
|
+
whenClause: entry.whenClause || '',
|
|
721
|
+
coreCode: entry.coreCode || '',
|
|
722
|
+
usageGuide: entry.usageGuide || content.markdown || entry.doClause || '',
|
|
723
|
+
contentMarkdown: content.markdown || '',
|
|
724
|
+
contentRationale: content.rationale || '',
|
|
725
|
+
reasoningWhyStandard: reasoning.whyStandard || '',
|
|
726
|
+
reasoningSources: reasoning.sources || [],
|
|
727
|
+
reasoningConfidence: reasoning.confidence || 0,
|
|
728
|
+
source: entry.source || '',
|
|
690
729
|
headers: entry.headers || [],
|
|
691
730
|
tags: entry.tags || [],
|
|
692
|
-
// engagement: views → views, adoptions+applications → clicks, authority → rating
|
|
693
731
|
views: (stats.views ?? 0) + (stats.searchHits ?? 0),
|
|
694
732
|
clicks: (stats.adoptions ?? 0) + (stats.applications ?? 0) + (stats.guardHits ?? 0),
|
|
695
733
|
rating: stats.authority ?? 0,
|
|
@@ -708,20 +746,22 @@ export class KnowledgeService {
|
|
|
708
746
|
}
|
|
709
747
|
try {
|
|
710
748
|
const candidates = [];
|
|
711
|
-
//
|
|
712
|
-
const
|
|
713
|
-
|
|
749
|
+
// 与可消费 Recipe(active/staging/evolving)建立关联
|
|
750
|
+
const consumableFilter = {
|
|
751
|
+
lifecycle: [Lifecycle.ACTIVE, Lifecycle.STAGING, Lifecycle.EVOLVING],
|
|
752
|
+
};
|
|
753
|
+
// 按 moduleName 查同模块可消费条目
|
|
714
754
|
if (entry.moduleName) {
|
|
715
|
-
const sameModule = await this.repository.findWithPagination({ ...
|
|
755
|
+
const sameModule = await this.repository.findWithPagination({ ...consumableFilter, moduleName: entry.moduleName }, { page: 1, pageSize: 20 });
|
|
716
756
|
for (const r of sameModule.data) {
|
|
717
757
|
if (r.id !== id) {
|
|
718
758
|
candidates.push({ target: r.id, relation: 'related', weight: 0.8 });
|
|
719
759
|
}
|
|
720
760
|
}
|
|
721
761
|
}
|
|
722
|
-
// 按 category
|
|
762
|
+
// 按 category 查同类可消费条目(弱关联)
|
|
723
763
|
if (entry.category && candidates.length < 10) {
|
|
724
|
-
const sameCat = await this.repository.findWithPagination({ ...
|
|
764
|
+
const sameCat = await this.repository.findWithPagination({ ...consumableFilter, category: entry.category }, { page: 1, pageSize: 10 });
|
|
725
765
|
for (const r of sameCat.data) {
|
|
726
766
|
if (r.id !== id && !candidates.some((c) => c.target === r.id)) {
|
|
727
767
|
candidates.push({ target: r.id, relation: 'related', weight: 0.4 });
|
|
@@ -770,9 +810,9 @@ export class KnowledgeService {
|
|
|
770
810
|
return;
|
|
771
811
|
}
|
|
772
812
|
try {
|
|
773
|
-
|
|
774
|
-
.
|
|
775
|
-
|
|
813
|
+
if (this._edgeRepo) {
|
|
814
|
+
this._edgeRepo.deleteOutgoing(id, 'knowledge');
|
|
815
|
+
}
|
|
776
816
|
if (!relations || typeof relations !== 'object') {
|
|
777
817
|
return;
|
|
778
818
|
}
|
|
@@ -804,12 +844,11 @@ export class KnowledgeService {
|
|
|
804
844
|
}
|
|
805
845
|
/** 删除所有关联边 */
|
|
806
846
|
_removeAllEdges(id) {
|
|
807
|
-
|
|
808
|
-
if (!gs) {
|
|
847
|
+
if (!this._edgeRepo) {
|
|
809
848
|
return;
|
|
810
849
|
}
|
|
811
850
|
try {
|
|
812
|
-
|
|
851
|
+
this._edgeRepo.deleteByEntryId(id);
|
|
813
852
|
}
|
|
814
853
|
catch (err) {
|
|
815
854
|
this.logger.warn('Failed to remove edges', {
|
|
@@ -820,12 +859,11 @@ export class KnowledgeService {
|
|
|
820
859
|
}
|
|
821
860
|
/** 删除关联的 evolution_proposals(target_recipe_id 无 CASCADE) */
|
|
822
861
|
_removeRelatedProposals(id) {
|
|
823
|
-
|
|
824
|
-
if (!gs) {
|
|
862
|
+
if (!this._proposalRepo) {
|
|
825
863
|
return;
|
|
826
864
|
}
|
|
827
865
|
try {
|
|
828
|
-
|
|
866
|
+
this._proposalRepo.deleteByTargetRecipeId(id);
|
|
829
867
|
}
|
|
830
868
|
catch (err) {
|
|
831
869
|
this.logger.warn('Failed to remove related proposals', {
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
* 5. Quality Scoring — 质量评分
|
|
12
12
|
* 6. Supersede Proposal — 创建替代提案
|
|
13
13
|
* 7. Audit — 统一审计
|
|
14
|
-
*
|
|
15
|
-
* @see docs/copilot/recipe-lifecycle-management.md §6
|
|
16
14
|
*/
|
|
17
15
|
/** Lightweight log interface — avoids importing static-only Logger class. */
|
|
18
16
|
interface GatewayLogger {
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
* 5. Quality Scoring — 质量评分
|
|
12
12
|
* 6. Supersede Proposal — 创建替代提案
|
|
13
13
|
* 7. Audit — 统一审计
|
|
14
|
-
*
|
|
15
|
-
* @see docs/copilot/recipe-lifecycle-management.md §6
|
|
16
14
|
*/
|
|
17
15
|
import { UnifiedValidator } from '#domain/knowledge/UnifiedValidator.js';
|
|
18
16
|
/* ═══════════════════ Gateway ═══════════════════ */
|
|
@@ -10,15 +10,8 @@
|
|
|
10
10
|
* stale — 路径失效,无法自动修复
|
|
11
11
|
*/
|
|
12
12
|
import type { SignalBus } from '../../infrastructure/signal/SignalBus.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
all(...params: unknown[]): Record<string, unknown>[];
|
|
16
|
-
get(...params: unknown[]): Record<string, unknown> | undefined;
|
|
17
|
-
run(...params: unknown[]): {
|
|
18
|
-
changes: number;
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
}
|
|
13
|
+
import type KnowledgeRepositoryImpl from '../../repository/knowledge/KnowledgeRepository.impl.js';
|
|
14
|
+
import type { RecipeSourceRefRepositoryImpl } from '../../repository/sourceref/RecipeSourceRefRepository.js';
|
|
22
15
|
export interface ReconcileReport {
|
|
23
16
|
/** 新插入的 sourceRef 条目 */
|
|
24
17
|
inserted: number;
|
|
@@ -45,7 +38,7 @@ export interface ApplyReport {
|
|
|
45
38
|
}
|
|
46
39
|
export declare class SourceRefReconciler {
|
|
47
40
|
#private;
|
|
48
|
-
constructor(projectRoot: string,
|
|
41
|
+
constructor(projectRoot: string, sourceRefRepo: RecipeSourceRefRepositoryImpl, knowledgeRepo: KnowledgeRepositoryImpl, options?: {
|
|
49
42
|
ttlMs?: number;
|
|
50
43
|
signalBus?: SignalBus;
|
|
51
44
|
});
|
|
@@ -55,7 +48,7 @@ export declare class SourceRefReconciler {
|
|
|
55
48
|
*/
|
|
56
49
|
reconcile(opts?: {
|
|
57
50
|
force?: boolean;
|
|
58
|
-
}): ReconcileReport
|
|
51
|
+
}): Promise<ReconcileReport>;
|
|
59
52
|
/**
|
|
60
53
|
* 对 stale 条目尝试 git rename 修复。
|
|
61
54
|
* 使用 execFile() 安全执行 git log(防止命令注入)。
|
|
@@ -65,6 +58,5 @@ export declare class SourceRefReconciler {
|
|
|
65
58
|
* 将 renamed 条目的 new_path 写回 Recipe .md 文件的 _reasoning.sources。
|
|
66
59
|
* 完成后 status → active。
|
|
67
60
|
*/
|
|
68
|
-
applyRepairs(): ApplyReport
|
|
61
|
+
applyRepairs(): Promise<ApplyReport>;
|
|
69
62
|
}
|
|
70
|
-
export {};
|
|
@@ -20,13 +20,15 @@ const execFileAsync = promisify(execFile);
|
|
|
20
20
|
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
21
21
|
export class SourceRefReconciler {
|
|
22
22
|
#projectRoot;
|
|
23
|
-
#
|
|
23
|
+
#sourceRefRepo;
|
|
24
|
+
#knowledgeRepo;
|
|
24
25
|
#signalBus;
|
|
25
26
|
#logger = Logger.getInstance();
|
|
26
27
|
#ttlMs;
|
|
27
|
-
constructor(projectRoot,
|
|
28
|
+
constructor(projectRoot, sourceRefRepo, knowledgeRepo, options) {
|
|
28
29
|
this.#projectRoot = projectRoot;
|
|
29
|
-
this.#
|
|
30
|
+
this.#sourceRefRepo = sourceRefRepo;
|
|
31
|
+
this.#knowledgeRepo = knowledgeRepo;
|
|
30
32
|
this.#signalBus = options?.signalBus ?? null;
|
|
31
33
|
this.#ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
32
34
|
}
|
|
@@ -34,7 +36,7 @@ export class SourceRefReconciler {
|
|
|
34
36
|
* 从 knowledge_entries.reasoning 填充 recipe_source_refs 表。
|
|
35
37
|
* 对已有条目验证路径存在性,更新 status。
|
|
36
38
|
*/
|
|
37
|
-
reconcile(opts) {
|
|
39
|
+
async reconcile(opts) {
|
|
38
40
|
const force = opts?.force ?? false;
|
|
39
41
|
const report = {
|
|
40
42
|
inserted: 0,
|
|
@@ -43,12 +45,13 @@ export class SourceRefReconciler {
|
|
|
43
45
|
skipped: 0,
|
|
44
46
|
recipesProcessed: 0,
|
|
45
47
|
};
|
|
46
|
-
//
|
|
47
|
-
this.#
|
|
48
|
+
// 确保表可访问
|
|
49
|
+
if (!this.#sourceRefRepo.isAccessible()) {
|
|
50
|
+
this.#logger.warn('SourceRefReconciler: recipe_source_refs table not accessible, skipping');
|
|
51
|
+
return report;
|
|
52
|
+
}
|
|
48
53
|
// 获取所有有 reasoning 的知识条目
|
|
49
|
-
const rows = this.#
|
|
50
|
-
.prepare(`SELECT id, reasoning FROM knowledge_entries WHERE reasoning IS NOT NULL AND reasoning != '{}'`)
|
|
51
|
-
.all();
|
|
54
|
+
const rows = await this.#knowledgeRepo.findAllIdAndReasoning();
|
|
52
55
|
const now = Date.now();
|
|
53
56
|
for (const row of rows) {
|
|
54
57
|
let sources = [];
|
|
@@ -67,12 +70,10 @@ export class SourceRefReconciler {
|
|
|
67
70
|
report.recipesProcessed++;
|
|
68
71
|
for (const sourcePath of sources) {
|
|
69
72
|
// 检查是否已有记录
|
|
70
|
-
const existing = this.#
|
|
71
|
-
.prepare(`SELECT status, verified_at FROM recipe_source_refs WHERE recipe_id = ? AND source_path = ?`)
|
|
72
|
-
.get(row.id, sourcePath);
|
|
73
|
+
const existing = this.#sourceRefRepo.findOne(row.id, sourcePath);
|
|
73
74
|
if (existing && !force) {
|
|
74
75
|
// TTL 检查:跳过近期已验证的条目
|
|
75
|
-
if (now - existing.
|
|
76
|
+
if (now - existing.verifiedAt < this.#ttlMs) {
|
|
76
77
|
report.skipped++;
|
|
77
78
|
if (existing.status === 'active') {
|
|
78
79
|
report.active++;
|
|
@@ -89,24 +90,34 @@ export class SourceRefReconciler {
|
|
|
89
90
|
if (existing) {
|
|
90
91
|
// 更新已有记录
|
|
91
92
|
if (exists) {
|
|
92
|
-
this.#
|
|
93
|
-
.
|
|
94
|
-
|
|
93
|
+
this.#sourceRefRepo.upsert({
|
|
94
|
+
recipeId: row.id,
|
|
95
|
+
sourcePath,
|
|
96
|
+
status: 'active',
|
|
97
|
+
newPath: null,
|
|
98
|
+
verifiedAt: now,
|
|
99
|
+
});
|
|
95
100
|
report.active++;
|
|
96
101
|
}
|
|
97
102
|
else {
|
|
98
|
-
this.#
|
|
99
|
-
.
|
|
100
|
-
|
|
103
|
+
this.#sourceRefRepo.upsert({
|
|
104
|
+
recipeId: row.id,
|
|
105
|
+
sourcePath,
|
|
106
|
+
status: 'stale',
|
|
107
|
+
verifiedAt: now,
|
|
108
|
+
});
|
|
101
109
|
report.stale++;
|
|
102
110
|
}
|
|
103
111
|
}
|
|
104
112
|
else {
|
|
105
113
|
// 新增记录
|
|
106
114
|
const status = exists ? 'active' : 'stale';
|
|
107
|
-
this.#
|
|
108
|
-
.
|
|
109
|
-
|
|
115
|
+
this.#sourceRefRepo.upsert({
|
|
116
|
+
recipeId: row.id,
|
|
117
|
+
sourcePath,
|
|
118
|
+
status,
|
|
119
|
+
verifiedAt: now,
|
|
120
|
+
});
|
|
110
121
|
report.inserted++;
|
|
111
122
|
if (exists) {
|
|
112
123
|
report.active++;
|
|
@@ -139,21 +150,15 @@ export class SourceRefReconciler {
|
|
|
139
150
|
return;
|
|
140
151
|
}
|
|
141
152
|
try {
|
|
142
|
-
const staleRecipes = this.#
|
|
143
|
-
.prepare(`SELECT recipe_id, COUNT(*) AS stale_count,
|
|
144
|
-
(SELECT COUNT(*) FROM recipe_source_refs r2 WHERE r2.recipe_id = r.recipe_id) AS total_count
|
|
145
|
-
FROM recipe_source_refs r
|
|
146
|
-
WHERE status = 'stale'
|
|
147
|
-
GROUP BY recipe_id`)
|
|
148
|
-
.all();
|
|
153
|
+
const staleRecipes = this.#sourceRefRepo.getStaleCountsByRecipe();
|
|
149
154
|
for (const row of staleRecipes) {
|
|
150
|
-
const staleRatio = row.
|
|
155
|
+
const staleRatio = row.staleCount / row.totalCount;
|
|
151
156
|
this.#signalBus.send('quality', 'SourceRefReconciler', staleRatio, {
|
|
152
|
-
target: row.
|
|
157
|
+
target: row.recipeId,
|
|
153
158
|
metadata: {
|
|
154
159
|
reason: 'source_ref_stale',
|
|
155
|
-
staleCount: row.
|
|
156
|
-
totalRefs: row.
|
|
160
|
+
staleCount: row.staleCount,
|
|
161
|
+
totalRefs: row.totalCount,
|
|
157
162
|
},
|
|
158
163
|
});
|
|
159
164
|
}
|
|
@@ -169,9 +174,7 @@ export class SourceRefReconciler {
|
|
|
169
174
|
async repairRenames() {
|
|
170
175
|
const report = { renamed: 0, stillStale: 0 };
|
|
171
176
|
// 获取所有 stale 条目
|
|
172
|
-
const staleRows = this.#
|
|
173
|
-
.prepare(`SELECT recipe_id, source_path FROM recipe_source_refs WHERE status = 'stale'`)
|
|
174
|
-
.all();
|
|
177
|
+
const staleRows = this.#sourceRefRepo.findStale();
|
|
175
178
|
if (staleRows.length === 0) {
|
|
176
179
|
return report;
|
|
177
180
|
}
|
|
@@ -179,14 +182,18 @@ export class SourceRefReconciler {
|
|
|
179
182
|
const renameMap = await this.#getGitRenameMap();
|
|
180
183
|
const now = Date.now();
|
|
181
184
|
for (const row of staleRows) {
|
|
182
|
-
const newPath = renameMap.get(row.
|
|
185
|
+
const newPath = renameMap.get(row.sourcePath);
|
|
183
186
|
if (newPath) {
|
|
184
187
|
// 验证 newPath 存在
|
|
185
188
|
const absNewPath = path.resolve(this.#projectRoot, newPath);
|
|
186
189
|
if (fs.existsSync(absNewPath)) {
|
|
187
|
-
this.#
|
|
188
|
-
.
|
|
189
|
-
|
|
190
|
+
this.#sourceRefRepo.upsert({
|
|
191
|
+
recipeId: row.recipeId,
|
|
192
|
+
sourcePath: row.sourcePath,
|
|
193
|
+
status: 'renamed',
|
|
194
|
+
newPath,
|
|
195
|
+
verifiedAt: now,
|
|
196
|
+
});
|
|
190
197
|
report.renamed++;
|
|
191
198
|
continue;
|
|
192
199
|
}
|
|
@@ -215,29 +222,25 @@ export class SourceRefReconciler {
|
|
|
215
222
|
* 将 renamed 条目的 new_path 写回 Recipe .md 文件的 _reasoning.sources。
|
|
216
223
|
* 完成后 status → active。
|
|
217
224
|
*/
|
|
218
|
-
applyRepairs() {
|
|
225
|
+
async applyRepairs() {
|
|
219
226
|
const report = { applied: 0, failed: 0 };
|
|
220
|
-
const renamedRows = this.#
|
|
221
|
-
.prepare(`SELECT recipe_id, source_path, new_path FROM recipe_source_refs WHERE status = 'renamed' AND new_path IS NOT NULL`)
|
|
222
|
-
.all();
|
|
227
|
+
const renamedRows = this.#sourceRefRepo.findRenamed();
|
|
223
228
|
if (renamedRows.length === 0) {
|
|
224
229
|
return report;
|
|
225
230
|
}
|
|
226
|
-
// 按
|
|
231
|
+
// 按 recipeId 分组
|
|
227
232
|
const byRecipe = new Map();
|
|
228
233
|
for (const row of renamedRows) {
|
|
229
|
-
if (!byRecipe.has(row.
|
|
230
|
-
byRecipe.set(row.
|
|
234
|
+
if (!byRecipe.has(row.recipeId)) {
|
|
235
|
+
byRecipe.set(row.recipeId, []);
|
|
231
236
|
}
|
|
232
|
-
byRecipe.get(row.
|
|
237
|
+
byRecipe.get(row.recipeId)?.push({ sourcePath: row.sourcePath, newPath: row.newPath });
|
|
233
238
|
}
|
|
234
239
|
// 获取 recipe 的 sourceFile 以定位 .md 文件
|
|
235
240
|
const now = Date.now();
|
|
236
241
|
for (const [recipeId, renames] of byRecipe) {
|
|
237
242
|
try {
|
|
238
|
-
const entry = this.#
|
|
239
|
-
.prepare(`SELECT sourceFile, reasoning FROM knowledge_entries WHERE id = ?`)
|
|
240
|
-
.get(recipeId);
|
|
243
|
+
const entry = await this.#knowledgeRepo.findSourceFileAndReasoning(recipeId);
|
|
241
244
|
if (!entry?.sourceFile || !entry.reasoning) {
|
|
242
245
|
report.failed += renames.length;
|
|
243
246
|
continue;
|
|
@@ -260,9 +263,9 @@ export class SourceRefReconciler {
|
|
|
260
263
|
const sources = Array.isArray(reasoning.sources) ? [...reasoning.sources] : [];
|
|
261
264
|
let modified = false;
|
|
262
265
|
for (const rename of renames) {
|
|
263
|
-
const idx = sources.indexOf(rename.
|
|
266
|
+
const idx = sources.indexOf(rename.sourcePath);
|
|
264
267
|
if (idx >= 0) {
|
|
265
|
-
sources[idx] = rename.
|
|
268
|
+
sources[idx] = rename.newPath;
|
|
266
269
|
modified = true;
|
|
267
270
|
}
|
|
268
271
|
}
|
|
@@ -272,14 +275,10 @@ export class SourceRefReconciler {
|
|
|
272
275
|
// 查找 YAML frontmatter 中的 reasoning 并替换
|
|
273
276
|
const updatedReasoning = JSON.stringify(reasoning);
|
|
274
277
|
// 更新 DB reasoning 列
|
|
275
|
-
this.#
|
|
276
|
-
.prepare(`UPDATE knowledge_entries SET reasoning = ?, updatedAt = ? WHERE id = ?`)
|
|
277
|
-
.run(updatedReasoning, now, recipeId);
|
|
278
|
+
await this.#knowledgeRepo.updateReasoning(recipeId, updatedReasoning, now);
|
|
278
279
|
// 更新 recipe_source_refs 状态
|
|
279
280
|
for (const rename of renames) {
|
|
280
|
-
this.#
|
|
281
|
-
.prepare(`UPDATE recipe_source_refs SET status = 'active', source_path = ?, new_path = NULL, verified_at = ? WHERE recipe_id = ? AND source_path = ?`)
|
|
282
|
-
.run(rename.new_path, now, recipeId, rename.source_path);
|
|
281
|
+
this.#sourceRefRepo.replaceSourcePath(recipeId, rename.sourcePath, rename.newPath, now);
|
|
283
282
|
}
|
|
284
283
|
report.applied += renames.length;
|
|
285
284
|
}
|
|
@@ -301,25 +300,6 @@ export class SourceRefReconciler {
|
|
|
301
300
|
return report;
|
|
302
301
|
}
|
|
303
302
|
/* ═══ Private helpers ═══════════════════════════════ */
|
|
304
|
-
#ensureTable() {
|
|
305
|
-
try {
|
|
306
|
-
this.#db.prepare(`SELECT 1 FROM recipe_source_refs LIMIT 1`).get();
|
|
307
|
-
}
|
|
308
|
-
catch {
|
|
309
|
-
// 表不存在,创建之
|
|
310
|
-
this.#db.exec?.(`CREATE TABLE IF NOT EXISTS recipe_source_refs (
|
|
311
|
-
recipe_id TEXT NOT NULL,
|
|
312
|
-
source_path TEXT NOT NULL,
|
|
313
|
-
status TEXT NOT NULL DEFAULT 'active',
|
|
314
|
-
new_path TEXT,
|
|
315
|
-
verified_at INTEGER NOT NULL,
|
|
316
|
-
PRIMARY KEY (recipe_id, source_path),
|
|
317
|
-
FOREIGN KEY (recipe_id) REFERENCES knowledge_entries(id) ON DELETE CASCADE
|
|
318
|
-
);
|
|
319
|
-
CREATE INDEX IF NOT EXISTS idx_rsr_path ON recipe_source_refs(source_path);
|
|
320
|
-
CREATE INDEX IF NOT EXISTS idx_rsr_status ON recipe_source_refs(status);`);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
303
|
/**
|
|
324
304
|
* 通过 git log 获取 rename 映射(旧路径 → 新路径)
|
|
325
305
|
* 使用 execFile 防止命令注入
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module CouplingAnalyzer
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
9
|
+
import type { CodeEntityRepositoryImpl } from '../../repository/code/CodeEntityRepository.js';
|
|
10
|
+
import type { KnowledgeEdgeRepositoryImpl } from '../../repository/knowledge/KnowledgeEdgeRepository.js';
|
|
11
|
+
import type { CyclicDependency, Edge } from './PanoramaTypes.js';
|
|
10
12
|
export interface CouplingMetrics {
|
|
11
13
|
fanIn: number;
|
|
12
14
|
fanOut: number;
|
|
@@ -26,11 +28,11 @@ export interface CouplingResult {
|
|
|
26
28
|
}
|
|
27
29
|
export declare class CouplingAnalyzer {
|
|
28
30
|
#private;
|
|
29
|
-
constructor(
|
|
31
|
+
constructor(edgeRepo: KnowledgeEdgeRepositoryImpl, entityRepo: CodeEntityRepositoryImpl, projectRoot: string);
|
|
30
32
|
/**
|
|
31
33
|
* 分析模块间耦合关系
|
|
32
34
|
* @param moduleFiles - Map<moduleName, filePaths[]>
|
|
33
35
|
* @param externalModules - 外部模块名集合(无源码但参与依赖图)
|
|
34
36
|
*/
|
|
35
|
-
analyze(moduleFiles: Map<string, string[]>, externalModules?: Set<string>): CouplingResult
|
|
37
|
+
analyze(moduleFiles: Map<string, string[]>, externalModules?: Set<string>): Promise<CouplingResult>;
|
|
36
38
|
}
|