Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions packages/core/src/config/plugin/instruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export * as ConfigInstructionPlugin from "./instruction.js"
import { define } from "@opencode/plugin/effect/plugin"
import { FSUtil } from "@opencode/util/fs-util"
import { Global } from "@opencode/util/global"
import { dirname, join } from "path"
import { dirname, join, relative } from "path"
import { Effect, PubSub, Semaphore, Stream } from "effect"
import { Watcher } from "../../filesystem/watcher.js"
import { InstructionDiscovery } from "../../instruction-discovery.js"
Expand Down Expand Up @@ -34,6 +34,8 @@ export const Plugin = define({
const home = yield* fs.resolve(global.home)
const project = discovery.project && FSUtil.contains(root, start)
const stop = FSUtil.contains(home, start) ? home : root
const ancestors = project ? ancestorDirectories(start, stop) : []
const boundary = ancestors.at(-1) ?? stop
const globalFile = yield* fs.resolve(join(global.config, "AGENTS.md"))
const loaded: { current: Loaded } = { current: { type: "available", files: [] } }

Expand All @@ -43,7 +45,7 @@ export const Plugin = define({
const candidates = [
...(discovery.global ? [globalFile] : []),
...(project
? ancestorDirectories(start, stop)
? ancestors
.map((directory) => join(directory, "AGENTS.md"))
.filter((file) => discovery.global || file !== globalFile)
: []),
Expand All @@ -67,7 +69,10 @@ export const Plugin = define({

const projectSource = Effect.fn("ConfigInstructionPlugin.projectSource")(function* () {
if (!project) return []
const walked = yield* Effect.forEach(yield* fs.up({ targets: ["AGENTS.md"], start, stop }), fs.resolve)
const walked = yield* Effect.forEach(
yield* fs.up({ targets: ["AGENTS.md"], start, stop: boundary }),
fs.resolve,
)
const discovered = new Set(walked.filter((file) => discovery.global || file !== globalFile))
const files = yield* Effect.forEach(discovered, read, { concurrency: "unbounded" })
if (files.some((file) => file === undefined)) return Instructions.unavailable
Expand Down Expand Up @@ -131,6 +136,9 @@ export const Plugin = define({
})

function ancestorDirectories(start: string, stop: string): string[] {
if (start === stop) return [start]
return [start, ...ancestorDirectories(dirname(start), stop)]
const result = [start]
if (relative(start, stop) === "") return result
const parent = dirname(start)
if (parent === start) throw new Error(`Instruction boundary ${stop} is not an ancestor of ${start}`)
return [...result, ...ancestorDirectories(parent, stop)]
}
Loading