main.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "github.com/charmbracelet/crush/internal/config"
  7. "github.com/invopop/jsonschema"
  8. )
  9. func main() {
  10. // Create a new reflector
  11. r := &jsonschema.Reflector{
  12. // Use anonymous schemas to avoid ID conflicts
  13. Anonymous: true,
  14. // Expand the root struct instead of referencing it
  15. ExpandedStruct: true,
  16. AllowAdditionalProperties: true,
  17. }
  18. // Generate schema for the main Config struct
  19. schema := r.Reflect(&config.Config{})
  20. // Enhance the schema with additional information
  21. enhanceSchema(schema)
  22. // Set the schema metadata
  23. schema.Version = "https://json-schema.org/draft/2020-12/schema"
  24. schema.Title = "Crush Configuration"
  25. schema.Description = "Configuration schema for the Crush application"
  26. // Pretty print the schema
  27. encoder := json.NewEncoder(os.Stdout)
  28. encoder.SetIndent("", " ")
  29. if err := encoder.Encode(schema); err != nil {
  30. fmt.Fprintf(os.Stderr, "Error encoding schema: %v\n", err)
  31. os.Exit(1)
  32. }
  33. }
  34. // enhanceSchema adds additional enhancements to the generated schema
  35. func enhanceSchema(schema *jsonschema.Schema) {
  36. // Add provider enums
  37. addProviderEnums(schema)
  38. // Add model enums
  39. addModelEnums(schema)
  40. // Add tool enums
  41. addToolEnums(schema)
  42. // Add default context paths
  43. addDefaultContextPaths(schema)
  44. }
  45. // addProviderEnums adds provider enums to the schema
  46. func addProviderEnums(schema *jsonschema.Schema) {
  47. providers := config.Providers()
  48. var providerIDs []any
  49. for _, p := range providers {
  50. providerIDs = append(providerIDs, string(p.ID))
  51. }
  52. // Add to PreferredModel provider field
  53. if schema.Definitions != nil {
  54. if preferredModelDef, exists := schema.Definitions["PreferredModel"]; exists {
  55. if providerProp, exists := preferredModelDef.Properties.Get("provider"); exists {
  56. providerProp.Enum = providerIDs
  57. }
  58. }
  59. // Add to ProviderConfig ID field
  60. if providerConfigDef, exists := schema.Definitions["ProviderConfig"]; exists {
  61. if idProp, exists := providerConfigDef.Properties.Get("id"); exists {
  62. idProp.Enum = providerIDs
  63. }
  64. }
  65. }
  66. }
  67. // addModelEnums adds model enums to the schema
  68. func addModelEnums(schema *jsonschema.Schema) {
  69. providers := config.Providers()
  70. var modelIDs []any
  71. for _, p := range providers {
  72. for _, m := range p.Models {
  73. modelIDs = append(modelIDs, m.ID)
  74. }
  75. }
  76. // Add to PreferredModel model_id field
  77. if schema.Definitions != nil {
  78. if preferredModelDef, exists := schema.Definitions["PreferredModel"]; exists {
  79. if modelIDProp, exists := preferredModelDef.Properties.Get("model_id"); exists {
  80. modelIDProp.Enum = modelIDs
  81. }
  82. }
  83. }
  84. }
  85. // addToolEnums adds tool enums to the schema
  86. func addToolEnums(schema *jsonschema.Schema) {
  87. tools := []any{
  88. "bash", "edit", "fetch", "glob", "grep", "ls", "sourcegraph", "view", "write", "agent",
  89. }
  90. if schema.Definitions != nil {
  91. if agentDef, exists := schema.Definitions["Agent"]; exists {
  92. if allowedToolsProp, exists := agentDef.Properties.Get("allowed_tools"); exists {
  93. if allowedToolsProp.Items != nil {
  94. allowedToolsProp.Items.Enum = tools
  95. }
  96. }
  97. }
  98. }
  99. }
  100. // addDefaultContextPaths adds default context paths to the schema
  101. func addDefaultContextPaths(schema *jsonschema.Schema) {
  102. defaultContextPaths := []any{
  103. ".github/copilot-instructions.md",
  104. ".cursorrules",
  105. ".cursor/rules/",
  106. "CLAUDE.md",
  107. "CLAUDE.local.md",
  108. "GEMINI.md",
  109. "gemini.md",
  110. "crush.md",
  111. "crush.local.md",
  112. "Crush.md",
  113. "Crush.local.md",
  114. "CRUSH.md",
  115. "CRUSH.local.md",
  116. }
  117. if schema.Definitions != nil {
  118. if optionsDef, exists := schema.Definitions["Options"]; exists {
  119. if contextPathsProp, exists := optionsDef.Properties.Get("context_paths"); exists {
  120. contextPathsProp.Default = defaultContextPaths
  121. }
  122. }
  123. }
  124. // Also add to root properties if they exist
  125. if schema.Properties != nil {
  126. if optionsProp, exists := schema.Properties.Get("options"); exists {
  127. if optionsProp.Properties != nil {
  128. if contextPathsProp, exists := optionsProp.Properties.Get("context_paths"); exists {
  129. contextPathsProp.Default = defaultContextPaths
  130. }
  131. }
  132. }
  133. }
  134. }