diff options
| author | Kujtim Hoxha <[email protected]> | 2025-04-21 14:29:03 +0200 |
|---|---|---|
| committer | Kujtim Hoxha <[email protected]> | 2025-04-21 14:29:28 +0200 |
| commit | a8d5787e8ef561037f73b669128f46ae1b1e8553 (patch) | |
| tree | b606adbc85069d60cc518c74508a7ecbc87c051b /cmd | |
| parent | 9ae6af8856ca6a13d575ec6a8989a5f6ee4297b1 (diff) | |
| download | opencode-a8d5787e8ef561037f73b669128f46ae1b1e8553.tar.gz opencode-a8d5787e8ef561037f73b669128f46ae1b1e8553.zip | |
config validation
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/schema/README.md | 64 | ||||
| -rw-r--r-- | cmd/schema/main.go | 262 |
2 files changed, 326 insertions, 0 deletions
diff --git a/cmd/schema/README.md b/cmd/schema/README.md new file mode 100644 index 000000000..93ebe9f03 --- /dev/null +++ b/cmd/schema/README.md @@ -0,0 +1,64 @@ +# OpenCode Configuration Schema Generator + +This tool generates a JSON Schema for the OpenCode configuration file. The schema can be used to validate configuration files and provide autocompletion in editors that support JSON Schema. + +## Usage + +```bash +go run cmd/schema/main.go > opencode-schema.json +``` + +This will generate a JSON Schema file that can be used to validate configuration files. + +## Schema Features + +The generated schema includes: + +- All configuration options with descriptions +- Default values where applicable +- Validation for enum values (e.g., model IDs, provider types) +- Required fields +- Type checking + +## Using the Schema + +You can use the generated schema in several ways: + +1. **Editor Integration**: Many editors (VS Code, JetBrains IDEs, etc.) support JSON Schema for validation and autocompletion. You can configure your editor to use the generated schema for `.opencode.json` files. + +2. **Validation Tools**: You can use tools like [jsonschema](https://github.com/Julian/jsonschema) to validate your configuration files against the schema. + +3. **Documentation**: The schema serves as documentation for the configuration options. + +## Example Configuration + +Here's an example configuration that conforms to the schema: + +```json +{ + "data": { + "directory": ".opencode" + }, + "debug": false, + "providers": { + "anthropic": { + "apiKey": "your-api-key" + } + }, + "agents": { + "coder": { + "model": "claude-3.7-sonnet", + "maxTokens": 5000, + "reasoningEffort": "medium" + }, + "task": { + "model": "claude-3.7-sonnet", + "maxTokens": 5000 + }, + "title": { + "model": "claude-3.7-sonnet", + "maxTokens": 80 + } + } +} +```
\ No newline at end of file diff --git a/cmd/schema/main.go b/cmd/schema/main.go new file mode 100644 index 000000000..030c0907e --- /dev/null +++ b/cmd/schema/main.go @@ -0,0 +1,262 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/kujtimiihoxha/opencode/internal/config" + "github.com/kujtimiihoxha/opencode/internal/llm/models" +) + +// JSONSchemaType represents a JSON Schema type +type JSONSchemaType struct { + Type string `json:"type,omitempty"` + Description string `json:"description,omitempty"` + Properties map[string]any `json:"properties,omitempty"` + Required []string `json:"required,omitempty"` + AdditionalProperties any `json:"additionalProperties,omitempty"` + Enum []any `json:"enum,omitempty"` + Items map[string]any `json:"items,omitempty"` + OneOf []map[string]any `json:"oneOf,omitempty"` + AnyOf []map[string]any `json:"anyOf,omitempty"` + Default any `json:"default,omitempty"` +} + +func main() { + schema := generateSchema() + + // Pretty print the schema + encoder := json.NewEncoder(os.Stdout) + encoder.SetIndent("", " ") + if err := encoder.Encode(schema); err != nil { + fmt.Fprintf(os.Stderr, "Error encoding schema: %v\n", err) + os.Exit(1) + } +} + +func generateSchema() map[string]any { + schema := map[string]any{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "OpenCode Configuration", + "description": "Configuration schema for the OpenCode application", + "type": "object", + "properties": map[string]any{}, + } + + // Add Data configuration + schema["properties"].(map[string]any)["data"] = map[string]any{ + "type": "object", + "description": "Storage configuration", + "properties": map[string]any{ + "directory": map[string]any{ + "type": "string", + "description": "Directory where application data is stored", + "default": ".opencode", + }, + }, + "required": []string{"directory"}, + } + + // Add working directory + schema["properties"].(map[string]any)["wd"] = map[string]any{ + "type": "string", + "description": "Working directory for the application", + } + + // Add debug flags + schema["properties"].(map[string]any)["debug"] = map[string]any{ + "type": "boolean", + "description": "Enable debug mode", + "default": false, + } + + schema["properties"].(map[string]any)["debugLSP"] = map[string]any{ + "type": "boolean", + "description": "Enable LSP debug mode", + "default": false, + } + + // Add MCP servers + schema["properties"].(map[string]any)["mcpServers"] = map[string]any{ + "type": "object", + "description": "Model Control Protocol server configurations", + "additionalProperties": map[string]any{ + "type": "object", + "description": "MCP server configuration", + "properties": map[string]any{ + "command": map[string]any{ + "type": "string", + "description": "Command to execute for the MCP server", + }, + "env": map[string]any{ + "type": "array", + "description": "Environment variables for the MCP server", + "items": map[string]any{ + "type": "string", + }, + }, + "args": map[string]any{ + "type": "array", + "description": "Command arguments for the MCP server", + "items": map[string]any{ + "type": "string", + }, + }, + "type": map[string]any{ + "type": "string", + "description": "Type of MCP server", + "enum": []string{"stdio", "sse"}, + "default": "stdio", + }, + "url": map[string]any{ + "type": "string", + "description": "URL for SSE type MCP servers", + }, + "headers": map[string]any{ + "type": "object", + "description": "HTTP headers for SSE type MCP servers", + "additionalProperties": map[string]any{ + "type": "string", + }, + }, + }, + "required": []string{"command"}, + }, + } + + // Add providers + providerSchema := map[string]any{ + "type": "object", + "description": "LLM provider configurations", + "additionalProperties": map[string]any{ + "type": "object", + "description": "Provider configuration", + "properties": map[string]any{ + "apiKey": map[string]any{ + "type": "string", + "description": "API key for the provider", + }, + "disabled": map[string]any{ + "type": "boolean", + "description": "Whether the provider is disabled", + "default": false, + }, + }, + }, + } + + // Add known providers + knownProviders := []string{ + string(models.ProviderAnthropic), + string(models.ProviderOpenAI), + string(models.ProviderGemini), + string(models.ProviderGROQ), + string(models.ProviderBedrock), + } + + providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{ + "type": "string", + "description": "Provider type", + "enum": knownProviders, + } + + schema["properties"].(map[string]any)["providers"] = providerSchema + + // Add agents + agentSchema := map[string]any{ + "type": "object", + "description": "Agent configurations", + "additionalProperties": map[string]any{ + "type": "object", + "description": "Agent configuration", + "properties": map[string]any{ + "model": map[string]any{ + "type": "string", + "description": "Model ID for the agent", + }, + "maxTokens": map[string]any{ + "type": "integer", + "description": "Maximum tokens for the agent", + "minimum": 1, + }, + "reasoningEffort": map[string]any{ + "type": "string", + "description": "Reasoning effort for models that support it (OpenAI, Anthropic)", + "enum": []string{"low", "medium", "high"}, + }, + }, + "required": []string{"model"}, + }, + } + + // Add model enum + modelEnum := []string{} + for modelID := range models.SupportedModels { + modelEnum = append(modelEnum, string(modelID)) + } + agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum + + // Add specific agent properties + agentProperties := map[string]any{} + knownAgents := []string{ + string(config.AgentCoder), + string(config.AgentTask), + string(config.AgentTitle), + } + + for _, agentName := range knownAgents { + agentProperties[agentName] = map[string]any{ + "$ref": "#/definitions/agent", + } + } + + // Create a combined schema that allows both specific agents and additional ones + combinedAgentSchema := map[string]any{ + "type": "object", + "description": "Agent configurations", + "properties": agentProperties, + "additionalProperties": agentSchema["additionalProperties"], + } + + schema["properties"].(map[string]any)["agents"] = combinedAgentSchema + schema["definitions"] = map[string]any{ + "agent": agentSchema["additionalProperties"], + } + + // Add LSP configuration + schema["properties"].(map[string]any)["lsp"] = map[string]any{ + "type": "object", + "description": "Language Server Protocol configurations", + "additionalProperties": map[string]any{ + "type": "object", + "description": "LSP configuration for a language", + "properties": map[string]any{ + "disabled": map[string]any{ + "type": "boolean", + "description": "Whether the LSP is disabled", + "default": false, + }, + "command": map[string]any{ + "type": "string", + "description": "Command to execute for the LSP server", + }, + "args": map[string]any{ + "type": "array", + "description": "Command arguments for the LSP server", + "items": map[string]any{ + "type": "string", + }, + }, + "options": map[string]any{ + "type": "object", + "description": "Additional options for the LSP server", + }, + }, + "required": []string{"command"}, + }, + } + + return schema +} + |
