1
0
Эх сурвалжийг харах

Drop Config Info Zod static (#26933)

Kit Langton 3 сар өмнө
parent
commit
fe7ca3421e

+ 2 - 1
packages/opencode/script/schema.ts

@@ -2,6 +2,7 @@
 
 
 import { z } from "zod"
 import { z } from "zod"
 import { Config } from "@/config/config"
 import { Config } from "@/config/config"
+import { zodObject } from "@opencode-ai/core/effect-zod"
 import { TuiConfig } from "../src/cli/cmd/tui/config/tui"
 import { TuiConfig } from "../src/cli/cmd/tui/config/tui"
 
 
 function generate(schema: z.ZodType) {
 function generate(schema: z.ZodType) {
@@ -55,7 +56,7 @@ const configFile = process.argv[2]
 const tuiFile = process.argv[3]
 const tuiFile = process.argv[3]
 
 
 console.log(configFile)
 console.log(configFile)
-await Bun.write(configFile, JSON.stringify(generate(Config.Info.zod), null, 2))
+await Bun.write(configFile, JSON.stringify(generate(zodObject(Config.Info).strict().meta({ ref: "Config" })), null, 2))
 
 
 if (tuiFile) {
 if (tuiFile) {
   console.log(tuiFile)
   console.log(tuiFile)

+ 2 - 21
packages/opencode/src/config/config.ts

@@ -22,8 +22,7 @@ import { InstanceState } from "@/effect/instance-state"
 import { Context, Duration, Effect, Exit, Fiber, Layer, Option, Schema } from "effect"
 import { Context, Duration, Effect, Exit, Fiber, Layer, Option, Schema } from "effect"
 import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
 import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
 import { containsPath } from "../project/instance-context"
 import { containsPath } from "../project/instance-context"
-import { zod } from "@opencode-ai/core/effect-zod"
-import { NonNegativeInt, PositiveInt, withStatics, type DeepMutable } from "@opencode-ai/core/schema"
+import { NonNegativeInt, PositiveInt, type DeepMutable } from "@opencode-ai/core/schema"
 import { ConfigAgent } from "./agent"
 import { ConfigAgent } from "./agent"
 import { ConfigAttachment } from "./attachment"
 import { ConfigAttachment } from "./attachment"
 import { ConfigCommand } from "./command"
 import { ConfigCommand } from "./command"
@@ -112,8 +111,6 @@ async function resolveLoadedPlugins<T extends { plugin?: ConfigPlugin.Spec[] }>(
   return config
   return config
 }
 }
 
 
-export const Server = ConfigServer.Server.zod
-export const Layout = ConfigLayout.Layout.zod
 export type Layout = ConfigLayout.Layout
 export type Layout = ConfigLayout.Layout
 
 
 const LogLevelRef = Schema.Literals(["DEBUG", "INFO", "WARN", "ERROR"]).annotate({
 const LogLevelRef = Schema.Literals(["DEBUG", "INFO", "WARN", "ERROR"]).annotate({
@@ -121,14 +118,6 @@ const LogLevelRef = Schema.Literals(["DEBUG", "INFO", "WARN", "ERROR"]).annotate
   description: "Log level",
   description: "Log level",
 })
 })
 
 
-// The Effect Schema is the canonical source of truth. The `.zod` compatibility
-// surface is derived from it so plugin/SDK Zod consumers keep working without
-// a parallel hand-maintained Zod definition.
-//
-// The walker emits `z.object({...})` which is non-strict by default. Config
-// historically uses `.strict()` (additionalProperties: false in openapi.json),
-// so layer that on after derivation. Re-apply the Config ref afterward
-// since `.strict()` strips the walker's meta annotation.
 export const Info = Schema.Struct({
 export const Info = Schema.Struct({
   $schema: Schema.optional(Schema.String).annotate({
   $schema: Schema.optional(Schema.String).annotate({
     description: "JSON schema reference for configuration validation",
     description: "JSON schema reference for configuration validation",
@@ -301,15 +290,7 @@ export const Info = Schema.Struct({
       }),
       }),
     }),
     }),
   ),
   ),
-})
-  .annotate({ identifier: "Config" })
-  .pipe(
-    withStatics((s) => ({
-      zod: (zod(s) as unknown as z.ZodObject<any>).strict().meta({ ref: "Config" }) as unknown as z.ZodType<
-        DeepMutable<Schema.Schema.Type<typeof s>>
-      >,
-    })),
-  )
+}).annotate({ identifier: "Config" })
 
 
 // Uses the shared `DeepMutable` from `@opencode-ai/core/schema`. See the definition
 // Uses the shared `DeepMutable` from `@opencode-ai/core/schema`. See the definition
 // there for why the local variant is needed over `Types.DeepMutable` from
 // there for why the local variant is needed over `Types.DeepMutable` from

+ 1 - 1
packages/opencode/test/config/config.test.ts

@@ -251,7 +251,7 @@ test("updates global config and omits empty shell key in jsonc", async () => {
 
 
     const file = path.join(tmp.path, "opencode.jsonc")
     const file = path.join(tmp.path, "opencode.jsonc")
     const writtenConfig = await Filesystem.readText(file)
     const writtenConfig = await Filesystem.readText(file)
-    const parsed = ConfigParse.schema(Config.Info.zod, ConfigParse.jsonc(writtenConfig, file), file)
+    const parsed = ConfigParse.effectSchema(Config.Info, ConfigParse.jsonc(writtenConfig, file), file)
     expect(writtenConfig).not.toContain('"shell"')
     expect(writtenConfig).not.toContain('"shell"')
     expect(parsed.shell).toBeUndefined()
     expect(parsed.shell).toBeUndefined()
     expect(parsed.model).toBe("test/model")
     expect(parsed.model).toBe("test/model")

+ 2 - 2
packages/opencode/test/session/compaction.test.ts

@@ -1,6 +1,6 @@
 import { afterEach, describe, expect, mock, test } from "bun:test"
 import { afterEach, describe, expect, mock, test } from "bun:test"
 import { APICallError } from "ai"
 import { APICallError } from "ai"
-import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
+import { Cause, Deferred, Effect, Exit, Fiber, Layer, Schema } from "effect"
 import * as Stream from "effect/Stream"
 import * as Stream from "effect/Stream"
 import { Bus } from "../../src/bus"
 import { Bus } from "../../src/bus"
 import { Config } from "@/config/config"
 import { Config } from "@/config/config"
@@ -211,7 +211,7 @@ function layer(result: "continue" | "compact") {
 }
 }
 
 
 function cfg(compaction?: Config.Info["compaction"]) {
 function cfg(compaction?: Config.Info["compaction"]) {
-  const base = Config.Info.zod.parse({})
+  const base = Schema.decodeUnknownSync(Config.Info)({}) as Config.Info
   return TestConfig.layer({
   return TestConfig.layer({
     get: () => Effect.succeed({ ...base, compaction }),
     get: () => Effect.succeed({ ...base, compaction }),
   })
   })