Переглянути джерело

fix(opencode): ignore unknown config fields (#41312)

opencode-agent[bot] 3 днів тому
батько
коміт
38e10eb140

+ 5 - 23
packages/opencode/src/config/parse.ts

@@ -37,22 +37,11 @@ export function schema<S extends EffectSchema.Decoder<unknown, never>>(
   data: unknown,
   source: string,
 ): DeepMutable<S["Type"]> {
-  const extra = topLevelExtraKeys(schema, data)
-  if (extra.length) {
-    throw new InvalidError({
-      path: source,
-      issues: [
-        {
-          code: "unrecognized_keys",
-          keys: extra,
-          path: [],
-          message: `Unrecognized key${extra.length === 1 ? "" : "s"}: ${extra.join(", ")}`,
-        },
-      ],
-    })
-  }
-
-  const decoded = EffectSchema.decodeUnknownExit(schema)(data, { errors: "all", propertyOrder: "original" })
+  const decoded = EffectSchema.decodeUnknownExit(schema)(data, {
+    errors: "all",
+    onExcessProperty: "ignore",
+    propertyOrder: "original",
+  })
   if (Exit.isSuccess(decoded)) return decoded.value as DeepMutable<S["Type"]>
   const error = Cause.squash(decoded.cause)
 
@@ -70,10 +59,3 @@ export function schema<S extends EffectSchema.Decoder<unknown, never>>(
     { cause: error },
   )
 }
-
-function topLevelExtraKeys(schema: EffectSchema.Top, data: unknown) {
-  if (typeof data !== "object" || data === null || Array.isArray(data)) return []
-  if (schema.ast._tag !== "Objects" || schema.ast.indexSignatures.length > 0) return []
-  const known = new Set(schema.ast.propertySignatures.map((item) => String(item.name)))
-  return Object.keys(data).filter((key) => !known.has(key))
-}

+ 5 - 10
packages/opencode/test/config/config.test.ts

@@ -597,12 +597,12 @@ accountTokenIt.instance("resolves env templates in account config with account t
   }),
 )
 
-it.instance("validates config schema and throws on invalid fields", () =>
+it.instance("validates config schema and throws on invalid values", () =>
   Effect.gen(function* () {
     const test = yield* TestInstance
     yield* writeConfigEffect(test.directory, {
       $schema: "https://opencode.ai/config.json",
-      invalid_field: "should cause error",
+      model: 42,
     })
     const exit = yield* Config.use.get().pipe(Effect.exit)
     expect(Exit.isFailure(exit)).toBe(true)
@@ -1331,7 +1331,7 @@ it.instance("permission config preserves user key order", () =>
   }),
 )
 
-test("config parser preserves permission order while rejecting unknown top-level keys", () => {
+test("config parser preserves permission order while ignoring unknown top-level keys", () => {
   const config = ConfigParse.schema(
     ConfigV1.Info,
     {
@@ -1340,18 +1340,13 @@ test("config parser preserves permission order while rejecting unknown top-level
         "*": "deny",
         edit: "ask",
       },
+      plugins: ["example"],
     },
     "test",
   )
 
   expect(Object.keys(config.permission!)).toEqual(["bash", "*", "edit"])
-  try {
-    ConfigParse.schema(ConfigV1.Info, { invalid_field: true }, "test")
-    throw new Error("expected config parse to fail")
-  } catch (err) {
-    const error = err as { data?: { issues?: Array<{ code?: string; keys?: string[]; path?: string[] }> } }
-    expect(error.data?.issues?.[0]).toMatchObject({ code: "unrecognized_keys", keys: ["invalid_field"], path: [] })
-  }
+  expect(config).not.toHaveProperty("plugins")
 })
 
 // MCP config merging tests