1package main
2
3import (
4 "encoding/json"
5 "fmt"
6 "os"
7
8 "github.com/kujtimiihoxha/opencode/internal/config"
9 "github.com/kujtimiihoxha/opencode/internal/llm/models"
10)
11
12// JSONSchemaType represents a JSON Schema type
13type JSONSchemaType struct {
14 Type string `json:"type,omitempty"`
15 Description string `json:"description,omitempty"`
16 Properties map[string]any `json:"properties,omitempty"`
17 Required []string `json:"required,omitempty"`
18 AdditionalProperties any `json:"additionalProperties,omitempty"`
19 Enum []any `json:"enum,omitempty"`
20 Items map[string]any `json:"items,omitempty"`
21 OneOf []map[string]any `json:"oneOf,omitempty"`
22 AnyOf []map[string]any `json:"anyOf,omitempty"`
23 Default any `json:"default,omitempty"`
24}
25
26func main() {
27 schema := generateSchema()
28
29 // Pretty print the schema
30 encoder := json.NewEncoder(os.Stdout)
31 encoder.SetIndent("", " ")
32 if err := encoder.Encode(schema); err != nil {
33 fmt.Fprintf(os.Stderr, "Error encoding schema: %v\n", err)
34 os.Exit(1)
35 }
36}
37
38func generateSchema() map[string]any {
39 schema := map[string]any{
40 "$schema": "http://json-schema.org/draft-07/schema#",
41 "title": "OpenCode Configuration",
42 "description": "Configuration schema for the OpenCode application",
43 "type": "object",
44 "properties": map[string]any{},
45 }
46
47 // Add Data configuration
48 schema["properties"].(map[string]any)["data"] = map[string]any{
49 "type": "object",
50 "description": "Storage configuration",
51 "properties": map[string]any{
52 "directory": map[string]any{
53 "type": "string",
54 "description": "Directory where application data is stored",
55 "default": ".opencode",
56 },
57 },
58 "required": []string{"directory"},
59 }
60
61 // Add working directory
62 schema["properties"].(map[string]any)["wd"] = map[string]any{
63 "type": "string",
64 "description": "Working directory for the application",
65 }
66
67 // Add debug flags
68 schema["properties"].(map[string]any)["debug"] = map[string]any{
69 "type": "boolean",
70 "description": "Enable debug mode",
71 "default": false,
72 }
73
74 schema["properties"].(map[string]any)["debugLSP"] = map[string]any{
75 "type": "boolean",
76 "description": "Enable LSP debug mode",
77 "default": false,
78 }
79
80 // Add MCP servers
81 schema["properties"].(map[string]any)["mcpServers"] = map[string]any{
82 "type": "object",
83 "description": "Model Control Protocol server configurations",
84 "additionalProperties": map[string]any{
85 "type": "object",
86 "description": "MCP server configuration",
87 "properties": map[string]any{
88 "command": map[string]any{
89 "type": "string",
90 "description": "Command to execute for the MCP server",
91 },
92 "env": map[string]any{
93 "type": "array",
94 "description": "Environment variables for the MCP server",
95 "items": map[string]any{
96 "type": "string",
97 },
98 },
99 "args": map[string]any{
100 "type": "array",
101 "description": "Command arguments for the MCP server",
102 "items": map[string]any{
103 "type": "string",
104 },
105 },
106 "type": map[string]any{
107 "type": "string",
108 "description": "Type of MCP server",
109 "enum": []string{"stdio", "sse"},
110 "default": "stdio",
111 },
112 "url": map[string]any{
113 "type": "string",
114 "description": "URL for SSE type MCP servers",
115 },
116 "headers": map[string]any{
117 "type": "object",
118 "description": "HTTP headers for SSE type MCP servers",
119 "additionalProperties": map[string]any{
120 "type": "string",
121 },
122 },
123 },
124 "required": []string{"command"},
125 },
126 }
127
128 // Add providers
129 providerSchema := map[string]any{
130 "type": "object",
131 "description": "LLM provider configurations",
132 "additionalProperties": map[string]any{
133 "type": "object",
134 "description": "Provider configuration",
135 "properties": map[string]any{
136 "apiKey": map[string]any{
137 "type": "string",
138 "description": "API key for the provider",
139 },
140 "disabled": map[string]any{
141 "type": "boolean",
142 "description": "Whether the provider is disabled",
143 "default": false,
144 },
145 },
146 },
147 }
148
149 // Add known providers
150 knownProviders := []string{
151 string(models.ProviderAnthropic),
152 string(models.ProviderOpenAI),
153 string(models.ProviderGemini),
154 string(models.ProviderGROQ),
155 string(models.ProviderBedrock),
156 }
157
158 providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{
159 "type": "string",
160 "description": "Provider type",
161 "enum": knownProviders,
162 }
163
164 schema["properties"].(map[string]any)["providers"] = providerSchema
165
166 // Add agents
167 agentSchema := map[string]any{
168 "type": "object",
169 "description": "Agent configurations",
170 "additionalProperties": map[string]any{
171 "type": "object",
172 "description": "Agent configuration",
173 "properties": map[string]any{
174 "model": map[string]any{
175 "type": "string",
176 "description": "Model ID for the agent",
177 },
178 "maxTokens": map[string]any{
179 "type": "integer",
180 "description": "Maximum tokens for the agent",
181 "minimum": 1,
182 },
183 "reasoningEffort": map[string]any{
184 "type": "string",
185 "description": "Reasoning effort for models that support it (OpenAI, Anthropic)",
186 "enum": []string{"low", "medium", "high"},
187 },
188 },
189 "required": []string{"model"},
190 },
191 }
192
193 // Add model enum
194 modelEnum := []string{}
195 for modelID := range models.SupportedModels {
196 modelEnum = append(modelEnum, string(modelID))
197 }
198 agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum
199
200 // Add specific agent properties
201 agentProperties := map[string]any{}
202 knownAgents := []string{
203 string(config.AgentCoder),
204 string(config.AgentTask),
205 string(config.AgentTitle),
206 }
207
208 for _, agentName := range knownAgents {
209 agentProperties[agentName] = map[string]any{
210 "$ref": "#/definitions/agent",
211 }
212 }
213
214 // Create a combined schema that allows both specific agents and additional ones
215 combinedAgentSchema := map[string]any{
216 "type": "object",
217 "description": "Agent configurations",
218 "properties": agentProperties,
219 "additionalProperties": agentSchema["additionalProperties"],
220 }
221
222 schema["properties"].(map[string]any)["agents"] = combinedAgentSchema
223 schema["definitions"] = map[string]any{
224 "agent": agentSchema["additionalProperties"],
225 }
226
227 // Add LSP configuration
228 schema["properties"].(map[string]any)["lsp"] = map[string]any{
229 "type": "object",
230 "description": "Language Server Protocol configurations",
231 "additionalProperties": map[string]any{
232 "type": "object",
233 "description": "LSP configuration for a language",
234 "properties": map[string]any{
235 "disabled": map[string]any{
236 "type": "boolean",
237 "description": "Whether the LSP is disabled",
238 "default": false,
239 },
240 "command": map[string]any{
241 "type": "string",
242 "description": "Command to execute for the LSP server",
243 },
244 "args": map[string]any{
245 "type": "array",
246 "description": "Command arguments for the LSP server",
247 "items": map[string]any{
248 "type": "string",
249 },
250 },
251 "options": map[string]any{
252 "type": "object",
253 "description": "Additional options for the LSP server",
254 },
255 },
256 "required": []string{"command"},
257 },
258 }
259
260 return schema
261}
262