diff --git a/src/hooks/directory-agents-injector/finder.ts b/src/hooks/directory-agents-injector/finder.ts index 8ac8a1463..e04cfab74 100644 --- a/src/hooks/directory-agents-injector/finder.ts +++ b/src/hooks/directory-agents-injector/finder.ts @@ -1,4 +1,4 @@ -import { existsSync } from "node:fs"; +import { constants, promises as fsPromises } from "node:fs"; import { dirname, isAbsolute, join, resolve } from "node:path"; import { AGENTS_FILENAME } from "./constants"; @@ -9,10 +9,10 @@ export function resolveFilePath(rootDirectory: string, path: string): string | n return resolve(rootDirectory, path); } -export function findAgentsMdUp(input: { +export async function findAgentsMdUp(input: { startDir: string; rootDir: string; -}): string[] { +}): Promise { const found: string[] = []; let current = input.startDir; @@ -22,7 +22,11 @@ export function findAgentsMdUp(input: { const isRootDir = current === input.rootDir; if (!isRootDir) { const agentsPath = join(current, AGENTS_FILENAME); - if (existsSync(agentsPath)) { + const exists = await fsPromises + .access(agentsPath, constants.F_OK) + .then(() => true) + .catch(() => false); + if (exists) { found.push(agentsPath); } } diff --git a/src/hooks/directory-agents-injector/injector.test.ts b/src/hooks/directory-agents-injector/injector.test.ts index 8f5701645..822381a69 100644 --- a/src/hooks/directory-agents-injector/injector.test.ts +++ b/src/hooks/directory-agents-injector/injector.test.ts @@ -84,6 +84,23 @@ describe("processFilePathForAgentsInjection", () => { expect(output.output).toContain(srcAgentsContent) }) + it("finds AGENTS.md files while walking up directories", async () => { + // given + const { findAgentsMdUp } = await import("./finder") + + // when + const agentsPaths = await findAgentsMdUp({ + startDir: componentsDirectory, + rootDir: testRoot, + }) + + // then + expect(agentsPaths).toEqual([ + join(srcDirectory, "AGENTS.md"), + join(componentsDirectory, "AGENTS.md"), + ]) + }) + it("skips root-level AGENTS.md", async () => { // given rmSync(join(srcDirectory, "AGENTS.md"), { force: true }) diff --git a/src/hooks/directory-agents-injector/injector.ts b/src/hooks/directory-agents-injector/injector.ts index 28d0be943..3ff40784d 100644 --- a/src/hooks/directory-agents-injector/injector.ts +++ b/src/hooks/directory-agents-injector/injector.ts @@ -1,5 +1,5 @@ import type { PluginInput } from "@opencode-ai/plugin"; -import { readFileSync } from "node:fs"; +import { promises as fsPromises } from "node:fs"; import { dirname } from "node:path"; import type { createDynamicTruncator } from "../../shared/dynamic-truncator"; @@ -31,7 +31,7 @@ export async function processFilePathForAgentsInjection(input: { const dir = dirname(resolved); const cache = getSessionCache(input.sessionCaches, input.sessionID); - const agentsPaths = findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory }); + const agentsPaths = await findAgentsMdUp({ startDir: dir, rootDir: input.ctx.directory }); let dirty = false; for (const agentsPath of agentsPaths) { @@ -39,7 +39,8 @@ export async function processFilePathForAgentsInjection(input: { if (cache.has(agentsDir)) continue; try { - const content = readFileSync(agentsPath, "utf-8"); + const content = await fsPromises.readFile(agentsPath, "utf-8"); + cache.add(agentsDir); const { result, truncated } = await input.truncator.truncate( input.sessionID, content, @@ -48,7 +49,6 @@ export async function processFilePathForAgentsInjection(input: { ? `\n\n[Note: Content was truncated to save context window space. For full context, please read the file directly: ${agentsPath}]` : ""; input.output.output += `\n\n[Directory Context: ${agentsPath}]\n${result}${truncationNotice}`; - cache.add(agentsDir); dirty = true; } catch {} }