- VERSION file as authoritative version source - export.mjs reads VERSION with package.json fallback - bw-ota.ps1 DryRun mode for safe testing - auto-setup.ps1 bumped to v3.2.0 (Phase 8 OTA)
96 lines
2.9 KiB
JavaScript
96 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* patch-evo-log-dedup.js
|
|
* P2 去噪: evolution-log.jsonl 去重 + seq 重编号
|
|
* 规则:
|
|
* - consistency-sentinel 同日同内容只保留首条
|
|
* - sig-drift(auto) 有 fix_count>0 的保留
|
|
* - 所有条目按时间排序后重编号 seq
|
|
* Idempotent: sentinel 防重复
|
|
*/
|
|
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const CLAUDE_ROOT = path.join(process.env.USERPROFILE || process.env.HOME, '.claude');
|
|
const EVO_LOG = path.join(CLAUDE_ROOT, 'evolution-log.jsonl');
|
|
const STATE_DIR = path.join(CLAUDE_ROOT, 'session-state');
|
|
const SENTINEL = path.join(STATE_DIR, 'patch-evo-log-dedup.done');
|
|
|
|
if (fs.existsSync(SENTINEL)) {
|
|
console.log('[SKIP] patch-evo-log-dedup already applied');
|
|
process.exit(0);
|
|
}
|
|
|
|
if (!fs.existsSync(EVO_LOG)) {
|
|
console.error('[FAIL] evolution-log.jsonl not found');
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
const bak = EVO_LOG + '.bak-dedup-' + Date.now();
|
|
fs.copyFileSync(EVO_LOG, bak);
|
|
console.log('[OK] Backup: ' + path.basename(bak));
|
|
|
|
const raw = fs.readFileSync(EVO_LOG, 'utf8').trim();
|
|
const lines = raw.split('\n').map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
|
|
|
|
const before = lines.length;
|
|
const kept = [];
|
|
const sentinelSeen = new Map();
|
|
|
|
for (const entry of lines) {
|
|
if (entry.scope === 'consistency-sentinel' && entry.trigger === 'stop-dispatcher') {
|
|
const key = entry.ts + '::' + entry.summary;
|
|
if (sentinelSeen.has(key)) continue;
|
|
|
|
const dayKey = entry.ts;
|
|
const dayEntries = lines.filter(e =>
|
|
e.scope === 'consistency-sentinel' && e.trigger === 'stop-dispatcher' && e.ts === dayKey
|
|
);
|
|
const hasSameDay = kept.some(e =>
|
|
e.scope === 'consistency-sentinel' && e.trigger === 'stop-dispatcher' && e.ts === dayKey
|
|
);
|
|
|
|
if (hasSameDay && (!entry.fix_count || entry.fix_count === 0)) {
|
|
sentinelSeen.set(key, true);
|
|
continue;
|
|
}
|
|
|
|
sentinelSeen.set(key, true);
|
|
}
|
|
|
|
kept.push(entry);
|
|
}
|
|
|
|
let seq = 1;
|
|
for (const entry of kept) {
|
|
entry.seq = seq++;
|
|
}
|
|
|
|
const output = kept.map(e => JSON.stringify(e)).join('\n') + '\n';
|
|
const tmp = EVO_LOG + '.tmp.' + process.pid;
|
|
fs.writeFileSync(tmp, output, 'utf8');
|
|
fs.renameSync(tmp, EVO_LOG);
|
|
|
|
const after = kept.length;
|
|
const removed = before - after;
|
|
console.log('[OK] evolution-log: ' + before + ' → ' + after + ' entries (removed ' + removed + ' duplicates)');
|
|
console.log('[OK] seq renumbered 1..' + after);
|
|
|
|
if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
fs.writeFileSync(SENTINEL, JSON.stringify({
|
|
applied: new Date().toISOString(),
|
|
before: before,
|
|
after: after,
|
|
removed: removed,
|
|
backup: path.basename(bak)
|
|
}, null, 2), 'utf8');
|
|
console.log('[DONE] patch-evo-log-dedup applied');
|
|
|
|
} catch (err) {
|
|
console.error('[FAIL] ' + err.message);
|
|
process.exit(1);
|
|
}
|