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.ProviderOpenRouter),
177		string(models.ProviderBedrock),
178		string(models.ProviderAzure),
179	}
180
181	providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{
182		"type":        "string",
183		"description": "Provider type",
184		"enum":        knownProviders,
185	}
186
187	schema["properties"].(map[string]any)["providers"] = providerSchema
188
189	// Add agents
190	agentSchema := map[string]any{
191		"type":        "object",
192		"description": "Agent configurations",
193		"additionalProperties": map[string]any{
194			"type":        "object",
195			"description": "Agent configuration",
196			"properties": map[string]any{
197				"model": map[string]any{
198					"type":        "string",
199					"description": "Model ID for the agent",
200				},
201				"maxTokens": map[string]any{
202					"type":        "integer",
203					"description": "Maximum tokens for the agent",
204					"minimum":     1,
205				},
206				"reasoningEffort": map[string]any{
207					"type":        "string",
208					"description": "Reasoning effort for models that support it (OpenAI, Anthropic)",
209					"enum":        []string{"low", "medium", "high"},
210				},
211			},
212			"required": []string{"model"},
213		},
214	}
215
216	// Add model enum
217	modelEnum := []string{}
218	for modelID := range models.SupportedModels {
219		modelEnum = append(modelEnum, string(modelID))
220	}
221	agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum
222
223	// Add specific agent properties
224	agentProperties := map[string]any{}
225	knownAgents := []string{
226		string(config.AgentCoder),
227		string(config.AgentTask),
228		string(config.AgentTitle),
229	}
230
231	for _, agentName := range knownAgents {
232		agentProperties[agentName] = map[string]any{
233			"$ref": "#/definitions/agent",
234		}
235	}
236
237	// Create a combined schema that allows both specific agents and additional ones
238	combinedAgentSchema := map[string]any{
239		"type":                 "object",
240		"description":          "Agent configurations",
241		"properties":           agentProperties,
242		"additionalProperties": agentSchema["additionalProperties"],
243	}
244
245	schema["properties"].(map[string]any)["agents"] = combinedAgentSchema
246	schema["definitions"] = map[string]any{
247		"agent": agentSchema["additionalProperties"],
248	}
249
250	// Add LSP configuration
251	schema["properties"].(map[string]any)["lsp"] = map[string]any{
252		"type":        "object",
253		"description": "Language Server Protocol configurations",
254		"additionalProperties": map[string]any{
255			"type":        "object",
256			"description": "LSP configuration for a language",
257			"properties": map[string]any{
258				"disabled": map[string]any{
259					"type":        "boolean",
260					"description": "Whether the LSP is disabled",
261					"default":     false,
262				},
263				"command": map[string]any{
264					"type":        "string",
265					"description": "Command to execute for the LSP server",
266				},
267				"args": map[string]any{
268					"type":        "array",
269					"description": "Command arguments for the LSP server",
270					"items": map[string]any{
271						"type": "string",
272					},
273				},
274				"options": map[string]any{
275					"type":        "object",
276					"description": "Additional options for the LSP server",
277				},
278			},
279			"required": []string{"command"},
280		},
281	}
282
283	return schema
284}