feat(config): add Zod schema validation and JSON Schema generation

- Add Zod schema for oh-my-opencode.json configuration validation
- Generate JSON Schema at build time for IDE autocompletion
- Add safeParse validation with error reporting on config load
- Export OhMyOpenCodeConfigSchema for programmatic usage
- Add build:schema script and ./schema.json export
- Update README with $schema usage documentation
This commit is contained in:
YeonGyu-Kim
2025-12-05 02:53:44 +09:00
parent 8e5064c547
commit b5274fcb63
3 changed files with 100 additions and 0 deletions

28
script/build-schema.ts Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bun
import * as z from "zod"
import { OhMyOpenCodeConfigSchema } from "../src/config/schema"
const SCHEMA_OUTPUT_PATH = "dist/oh-my-opencode.schema.json"
async function main() {
console.log("Generating JSON Schema...")
const jsonSchema = z.toJSONSchema(OhMyOpenCodeConfigSchema, {
io: "input",
target: "draft-7",
})
const finalSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
$id: "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/dist/oh-my-opencode.schema.json",
title: "Oh My OpenCode Configuration",
description: "Configuration schema for oh-my-opencode plugin",
...jsonSchema,
}
await Bun.write(SCHEMA_OUTPUT_PATH, JSON.stringify(finalSchema, null, 2))
console.log(`✓ JSON Schema generated: ${SCHEMA_OUTPUT_PATH}`)
}
main()

15
src/config/index.ts Normal file
View File

@@ -0,0 +1,15 @@
export {
OhMyOpenCodeConfigSchema,
AgentOverrideConfigSchema,
AgentOverridesSchema,
McpNameSchema,
AgentNameSchema,
} from "./schema"
export type {
OhMyOpenCodeConfig,
AgentOverrideConfig,
AgentOverrides,
McpName,
AgentName,
} from "./schema"

57
src/config/schema.ts Normal file
View File

@@ -0,0 +1,57 @@
import { z } from "zod"
const PermissionValue = z.enum(["ask", "allow", "deny"])
const BashPermission = z.union([
PermissionValue,
z.record(z.string(), PermissionValue),
])
const AgentPermissionSchema = z.object({
edit: PermissionValue.optional(),
bash: BashPermission.optional(),
webfetch: PermissionValue.optional(),
doom_loop: PermissionValue.optional(),
external_directory: PermissionValue.optional(),
})
export const AgentNameSchema = z.enum([
"oracle",
"librarian",
"explore",
"frontend-ui-ux-engineer",
"document-writer",
])
export const McpNameSchema = z.enum(["websearch_exa", "context7"])
export const AgentOverrideConfigSchema = z.object({
model: z.string().optional(),
temperature: z.number().min(0).max(2).optional(),
top_p: z.number().min(0).max(1).optional(),
prompt: z.string().optional(),
tools: z.record(z.string(), z.boolean()).optional(),
disable: z.boolean().optional(),
description: z.string().optional(),
mode: z.enum(["subagent", "primary", "all"]).optional(),
color: z
.string()
.regex(/^#[0-9A-Fa-f]{6}$/)
.optional(),
permission: AgentPermissionSchema.optional(),
})
export const AgentOverridesSchema = z.record(AgentNameSchema, AgentOverrideConfigSchema)
export const OhMyOpenCodeConfigSchema = z.object({
$schema: z.string().optional(),
disabled_mcps: z.array(McpNameSchema).optional(),
disabled_agents: z.array(AgentNameSchema).optional(),
agents: AgentOverridesSchema.optional(),
})
export type OhMyOpenCodeConfig = z.infer<typeof OhMyOpenCodeConfigSchema>
export type AgentOverrideConfig = z.infer<typeof AgentOverrideConfigSchema>
export type AgentOverrides = z.infer<typeof AgentOverridesSchema>
export type McpName = z.infer<typeof McpNameSchema>
export type AgentName = z.infer<typeof AgentNameSchema>