fix(hooks): improve rules injector implementation

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-10 15:53:10 +09:00
parent bd910ad011
commit 5a762ba2ca
+53 -35
View File
@@ -43,33 +43,6 @@ interface ParsedRuleEntry {
const parsedRuleCache = new Map<string, ParsedRuleEntry>();
function getCachedParsedRule(
filePath: string,
realPath: string
): { metadata: RuleMetadata; body: string } {
try {
const stat = statSync(filePath);
const cached = parsedRuleCache.get(realPath);
if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
return { metadata: cached.metadata, body: cached.body };
}
const rawContent = readFileSync(filePath, "utf-8");
const { metadata, body } = parseRuleFrontmatter(rawContent);
parsedRuleCache.set(realPath, {
mtimeMs: stat.mtimeMs,
size: stat.size,
metadata,
body,
});
return { metadata, body };
} catch {
const rawContent = readFileSync(filePath, "utf-8");
return parseRuleFrontmatter(rawContent);
}
}
function resolveFilePath(
workspaceDirectory: string,
path: string
@@ -84,6 +57,14 @@ export function createRuleInjectionProcessor(deps: {
truncator: DynamicTruncator;
getSessionCache: (sessionID: string) => SessionInjectedRulesCache;
ruleFinderOptions?: FindRuleFilesOptions;
readFileSync?: typeof readFileSync;
statSync?: typeof statSync;
homedir?: typeof homedir;
shouldApplyRule?: typeof shouldApplyRule;
isDuplicateByRealPath?: typeof isDuplicateByRealPath;
createContentHash?: typeof createContentHash;
isDuplicateByContentHash?: typeof isDuplicateByContentHash;
saveInjectedRules?: typeof saveInjectedRules;
}): {
processFilePathForInjection: (
filePath: string,
@@ -91,7 +72,44 @@ export function createRuleInjectionProcessor(deps: {
output: ToolExecuteOutput
) => Promise<void>;
} {
const { workspaceDirectory, truncator, getSessionCache, ruleFinderOptions } = deps;
const {
workspaceDirectory,
truncator,
getSessionCache,
ruleFinderOptions,
readFileSync: readRuleFileSync = readFileSync,
statSync: statRuleSync = statSync,
homedir: getHomeDir = homedir,
shouldApplyRule: shouldApplyRuleImpl = shouldApplyRule,
isDuplicateByRealPath: isDuplicateByRealPathImpl = isDuplicateByRealPath,
createContentHash: createContentHashImpl = createContentHash,
isDuplicateByContentHash: isDuplicateByContentHashImpl = isDuplicateByContentHash,
saveInjectedRules: saveInjectedRulesImpl = saveInjectedRules,
} = deps;
function getParsedRule(filePath: string, realPath: string): { metadata: RuleMetadata; body: string } {
try {
const stat = statRuleSync(filePath);
const cached = parsedRuleCache.get(realPath);
if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
return { metadata: cached.metadata, body: cached.body };
}
const rawContent = readRuleFileSync(filePath, "utf-8");
const { metadata, body } = parseRuleFrontmatter(rawContent);
parsedRuleCache.set(realPath, {
mtimeMs: stat.mtimeMs,
size: stat.size,
metadata,
body,
});
return { metadata, body };
} catch {
const rawContent = readRuleFileSync(filePath, "utf-8");
return parseRuleFrontmatter(rawContent);
}
}
async function processFilePathForInjection(
filePath: string,
@@ -103,17 +121,17 @@ export function createRuleInjectionProcessor(deps: {
const projectRoot = findProjectRoot(resolved);
const cache = getSessionCache(sessionID);
const home = homedir();
const home = getHomeDir();
const ruleFileCandidates = findRuleFiles(projectRoot, home, resolved, ruleFinderOptions);
const toInject: RuleToInject[] = [];
let dirty = false;
for (const candidate of ruleFileCandidates) {
if (isDuplicateByRealPath(candidate.realPath, cache.realPaths)) continue;
if (isDuplicateByRealPathImpl(candidate.realPath, cache.realPaths)) continue;
try {
const { metadata, body } = getCachedParsedRule(
const { metadata, body } = getParsedRule(
candidate.path,
candidate.realPath
);
@@ -122,13 +140,13 @@ export function createRuleInjectionProcessor(deps: {
if (candidate.isSingleFile) {
matchReason = "copilot-instructions (always apply)";
} else {
const matchResult = shouldApplyRule(metadata, resolved, projectRoot);
const matchResult = shouldApplyRuleImpl(metadata, resolved, projectRoot);
if (!matchResult.applies) continue;
matchReason = matchResult.reason ?? "matched";
}
const contentHash = createContentHash(body);
if (isDuplicateByContentHash(contentHash, cache.contentHashes)) continue;
const contentHash = createContentHashImpl(body);
if (isDuplicateByContentHashImpl(contentHash, cache.contentHashes)) continue;
const relativePath = projectRoot
? relative(projectRoot, candidate.path)
@@ -163,7 +181,7 @@ export function createRuleInjectionProcessor(deps: {
}
if (dirty) {
saveInjectedRules(sessionID, cache);
saveInjectedRulesImpl(sessionID, cache);
}
}