Files
oh-my-opencode/packages/agents-md-core/src/injector.ts
T
YeonGyu-Kim 7c66aae0b8 refactor(rules-engine): centralize rule constants and AGENTS.md walk-up
Promote the project-rule constants (PROJECT_MARKERS, PROJECT_RULE_SUBDIRS, PROJECT_RULE_FILES, OPENCODE_USER_RULE_DIRS, USER_RULE_DIR, GITHUB_INSTRUCTIONS_PATTERN, RULE_EXTENSIONS, AGENTS_FILENAME, etc.) and the findAgentsMdUp walk-up helper out of the agents-md-core and rules-injector adapters and into @oh-my-opencode/rules-engine, the single owner of rule discovery.

- packages/agents-md-core/ drops the findAgentsMdUp/AgentsMdDiscoveryInput wrappers (now sourced directly from rules-engine) and its constants module re-exports AGENTS_FILENAME from rules-engine instead of duplicating it.
- src/hooks/directory-agents-injector/finder.ts pulls findAgentsMdUp from rules-engine directly while still re-exporting resolveFilePath from agents-md-core.
- src/hooks/rules-injector/constants.ts becomes a pure re-export shim over the rules-engine constants.

Add packages/agents-md-core/src/injector.test.ts to lock the root-skipping AGENTS.md injection order so future changes to findAgentsMdUp cannot silently regress the [Directory Context: ...] block format the injector emits.

Tests: bun test packages/agents-md-core packages/rules-engine src/hooks/directory-agents-injector src/hooks/rules-injector
2026-05-21 16:19:38 +09:00

73 lines
2.0 KiB
TypeScript

import {
findAgentsMdUp,
type AgentsMdCache,
type FindAgentsMdUpInput,
} from "@oh-my-opencode/rules-engine";
import { promises as fsPromises } from "node:fs";
import { dirname } from "node:path";
import { resolveFilePath } from "./finder";
import { formatAgentsMdContextBlock } from "./formatter";
import { getSessionCache } from "./injection-cache";
import type {
AgentsMdContextOutput,
AgentsMdInjectedPathsStorage,
AgentsMdTruncator,
} from "./types";
export async function processFilePathForAgentsInjection(input: {
readonly rootDirectory: string;
readonly truncator: AgentsMdTruncator;
readonly sessionCaches: Map<string, Set<string>>;
readonly storage: AgentsMdInjectedPathsStorage;
readonly agentsMdCache?: AgentsMdCache;
readonly filePath: string;
readonly sessionID: string;
readonly output: AgentsMdContextOutput;
}): Promise<void> {
if (typeof input.output.output !== "string") return;
const resolved = resolveFilePath(input.rootDirectory, input.filePath);
if (!resolved) return;
const dir = dirname(resolved);
const cache = getSessionCache({
sessionCaches: input.sessionCaches,
sessionID: input.sessionID,
storage: input.storage,
});
const agentsMdDiscoveryInput: FindAgentsMdUpInput = {
startDir: dir,
rootDir: input.rootDirectory,
cache: input.agentsMdCache,
};
const agentsPaths = await findAgentsMdUp(agentsMdDiscoveryInput);
let dirty = false;
for (const agentsPath of agentsPaths) {
const agentsDir = dirname(agentsPath);
if (cache.has(agentsDir)) continue;
const content = await fsPromises.readFile(agentsPath, "utf-8").catch(() => null);
if (content === null) continue;
cache.add(agentsDir);
const { result, truncated } = await input.truncator.truncate(
input.sessionID,
content,
);
input.output.output += formatAgentsMdContextBlock({
agentsPath,
content: result,
truncated,
});
dirty = true;
}
if (dirty) {
input.storage.saveInjectedPaths(input.sessionID, cache);
}
}