Просмотр исходного кода

tweak: adjust instructions resolving logic

Aiden Cline 2 месяцев назад
Родитель
Сommit
f2e1dbda16

+ 15 - 17
packages/opencode/src/session/instruction.ts

@@ -16,17 +16,6 @@ const FILES = [
   "CONTEXT.md", // deprecated
 ]
 
-function globalFiles() {
-  const files = [path.join(Global.Path.config, "AGENTS.md")]
-  if (!Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT) {
-    files.push(path.join(os.homedir(), ".claude", "CLAUDE.md"))
-  }
-  if (Flag.OPENCODE_CONFIG_DIR) {
-    files.push(path.join(Flag.OPENCODE_CONFIG_DIR, "AGENTS.md"))
-  }
-  return files
-}
-
 async function resolveRelative(instruction: string): Promise<string[]> {
   if (!Flag.OPENCODE_DISABLE_PROJECT_CONFIG) {
     return Filesystem.globUp(instruction, Instance.directory, Instance.worktree).catch(() => [])
@@ -81,18 +70,27 @@ export namespace InstructionPrompt {
       }
     }
 
-    for (const file of globalFiles()) {
-      if (await Bun.file(file).exists()) {
-        paths.add(path.resolve(file))
-        break
-      }
+    const agentsmd: string[] = []
+    if (Flag.OPENCODE_CONFIG_DIR) agentsmd.push(path.join(Flag.OPENCODE_CONFIG_DIR, "AGENTS.md"))
+    agentsmd.push(path.join(Global.Path.config, "AGENTS.md"))
+
+    const found: string[] = []
+    for (const file of agentsmd) {
+      if (await Bun.file(file).exists()) found.push(path.resolve(file))
+    }
+
+    if (found.length === 0 && !Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT) {
+      const claude = path.join(Global.Path.home, ".claude", "CLAUDE.md")
+      if (await Bun.file(claude).exists()) found.push(path.resolve(claude))
     }
 
+    found.forEach((file) => paths.add(file))
+
     if (config.instructions) {
       for (let instruction of config.instructions) {
         if (instruction.startsWith("https://") || instruction.startsWith("http://")) continue
         if (instruction.startsWith("~/")) {
-          instruction = path.join(os.homedir(), instruction.slice(2))
+          instruction = path.join(Global.Path.home, instruction.slice(2))
         }
         const matches = path.isAbsolute(instruction)
           ? await Array.fromAsync(

+ 91 - 0
packages/opencode/test/session/instruction.test.ts

@@ -1,9 +1,19 @@
 import { describe, expect, test } from "bun:test"
+import fs from "fs/promises"
 import path from "path"
+import { Global } from "../../src/global"
 import { InstructionPrompt } from "../../src/session/instruction"
 import { Instance } from "../../src/project/instance"
 import { tmpdir } from "../fixture/fixture"
 
+const restore = (key: string, value: string | undefined) => {
+  if (value === undefined) {
+    delete process.env[key]
+    return
+  }
+  process.env[key] = value
+}
+
 describe("InstructionPrompt.resolve", () => {
   test("returns empty when AGENTS.md is at project root (already in systemPaths)", async () => {
     await using tmp = await tmpdir({
@@ -48,3 +58,84 @@ describe("InstructionPrompt.resolve", () => {
     })
   })
 })
+
+describe("InstructionPrompt.systemPaths", () => {
+  test("includes config and global AGENTS, skips CLAUDE when agents exist", async () => {
+    const homeValue = process.env["OPENCODE_TEST_HOME"]
+    const configValue = process.env["OPENCODE_CONFIG_DIR"]
+    const disableValue = process.env["OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"]
+
+    await using config = await tmpdir()
+    await using home = await tmpdir()
+    await using project = await tmpdir()
+
+    try {
+      process.env["OPENCODE_CONFIG_DIR"] = config.path
+      process.env["OPENCODE_TEST_HOME"] = home.path
+      delete process.env["OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"]
+
+      const configAgent = path.join(config.path, "AGENTS.md")
+      const globalAgent = path.join(Global.Path.config, "AGENTS.md")
+      const claudeAgent = path.join(Global.Path.home, ".claude", "CLAUDE.md")
+
+      await fs.mkdir(path.dirname(globalAgent), { recursive: true })
+      await fs.mkdir(path.dirname(claudeAgent), { recursive: true })
+
+      await Bun.write(configAgent, "# Config")
+      await Bun.write(globalAgent, "# Global")
+      await Bun.write(claudeAgent, "# Claude")
+
+      await Instance.provide({
+        directory: project.path,
+        fn: async () => {
+          const system = await InstructionPrompt.systemPaths()
+          expect(system.has(path.resolve(configAgent))).toBe(true)
+          expect(system.has(path.resolve(globalAgent))).toBe(true)
+          expect(system.has(path.resolve(claudeAgent))).toBe(false)
+        },
+      })
+    } finally {
+      await fs.rm(path.join(Global.Path.config, "AGENTS.md"), { force: true })
+      restore("OPENCODE_TEST_HOME", homeValue)
+      restore("OPENCODE_CONFIG_DIR", configValue)
+      restore("OPENCODE_DISABLE_CLAUDE_CODE_PROMPT", disableValue)
+    }
+  })
+
+  test("uses CLAUDE when no agents exist", async () => {
+    const homeValue = process.env["OPENCODE_TEST_HOME"]
+    const configValue = process.env["OPENCODE_CONFIG_DIR"]
+    const disableValue = process.env["OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"]
+
+    await using config = await tmpdir()
+    await using home = await tmpdir()
+    await using project = await tmpdir()
+
+    try {
+      process.env["OPENCODE_CONFIG_DIR"] = config.path
+      process.env["OPENCODE_TEST_HOME"] = home.path
+      delete process.env["OPENCODE_DISABLE_CLAUDE_CODE_PROMPT"]
+
+      const globalAgent = path.join(Global.Path.config, "AGENTS.md")
+      const claudeAgent = path.join(Global.Path.home, ".claude", "CLAUDE.md")
+
+      await fs.rm(globalAgent, { force: true })
+      await fs.mkdir(path.dirname(claudeAgent), { recursive: true })
+      await Bun.write(claudeAgent, "# Claude")
+
+      await Instance.provide({
+        directory: project.path,
+        fn: async () => {
+          const system = await InstructionPrompt.systemPaths()
+          expect(system.has(path.resolve(globalAgent))).toBe(false)
+          expect(system.has(path.resolve(claudeAgent))).toBe(true)
+        },
+      })
+    } finally {
+      await fs.rm(path.join(Global.Path.config, "AGENTS.md"), { force: true })
+      restore("OPENCODE_TEST_HOME", homeValue)
+      restore("OPENCODE_CONFIG_DIR", configValue)
+      restore("OPENCODE_DISABLE_CLAUDE_CODE_PROMPT", disableValue)
+    }
+  })
+})