76 lines
2.5 KiB
JavaScript
76 lines
2.5 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
'use strict';
|
||
|
|
const fs = require('fs');
|
||
|
|
const path = require('path');
|
||
|
|
const { execSync } = require('child_process');
|
||
|
|
|
||
|
|
const TARGET = path.join(__dirname, '..', '..', 'hooks', 'route-interceptor-bundle.js');
|
||
|
|
const SENTINEL_TAG = 'ROUTE-ACC-3D-V1';
|
||
|
|
|
||
|
|
const HELPER = [
|
||
|
|
'',
|
||
|
|
' // /* ROUTE-ACC-3D-V1 */ near-3-day route accuracy',
|
||
|
|
" let routeAccuracy3d = 'N/A';",
|
||
|
|
' try {',
|
||
|
|
' const cutoff = Date.now() - 3 * 86400 * 1000;',
|
||
|
|
' const files = fs.readdirSync(DEBUG_DIR).filter(function(f){return /^route-\\d{4}-\\d{2}-\\d{2}\\.jsonl$/.test(f);});',
|
||
|
|
' let total = 0, hit = 0;',
|
||
|
|
' for (const f of files) {',
|
||
|
|
" const lines = fs.readFileSync(path.join(DEBUG_DIR, f), 'utf8').split('\\n');",
|
||
|
|
' for (const L of lines) {',
|
||
|
|
' if (!L) continue;',
|
||
|
|
' try {',
|
||
|
|
' const j = JSON.parse(L);',
|
||
|
|
' const ts = new Date(j.ts).getTime();',
|
||
|
|
' if (!Number.isFinite(ts) || ts < cutoff) continue;',
|
||
|
|
' total++;',
|
||
|
|
' if (j.topConfidence && j.topConfidence > 0) hit++;',
|
||
|
|
' } catch {}',
|
||
|
|
' }',
|
||
|
|
' }',
|
||
|
|
" if (total > 0) routeAccuracy3d = (hit / total * 100).toFixed(1) + '%';",
|
||
|
|
' } catch {}',
|
||
|
|
'',
|
||
|
|
' const now = new Date();',
|
||
|
|
].join('\n');
|
||
|
|
|
||
|
|
function main() {
|
||
|
|
const src = fs.readFileSync(TARGET, 'utf8');
|
||
|
|
if (src.includes(SENTINEL_TAG)) {
|
||
|
|
console.log('[banner-acc] already applied, skip');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const anchor = '\n const now = new Date();';
|
||
|
|
if (!src.includes(anchor)) {
|
||
|
|
console.error('[banner-acc] anchor missing');
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
let next = src.replace(anchor, HELPER);
|
||
|
|
|
||
|
|
const bannerOld = ' `active_skills: ${activeSkillCount}/${skillCount}`,';
|
||
|
|
const bannerNew = bannerOld + '\n `route_accuracy_3d: ${routeAccuracy3d}`,';
|
||
|
|
if (!next.includes(bannerOld)) {
|
||
|
|
console.error('[banner-acc] banner anchor missing');
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
next = next.replace(bannerOld, bannerNew);
|
||
|
|
|
||
|
|
const bak = TARGET + '.bak.banner-acc.' + Date.now();
|
||
|
|
fs.copyFileSync(TARGET, bak);
|
||
|
|
const tmp = TARGET + '.tmp.' + process.pid;
|
||
|
|
fs.writeFileSync(tmp, next, 'utf8');
|
||
|
|
fs.renameSync(tmp, TARGET);
|
||
|
|
|
||
|
|
try {
|
||
|
|
execSync('node --check "' + TARGET + '"', { stdio: 'pipe' });
|
||
|
|
console.log('[banner-acc] OK, bak:', path.basename(bak));
|
||
|
|
} catch (e) {
|
||
|
|
fs.copyFileSync(bak, TARGET);
|
||
|
|
console.error('[banner-acc] SYNTAX FAIL, rolled back:', String(e.stderr || e.message).split('\n').slice(0, 4).join(' | '));
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
main();
|