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	// Add MCP servers
102	schema["properties"].(map[string]any)["mcpServers"] = map[string]any{
103		"type":        "object",
104		"description": "Model Control Protocol server configurations",
105		"additionalProperties": map[string]any{
106			"type":        "object",
107			"description": "MCP server configuration",
108			"properties": map[string]any{
109				"command": map[string]any{
110					"type":        "string",
111					"description": "Command to execute for the MCP server",
112				},
113				"env": map[string]any{
114					"type":        "array",
115					"description": "Environment variables for the MCP server",
116					"items": map[string]any{
117						"type": "string",
118					},
119				},
120				"args": map[string]any{
121					"type":        "array",
122					"description": "Command arguments for the MCP server",
123					"items": map[string]any{
124						"type": "string",
125					},
126				},
127				"type": map[string]any{
128					"type":        "string",
129					"description": "Type of MCP server",
130					"enum":        []string{"stdio", "sse"},
131					"default":     "stdio",
132				},
133				"url": map[string]any{
134					"type":        "string",
135					"description": "URL for SSE type MCP servers",
136				},
137				"headers": map[string]any{
138					"type":        "object",
139					"description": "HTTP headers for SSE type MCP servers",
140					"additionalProperties": map[string]any{
141						"type": "string",
142					},
143				},
144			},
145			"required": []string{"command"},
146		},
147	}
148
149	// Add providers
150	providerSchema := map[string]any{
151		"type":        "object",
152		"description": "LLM provider configurations",
153		"additionalProperties": map[string]any{
154			"type":        "object",
155			"description": "Provider configuration",
156			"properties": map[string]any{
157				"apiKey": map[string]any{
158					"type":        "string",
159					"description": "API key for the provider",
160				},
161				"disabled": map[string]any{
162					"type":        "boolean",
163					"description": "Whether the provider is disabled",
164					"default":     false,
165				},
166			},
167		},
168	}
169
170	// Add known providers
171	knownProviders := []string{
172		string(models.ProviderAnthropic),
173		string(models.ProviderOpenAI),
174		string(models.ProviderGemini),
175		string(models.ProviderGROQ),
176		string(models.ProviderBedrock),
177	}
178
179	providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{
180		"type":        "string",
181		"description": "Provider type",
182		"enum":        knownProviders,
183	}
184
185	schema["properties"].(map[string]any)["providers"] = providerSchema
186
187	// Add agents
188	agentSchema := map[string]any{
189		"type":        "object",
190		"description": "Agent configurations",
191		"additionalProperties": map[string]any{
192			"type":        "object",
193			"description": "Agent configuration",
194			"properties": map[string]any{
195				"model": map[string]any{
196					"type":        "string",
197					"description": "Model ID for the agent",
198				},
199				"maxTokens": map[string]any{
200					"type":        "integer",
201					"description": "Maximum tokens for the agent",
202					"minimum":     1,
203				},
204				"reasoningEffort": map[string]any{
205					"type":        "string",
206					"description": "Reasoning effort for models that support it (OpenAI, Anthropic)",
207					"enum":        []string{"low", "medium", "high"},
208				},
209			},
210			"required": []string{"model"},
211		},
212	}
213
214	// Add model enum
215	modelEnum := []string{}
216	for modelID := range models.SupportedModels {
217		modelEnum = append(modelEnum, string(modelID))
218	}
219	agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum
220
221	// Add specific agent properties
222	agentProperties := map[string]any{}
223	knownAgents := []string{
224		string(config.AgentCoder),
225		string(config.AgentTask),
226		string(config.AgentTitle),
227	}
228
229	for _, agentName := range knownAgents {
230		agentProperties[agentName] = map[string]any{
231			"$ref": "#/definitions/agent",
232		}
233	}
234
235	// Create a combined schema that allows both specific agents and additional ones
236	combinedAgentSchema := map[string]any{
237		"type":                 "object",
238		"description":          "Agent configurations",
239		"properties":           agentProperties,
240		"additionalProperties": agentSchema["additionalProperties"],
241	}
242
243	schema["properties"].(map[string]any)["agents"] = combinedAgentSchema
244	schema["definitions"] = map[string]any{
245		"agent": agentSchema["additionalProperties"],
246	}
247
248	// Add LSP configuration
249	schema["properties"].(map[string]any)["lsp"] = map[string]any{
250		"type":        "object",
251		"description": "Language Server Protocol configurations",
252		"additionalProperties": map[string]any{
253			"type":        "object",
254			"description": "LSP configuration for a language",
255			"properties": map[string]any{
256				"disabled": map[string]any{
257					"type":        "boolean",
258					"description": "Whether the LSP is disabled",
259					"default":     false,
260				},
261				"command": map[string]any{
262					"type":        "string",
263					"description": "Command to execute for the LSP server",
264				},
265				"args": map[string]any{
266					"type":        "array",
267					"description": "Command arguments for the LSP server",
268					"items": map[string]any{
269						"type": "string",
270					},
271				},
272				"options": map[string]any{
273					"type":        "object",
274					"description": "Additional options for the LSP server",
275				},
276			},
277			"required": []string{"command"},
278		},
279	}
280
281	return schema
282}