bookworm-smart-assistant/hooks/lib/rule-loader.js

75 lines
2.3 KiB
JavaScript
Raw Permalink Normal View History

/**
* 共享规则加载模块 (M15)
*
* 替代 block-dangerous-commands.js block-sensitive-files.js
* 重复的 loadCompiledCache + compilePatterns + loadRules 三件套
*/
const fs = require('fs');
const path = require('path');
const CLAUDE_ROOT = require('./root.js');
const RULES_DIR = path.join(CLAUDE_ROOT, 'hooks', 'rules');
const COMPILED_CACHE = path.join(RULES_DIR, 'rules-compiled.json');
let _compiledCache = null;
/**
* 加载编译缓存 mtime 新鲜度检查
* @returns {object|null}
*/
function loadCompiledCache() {
try {
if (!fs.existsSync(COMPILED_CACHE)) return null;
const raw = JSON.parse(fs.readFileSync(COMPILED_CACHE, 'utf8'));
if (!raw.sources) return raw;
// mtime 新鲜度检查
for (const [filePath, savedMtime] of Object.entries(raw.sources)) {
if (!fs.existsSync(filePath)) return null;
const stat = fs.statSync(filePath);
if (stat.mtimeMs > savedMtime) return null;
}
_compiledCache = raw;
return raw;
} catch { return null; }
}
/**
* 编译正则模式数组
* @param {Array} patterns - [{regex, flags, reason}]
* @returns {Array} [{pattern: RegExp, reason: string}]
*/
function compilePatterns(patterns) {
return (patterns || []).map(p => ({
pattern: new RegExp(p.regex, (p.flags || '').replace(/g/g, '')),
reason: p.reason,
}));
}
/**
* 加载规则文件优先编译缓存回退到源文件最后使用硬编码后备
* @param {string} filename - 规则文件名 ( 'deny-patterns.json')
* @param {object} [fallbackRules] - 硬编码后备规则 {key: [patterns]}
* @returns {Array} 编译后的规则数组
*/
function loadRules(filename, fallbackRules) {
const key = filename.replace('.json', '');
const cache = loadCompiledCache();
if (cache && cache.rules && cache.rules[key]) {
return compilePatterns(cache.rules[key]);
}
try {
const filePath = path.join(RULES_DIR, filename);
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
return compilePatterns(data.patterns);
} catch {
// 规则文件丢失时使用硬编码后备
if (fallbackRules && fallbackRules[key]) {
return compilePatterns(fallbackRules[key]);
}
return [];
}
}
module.exports = { loadCompiledCache, compilePatterns, loadRules, RULES_DIR };