Files
oh-my-opencode/packages/agents-md-core/src/injector.test.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

83 lines
2.6 KiB
TypeScript

import { randomUUID } from "node:crypto";
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "bun:test";
import { processFilePathForAgentsInjection } from "./injector";
describe("processFilePathForAgentsInjection", () => {
const sessionCaches = new Map<string, Set<string>>();
const storageBackfill = new Map<string, Set<string>>();
const storage = {
loadInjectedPaths: (sessionID: string): Set<string> =>
storageBackfill.get(sessionID) ?? new Set<string>(),
saveInjectedPaths: (sessionID: string, paths: Set<string>): void => {
storageBackfill.set(sessionID, paths);
},
};
const truncator = {
truncate: async (_sessionID: string, content: string) => ({
result: content,
truncated: false,
}),
};
let rootDirectory = "";
afterEach(() => {
if (rootDirectory) {
rmSync(rootDirectory, { recursive: true, force: true });
}
rootDirectory = "";
sessionCaches.clear();
storageBackfill.clear();
});
it("injects AGENTS.md chain in root-skipping order with unchanged context format", async () => {
// given
rootDirectory = join(tmpdir(), `agents-md-core-injector-${randomUUID()}`);
const srcDirectory = join(rootDirectory, "src");
const nestedDirectory = join(srcDirectory, "components");
mkdirSync(nestedDirectory, { recursive: true });
const rootAgents = "# root";
const srcAgents = "# src";
const nestedAgents = "# nested";
writeFileSync(join(rootDirectory, "AGENTS.md"), rootAgents);
writeFileSync(join(srcDirectory, "AGENTS.md"), srcAgents);
writeFileSync(join(nestedDirectory, "AGENTS.md"), nestedAgents);
writeFileSync(join(nestedDirectory, "button.ts"), "export const button = true;\n");
const output = {
title: "read result",
output: "base output",
metadata: {},
};
const srcAgentsPath = join(srcDirectory, "AGENTS.md");
const nestedAgentsPath = join(nestedDirectory, "AGENTS.md");
const expectedOutput =
"base output" +
`\n\n[Directory Context: ${srcAgentsPath}]\n${srcAgents}` +
`\n\n[Directory Context: ${nestedAgentsPath}]\n${nestedAgents}`;
// when
await processFilePathForAgentsInjection({
rootDirectory,
truncator,
sessionCaches,
storage,
filePath: join(nestedDirectory, "button.ts"),
sessionID: "session-regression",
output,
});
// then
expect(output.output).toBe(expectedOutput);
expect(output.output).not.toContain(rootAgents);
});
});