@@ -24,7 +24,7 @@ import {
2424 QualityStrategyProposalGenerator ,
2525 ApprovalManager ,
2626} from "@devap/core" ;
27- import type { EvolutionConfig , AnalyzerConfig , QualityStrategyConfig , ProposalStatus } from "@devap/core" ;
27+ import type { EvolutionConfig , AnalyzerConfig , QualityStrategyConfig , DriftDetectionConfig , ProposalStatus } from "@devap/core" ;
2828
2929// ─── 預設配置 ───────────────────────────────────────────────
3030
@@ -48,20 +48,25 @@ const DEFAULT_QUALITY_STRATEGY_CONFIG: QualityStrategyConfig = {
4848 token_overhead_ratio : 1.5 ,
4949} ;
5050
51+ const DEFAULT_DRIFT_DETECTION_CONFIG : DriftDetectionConfig = {
52+ enabled : true ,
53+ } ;
54+
5155const DEFAULT_EVOLUTION_CONFIG : EvolutionConfig = {
5256 enabled : true ,
5357 analyzers : {
5458 "token-cost" : DEFAULT_TOKEN_COST_CONFIG ,
5559 "hook-efficiency" : DEFAULT_HOOK_EFFICIENCY_CONFIG ,
5660 "quality-strategy" : DEFAULT_QUALITY_STRATEGY_CONFIG ,
61+ "drift-detection" : DEFAULT_DRIFT_DETECTION_CONFIG ,
5762 } ,
5863 trigger : { mode : "manual" } ,
5964 approval : { required : true } ,
6065} ;
6166
6267// ─── Config 載入 ────────────────────────────────────────────
6368
64- async function loadEvolutionConfig ( cwd : string ) : Promise < EvolutionConfig > {
69+ export async function loadEvolutionConfig ( cwd : string ) : Promise < EvolutionConfig > {
6570 const configPath = join ( cwd , ".evolution" , "config.yaml" ) ;
6671 try {
6772 const raw = await readFile ( configPath , "utf-8" ) ;
@@ -82,6 +87,14 @@ async function loadEvolutionConfig(cwd: string): Promise<EvolutionConfig> {
8287 ...DEFAULT_QUALITY_STRATEGY_CONFIG ,
8388 ...parsed . analyzers ?. [ "quality-strategy" ] ,
8489 } ,
90+ "drift-detection" : {
91+ ...DEFAULT_DRIFT_DETECTION_CONFIG ,
92+ ...parsed . analyzers ?. [ "drift-detection" ] ,
93+ } ,
94+ } ,
95+ trigger : {
96+ ...DEFAULT_EVOLUTION_CONFIG . trigger ,
97+ ...parsed . trigger ,
8598 } ,
8699 } ;
87100 } catch {
@@ -132,7 +145,7 @@ export async function executeEvolutionAnalyze(opts: {
132145 // ── Token Cost Analysis ──────────────────────────────────
133146 const tokenConfig = config . analyzers [ "token-cost" ] ;
134147 if ( tokenConfig . enabled ) {
135- console . log ( "📊 [1/3 ] Token 成本分析器..." ) ;
148+ console . log ( "📊 [1/4 ] Token 成本分析器..." ) ;
136149 const tokenAnalyzer = new TokenCostAnalyzer ( executionHistoryBackend , tokenConfig ) ;
137150 const tokenResult = await tokenAnalyzer . analyze ( ) ;
138151
@@ -158,7 +171,7 @@ export async function executeEvolutionAnalyze(opts: {
158171 // ── Hook Efficiency Analysis ─────────────────────────────
159172 const hookConfig = config . analyzers [ "hook-efficiency" ] ;
160173 if ( hookConfig ?. enabled ) {
161- console . log ( "\n🪝 [2/3 ] Hook 效率分析器..." ) ;
174+ console . log ( "\n🪝 [2/4 ] Hook 效率分析器..." ) ;
162175 const hookAnalyzer = new HookEfficiencyAnalyzer ( cwd , hookConfig ) ;
163176 const hookResult = await hookAnalyzer . analyze ( ) ;
164177
@@ -189,7 +202,7 @@ export async function executeEvolutionAnalyze(opts: {
189202 // ── Quality Strategy Analysis ────────────────────────────
190203 const qualityConfig = config . analyzers [ "quality-strategy" ] ;
191204 if ( qualityConfig ?. enabled ) {
192- console . log ( "\n🎯 [3/3 ] 品質策略分析器..." ) ;
205+ console . log ( "\n🎯 [3/4 ] 品質策略分析器..." ) ;
193206 const qualityAnalyzer = new QualityStrategyAnalyzer ( executionHistoryBackend , qualityConfig ) ;
194207 const qualityResult = await qualityAnalyzer . analyze ( ) ;
195208
@@ -218,6 +231,33 @@ export async function executeEvolutionAnalyze(opts: {
218231 }
219232 }
220233
234+ // ── Drift Detection ──────────────────────────────────────
235+ const driftConfig = config . analyzers [ "drift-detection" ] ;
236+ if ( driftConfig ?. enabled ) {
237+ console . log ( "\n🔍 [4/4] 文件飄移偵測..." ) ;
238+ const driftDetector = new DriftDetector ( cwd ) ;
239+ const driftResult = await driftDetector . analyze ( ) ;
240+
241+ if ( driftResult . skipped ) {
242+ console . log ( ` ⏭ 跳過:${ driftResult . skip_reason } (找不到 .standards/ 目錄)` ) ;
243+ } else {
244+ console . log ( ` ✓ 掃描 ${ driftResult . files_scanned } 個檔案` ) ;
245+ console . log ( ` 📌 發現 ${ driftResult . items . length } 個飄移引用` ) ;
246+
247+ if ( driftResult . items . length > 0 ) {
248+ const broken = driftResult . items . filter ( ( i ) => i . drift_type === "broken_reference" ) ;
249+ const stale = driftResult . items . filter ( ( i ) => i . drift_type === "stale_standard" ) ;
250+ if ( broken . length > 0 ) console . log ( ` - 失效路徑引用:${ broken . length } 個` ) ;
251+ if ( stale . length > 0 ) console . log ( ` - 失效標準引用:${ stale . length } 個` ) ;
252+
253+ const reportPath = await driftDetector . writeReport ( driftResult , join ( cwd , ".evolution" ) ) ;
254+ if ( reportPath ) {
255+ console . log ( ` 📄 drift-report.md 已寫入 .evolution/proposals/` ) ;
256+ }
257+ }
258+ }
259+ }
260+
221261 console . log ( `\n─────────────────────────────────────────────` ) ;
222262 if ( totalProposals > 0 ) {
223263 console . log ( `✅ 分析完成,共產生 ${ totalProposals } 個提案` ) ;
0 commit comments