Skip to content
Closed
Show file tree
Hide file tree
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
13 changes: 7 additions & 6 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export namespace Config {
if (!md.data) continue

const name = (() => {
const patterns = ["/.opencode/command/", "/command/"]
const patterns = ["/.opencode/commands/", "/.opencode/command/", "/commands/", "/command/"]
const pattern = patterns.find((p) => item.includes(p))

if (pattern) {
Expand Down Expand Up @@ -261,12 +261,13 @@ export namespace Config {
if (!md.data) continue

// Extract relative path from agent folder for nested agents
const agentFolderPath = (() => {
const patterns = ["/.opencode/agents/", "/.opencode/agent/", "/agents/", "/agent/"]
const pattern = patterns.find((p) => item.includes(p))
if (pattern) return item.split(pattern)[1]
return path.basename(item, ".md") + ".md"
})()
let agentName = path.basename(item, ".md")
const agentFolderPath = item.includes("/.opencode/agent/")
? item.split("/.opencode/agent/")[1]
: item.includes("/agent/")
? item.split("/agent/")[1]
: agentName + ".md"

// If agent is in a subfolder, include folder path in name
if (agentFolderPath.includes("/")) {
Expand Down
63 changes: 63 additions & 0 deletions packages/opencode/test/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,69 @@ Test agent prompt`,
})
})

test("loads nested commands from plural commands/ directory with prefix", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const opencodeDir = path.join(dir, ".opencode")
await fs.mkdir(opencodeDir, { recursive: true })
const commandsDir = path.join(opencodeDir, "commands", "email")
await fs.mkdir(commandsDir, { recursive: true })

await Bun.write(
path.join(commandsDir, "digest.md"),
`---
description: Generate email digest
---
Generate a digest of recent emails`,
)
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const config = await Config.get()
// Should preserve the email/ prefix from nested directory
expect(config.command?.["email/digest"]).toEqual({
description: "Generate email digest",
template: "Generate a digest of recent emails",
})
},
})
})

test("loads nested agents from plural agents/ directory with prefix", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
const opencodeDir = path.join(dir, ".opencode")
await fs.mkdir(opencodeDir, { recursive: true })
const agentsDir = path.join(opencodeDir, "agents", "ml")
await fs.mkdir(agentsDir, { recursive: true })

await Bun.write(
path.join(agentsDir, "engineer.md"),
`---
model: test/model
---
ML Engineer agent prompt`,
)
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const config = await Config.get()
// Should preserve the ml/ prefix from nested directory
expect(config.agent?.["ml/engineer"]).toEqual(
expect.objectContaining({
name: "ml/engineer",
model: "test/model",
prompt: "ML Engineer agent prompt",
}),
)
},
})
})

test("updates config and writes to file", async () => {
await using tmp = await tmpdir()
await Instance.provide({
Expand Down