summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-10-09 22:40:23 -0400
committerDax Raad <[email protected]>2025-10-09 22:40:23 -0400
commit9b52d33889482d52fc2ccb86a48cfdcade21157b (patch)
tree39074f77c14f30989e759540b4abc10ff55f2bc5
parent096710a8cc58b7f4c81e516c9edb3147f9a5fb3f (diff)
downloadopencode-9b52d33889482d52fc2ccb86a48cfdcade21157b.tar.gz
opencode-9b52d33889482d52fc2ccb86a48cfdcade21157b.zip
core: improve directory validation error messages to help users fix invalid directory names
-rw-r--r--packages/opencode/src/cli/error.ts2
-rw-r--r--packages/opencode/src/config/config.ts40
2 files changed, 25 insertions, 17 deletions
diff --git a/packages/opencode/src/cli/error.ts b/packages/opencode/src/cli/error.ts
index fa77ca773..8288de1eb 100644
--- a/packages/opencode/src/cli/error.ts
+++ b/packages/opencode/src/cli/error.ts
@@ -10,6 +10,8 @@ export function FormatError(input: unknown) {
`Config file at ${input.data.path} is not valid JSON(C)` + (input.data.message ? `: ${input.data.message}` : "")
)
}
+ if (Config.DirectoryError.isInstance(input))
+ return `Directory "${input.data.dir}" in ${input.data.path} is not valid. Did you mean "${input.data.suggestion}"?`
if (Config.InvalidError.isInstance(input))
return [
`Config file at ${input.data.path} is invalid` + (input.data.message ? `: ${input.data.message}` : ""),
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 234d14573..a05d159e3 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -62,7 +62,7 @@ export namespace Config {
]
for (const dir of directories) {
- await assertValid(dir).catch(() => {})
+ await assertValid(dir)
installDependencies(dir)
result.command = mergeDeep(result.command ?? {}, await loadCommand(dir))
result.agent = mergeDeep(result.agent, await loadAgent(dir))
@@ -120,23 +120,20 @@ export namespace Config {
}
})
+ const INVALID_DIRS = new Bun.Glob(`{${["agents", "commands", "plugins", "tools"].join(",")}}/`)
async function assertValid(dir: string) {
- const ALLOWED_DIRS = new Set(["agent", "command", "mode", "plugin", "tool", "themes"])
- const UNEXPECTED_DIR_GLOB = new Bun.Glob("*/")
- for await (const item of UNEXPECTED_DIR_GLOB.scan({
- absolute: true,
- followSymlinks: true,
- dot: true,
- cwd: dir,
- onlyFiles: false,
- })) {
- const dirname = path.basename(item)
- if (!ALLOWED_DIRS.has(dirname)) {
- throw new InvalidError({
- path: dir,
- message: `Unexpected directory "${dirname}" found in "${dir}". Only ${ALLOWED_DIRS.values().toArray().join(", ")} directories are allowed.`,
- })
- }
+ const invalid = await Array.fromAsync(
+ INVALID_DIRS.scan({
+ onlyFiles: false,
+ cwd: dir,
+ }),
+ )
+ for (const item of invalid) {
+ throw new DirectoryError({
+ path: dir,
+ dir: item,
+ suggestion: item.substring(0, item.length - 1),
+ })
}
}
@@ -714,6 +711,15 @@ export namespace Config {
}),
)
+ export const DirectoryError = NamedError.create(
+ "ConfigDirectoryError",
+ z.object({
+ path: z.string(),
+ dir: z.string(),
+ suggestion: z.string(),
+ }),
+ )
+
export const InvalidError = NamedError.create(
"ConfigInvalidError",
z.object({