main.go

  1package main
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6	"os"
  7
  8	"github.com/opencode-ai/opencode/internal/config"
  9	"github.com/opencode-ai/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	schema["properties"].(map[string]any)["contextPaths"] = map[string]any{
 81		"type":        "array",
 82		"description": "Context paths for the application",
 83		"items": map[string]any{
 84			"type": "string",
 85		},
 86		"default": []string{
 87			".github/copilot-instructions.md",
 88			".cursorrules",
 89			".cursor/rules/",
 90			"CLAUDE.md",
 91			"CLAUDE.local.md",
 92			"opencode.md",
 93			"opencode.local.md",
 94			"OpenCode.md",
 95			"OpenCode.local.md",
 96			"OPENCODE.md",
 97			"OPENCODE.local.md",
 98		},
 99	}
100
101	schema["properties"].(map[string]any)["tui"] = map[string]any{
102		"type":        "object",
103		"description": "Terminal User Interface configuration",
104		"properties": map[string]any{
105			"theme": map[string]any{
106				"type":        "string",
107				"description": "TUI theme name",
108				"default":     "opencode",
109				"enum": []string{
110					"opencode",
111					"catppuccin",
112					"dracula",
113					"flexoki",
114					"gruvbox",
115					"monokai",
116					"onedark",
117					"tokyonight",
118					"tron",
119				},
120			},
121		},
122	}
123
124	// Add MCP servers
125	schema["properties"].(map[string]any)["mcpServers"] = map[string]any{
126		"type":        "object",
127		"description": "Model Control Protocol server configurations",
128		"additionalProperties": map[string]any{
129			"type":        "object",
130			"description": "MCP server configuration",
131			"properties": map[string]any{
132				"command": map[string]any{
133					"type":        "string",
134					"description": "Command to execute for the MCP server",
135				},
136				"env": map[string]any{
137					"type":        "array",
138					"description": "Environment variables for the MCP server",
139					"items": map[string]any{
140						"type": "string",
141					},
142				},
143				"args": map[string]any{
144					"type":        "array",
145					"description": "Command arguments for the MCP server",
146					"items": map[string]any{
147						"type": "string",
148					},
149				},
150				"type": map[string]any{
151					"type":        "string",
152					"description": "Type of MCP server",
153					"enum":        []string{"stdio", "sse"},
154					"default":     "stdio",
155				},
156				"url": map[string]any{
157					"type":        "string",
158					"description": "URL for SSE type MCP servers",
159				},
160				"headers": map[string]any{
161					"type":        "object",
162					"description": "HTTP headers for SSE type MCP servers",
163					"additionalProperties": map[string]any{
164						"type": "string",
165					},
166				},
167			},
168			"required": []string{"command"},
169		},
170	}
171
172	// Add providers
173	providerSchema := map[string]any{
174		"type":        "object",
175		"description": "LLM provider configurations",
176		"additionalProperties": map[string]any{
177			"type":        "object",
178			"description": "Provider configuration",
179			"properties": map[string]any{
180				"apiKey": map[string]any{
181					"type":        "string",
182					"description": "API key for the provider",
183				},
184				"disabled": map[string]any{
185					"type":        "boolean",
186					"description": "Whether the provider is disabled",
187					"default":     false,
188				},
189			},
190		},
191	}
192
193	// Add known providers
194	knownProviders := []string{
195		string(models.ProviderAnthropic),
196		string(models.ProviderOpenAI),
197		string(models.ProviderGemini),
198		string(models.ProviderGROQ),
199		string(models.ProviderOpenRouter),
200		string(models.ProviderBedrock),
201		string(models.ProviderAzure),
202		string(models.ProviderVertexAI),
203	}
204
205	providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{
206		"type":        "string",
207		"description": "Provider type",
208		"enum":        knownProviders,
209	}
210
211	schema["properties"].(map[string]any)["providers"] = providerSchema
212
213	// Add agents
214	agentSchema := map[string]any{
215		"type":        "object",
216		"description": "Agent configurations",
217		"additionalProperties": map[string]any{
218			"type":        "object",
219			"description": "Agent configuration",
220			"properties": map[string]any{
221				"model": map[string]any{
222					"type":        "string",
223					"description": "Model ID for the agent",
224				},
225				"maxTokens": map[string]any{
226					"type":        "integer",
227					"description": "Maximum tokens for the agent",
228					"minimum":     1,
229				},
230				"reasoningEffort": map[string]any{
231					"type":        "string",
232					"description": "Reasoning effort for models that support it (OpenAI, Anthropic)",
233					"enum":        []string{"low", "medium", "high"},
234				},
235			},
236			"required": []string{"model"},
237		},
238	}
239
240	// Add model enum
241	modelEnum := []string{}
242	for modelID := range models.SupportedModels {
243		modelEnum = append(modelEnum, string(modelID))
244	}
245	agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum
246
247	// Add specific agent properties
248	agentProperties := map[string]any{}
249	knownAgents := []string{
250		string(config.AgentCoder),
251		string(config.AgentTask),
252		string(config.AgentTitle),
253	}
254
255	for _, agentName := range knownAgents {
256		agentProperties[agentName] = map[string]any{
257			"$ref": "#/definitions/agent",
258		}
259	}
260
261	// Create a combined schema that allows both specific agents and additional ones
262	combinedAgentSchema := map[string]any{
263		"type":                 "object",
264		"description":          "Agent configurations",
265		"properties":           agentProperties,
266		"additionalProperties": agentSchema["additionalProperties"],
267	}
268
269	schema["properties"].(map[string]any)["agents"] = combinedAgentSchema
270	schema["definitions"] = map[string]any{
271		"agent": agentSchema["additionalProperties"],
272	}
273
274	// Add LSP configuration
275	schema["properties"].(map[string]any)["lsp"] = map[string]any{
276		"type":        "object",
277		"description": "Language Server Protocol configurations",
278		"additionalProperties": map[string]any{
279			"type":        "object",
280			"description": "LSP configuration for a language",
281			"properties": map[string]any{
282				"disabled": map[string]any{
283					"type":        "boolean",
284					"description": "Whether the LSP is disabled",
285					"default":     false,
286				},
287				"command": map[string]any{
288					"type":        "string",
289					"description": "Command to execute for the LSP server",
290				},
291				"args": map[string]any{
292					"type":        "array",
293					"description": "Command arguments for the LSP server",
294					"items": map[string]any{
295						"type": "string",
296					},
297				},
298				"options": map[string]any{
299					"type":        "object",
300					"description": "Additional options for the LSP server",
301				},
302			},
303			"required": []string{"command"},
304		},
305	}
306
307	return schema
308}