11#!/usr/bin/env bun
22
3- import { z } from "zod"
43import { Config } from "@/config/config"
5- import { zodObject } from "@opencode-ai/core/effect-zod"
6- import { TuiJsonSchema } from "../src/cli/cmd/tui/config/tui-json-schema"
74import { Schema } from "effect"
5+ import { TuiJsonSchema } from "../src/cli/cmd/tui/config/tui-json-schema"
86
97type JsonSchema = Record < string , unknown >
10-
11- function generate ( schema : z . ZodType ) {
12- const result = z . toJSONSchema ( schema , {
13- io : "input" , // Generate input shape (treats optional().default() as not required)
14- /**
15- * We'll use the `default` values of the field as the only value in `examples`.
16- * This will ensure no docs are needed to be read, as the configuration is
17- * self-documenting.
18- *
19- * See https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.9.5
20- */
21- override ( ctx ) {
22- const schema = ctx . jsonSchema
23-
24- // Preserve strictness: set additionalProperties: false for objects
25- if (
26- schema &&
27- typeof schema === "object" &&
28- schema . type === "object" &&
29- schema . additionalProperties === undefined
30- ) {
31- schema . additionalProperties = false
32- }
33-
34- // Add examples and default descriptions for string fields with defaults
35- if ( schema && typeof schema === "object" && "type" in schema && schema . type === "string" && schema ?. default ) {
36- if ( ! schema . examples ) {
37- schema . examples = [ schema . default ]
38- }
39-
40- schema . description = [ schema . description || "" , `default: \`${ formatDefault ( schema . default ) } \`` ]
41- . filter ( Boolean )
42- . join ( "\n\n" )
43- . trim ( )
44- }
45- } ,
46- } ) as Record < string , unknown > & {
47- allowComments ?: boolean
48- allowTrailingCommas ?: boolean
49- }
50-
51- // used for json lsps since config supports jsonc
52- result . allowComments = true
53- result . allowTrailingCommas = true
54-
55- return result
56- }
57-
58- function formatDefault ( value : unknown ) {
59- if ( typeof value !== "object" || value === null ) return String ( value )
60- return JSON . stringify ( value )
61- }
8+ const MODEL_REF = "https://models.dev/model-schema.json#/$defs/Model"
629
6310function generateEffect ( schema : Schema . Top ) {
6411 const document = Schema . toJsonSchemaDocument ( schema )
@@ -68,9 +15,11 @@ function generateEffect(schema: Schema.Top) {
6815 $defs : document . definitions ,
6916 } )
7017 if ( ! isRecord ( normalized ) ) throw new Error ( "schema generator produced a non-object schema" )
71- normalized . allowComments = true
72- normalized . allowTrailingCommas = true
73- return normalized
18+ const restored = restoreModelRefs ( normalized )
19+ if ( ! isRecord ( restored ) ) throw new Error ( "schema generator produced a non-object schema" )
20+ restored . allowComments = true
21+ restored . allowTrailingCommas = true
22+ return restored
7423}
7524
7625function normalize ( value : unknown ) : unknown {
@@ -100,6 +49,17 @@ function normalize(value: unknown): unknown {
10049 return schema
10150}
10251
52+ function restoreModelRefs ( value : unknown , key ?: string ) : unknown {
53+ if ( Array . isArray ( value ) ) return value . map ( ( item ) => restoreModelRefs ( item ) )
54+ if ( ! isRecord ( value ) ) return value
55+
56+ const schema = Object . fromEntries ( Object . entries ( value ) . map ( ( [ name , item ] ) => [ name , restoreModelRefs ( item , name ) ] ) )
57+ if ( ( key === "model" || key === "small_model" ) && schema . type === "string" ) {
58+ return { ...schema , $ref : MODEL_REF }
59+ }
60+ return schema
61+ }
62+
10363function isRecord ( value : unknown ) : value is JsonSchema {
10464 return typeof value === "object" && value !== null && ! Array . isArray ( value )
10565}
@@ -108,7 +68,7 @@ const configFile = process.argv[2]
10868const tuiFile = process . argv [ 3 ]
10969
11070console . log ( configFile )
111- await Bun . write ( configFile , JSON . stringify ( generate ( zodObject ( Config . Info ) . strict ( ) . meta ( { ref : "Config" } ) ) , null , 2 ) )
71+ await Bun . write ( configFile , JSON . stringify ( generateEffect ( Config . Info ) , null , 2 ) )
11272
11373if ( tuiFile ) {
11474 console . log ( tuiFile )
0 commit comments